From 20f9cf0047c53dcf6594818984671af45e0b8478 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 13 Dec 2024 20:13:56 -0800 Subject: [PATCH 001/125] Fix flaky signal handlers on posix (#15751) --- src/async/posix_event_loop.zig | 2 + src/bun.js/bindings/BunProcess.cpp | 39 +++++---- src/bun.js/event_loop.zig | 119 +++++++++++++++++++++++++++ src/bun.js/javascript.zig | 10 ++- src/bun_js.zig | 2 + src/cli/test_command.zig | 1 + src/tagged_pointer.zig | 8 ++ test/regression/issue/ctrl-c.test.ts | 71 +++++++++++++--- 8 files changed, 225 insertions(+), 27 deletions(-) diff --git a/src/async/posix_event_loop.zig b/src/async/posix_event_loop.zig index bb4c4286f1..2dfb108952 100644 --- a/src/async/posix_event_loop.zig +++ b/src/async/posix_event_loop.zig @@ -162,6 +162,7 @@ pub const FilePoll = struct { const Request = JSC.DNS.InternalDNS.Request; const LifecycleScriptSubprocessOutputReader = bun.install.LifecycleScriptSubprocess.OutputReader; const BufferedReader = bun.io.BufferedReader; + pub const Owner = bun.TaggedPointerUnion(.{ FileSink, @@ -386,6 +387,7 @@ pub const FilePoll = struct { var handler: *BufferedReader = ptr.as(BufferedReader); handler.onPoll(size_or_offset, poll.flags.contains(.hup)); }, + @field(Owner.Tag, bun.meta.typeBaseName(@typeName(Process))) => { log("onUpdate " ++ kqueue_or_epoll ++ " (fd: {}) Process", .{poll.fd}); var loader = ptr.as(Process); diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 62cc3fa6c1..5be9e86cdc 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -823,6 +823,19 @@ bool isSignalName(WTF::String input) return signalNameToNumberMap->contains(input); } +extern "C" void Bun__onSignalForJS(int signalNumber, Zig::GlobalObject* globalObject) +{ + Process* process = jsCast(globalObject->processObject()); + + String signalName = signalNumberToNameMap->get(signalNumber); + Identifier signalNameIdentifier = Identifier::fromString(globalObject->vm(), signalName); + MarkedArgumentBuffer args; + args.append(jsString(globalObject->vm(), signalNameIdentifier.string())); + args.append(jsNumber(signalNumber)); + + process->wrapped().emitForBindings(signalNameIdentifier, args); +} + #if OS(WINDOWS) extern "C" uv_signal_t* Bun__UVSignalHandle__init(JSC::JSGlobalObject* lexicalGlobalObject, int signalNumber, void (*callback)(uv_signal_t*, int)); extern "C" uv_signal_t* Bun__UVSignalHandle__close(uv_signal_t*); @@ -834,28 +847,20 @@ void signalHandler(int signalNumber) void signalHandler(uv_signal_t* signal, int signalNumber) #endif { +#if OS(WINDOWS) if (UNLIKELY(signalNumberToNameMap->find(signalNumber) == signalNumberToNameMap->end())) return; auto* context = ScriptExecutionContext::getMainThreadScriptExecutionContext(); if (UNLIKELY(!context)) return; - // signal handlers can be run on any thread context->postTaskConcurrently([signalNumber](ScriptExecutionContext& context) { - JSGlobalObject* lexicalGlobalObject = context.jsGlobalObject(); - Zig::GlobalObject* globalObject = jsCast(lexicalGlobalObject); - - Process* process = jsCast(globalObject->processObject()); - - String signalName = signalNumberToNameMap->get(signalNumber); - Identifier signalNameIdentifier = Identifier::fromString(globalObject->vm(), signalName); - MarkedArgumentBuffer args; - args.append(jsString(globalObject->vm(), signalNameIdentifier.string())); - args.append(jsNumber(signalNumber)); - - process->wrapped().emitForBindings(signalNameIdentifier, args); + Bun__onSignalForJS(signalNumber, jsCast(context.jsGlobalObject())); }); +#else + +#endif }; extern "C" void Bun__logUnhandledException(JSC::EncodedJSValue exception); @@ -934,7 +939,8 @@ extern "C" void Bun__setChannelRef(GlobalObject* globalObject, bool enabled) process->scriptExecutionContext()->unrefEventLoop(); } } - +extern "C" void Bun__ensureSignalHandler(); +extern "C" void Bun__onPosixSignal(int signalNumber); static void onDidChangeListeners(EventEmitter& eventEmitter, const Identifier& eventName, bool isAdded) { if (eventEmitter.scriptExecutionContext()->isMainThread()) { @@ -1056,11 +1062,14 @@ static void onDidChangeListeners(EventEmitter& eventEmitter, const Identifier& e #endif }; #if !OS(WINDOWS) + Bun__ensureSignalHandler(); struct sigaction action; memset(&action, 0, sizeof(struct sigaction)); // Set the handler in the action struct - action.sa_handler = signalHandler; + action.sa_handler = [](int signalNumber) { + Bun__onPosixSignal(signalNumber); + }; // Clear the sa_mask sigemptyset(&action.sa_mask); diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 514e8489d0..cad5a65525 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -407,6 +407,7 @@ const ServerAllConnectionsClosedTask = @import("./api/server.zig").ServerAllConn // Task.get(ReadFileTask) -> ?ReadFileTask pub const Task = TaggedPointerUnion(.{ FetchTasklet, + PosixSignalTask, AsyncGlobWalkTask, AsyncTransformTask, ReadFileTask, @@ -782,6 +783,19 @@ pub const EventLoop = struct { entered_event_loop_count: isize = 0, concurrent_ref: std.atomic.Value(i32) = std.atomic.Value(i32).init(0), + signal_handler: if (Environment.isPosix) ?*PosixSignalHandle else void = if (Environment.isPosix) null else {}, + + pub export fn Bun__ensureSignalHandler() void { + if (Environment.isPosix) { + const vm = JSC.VirtualMachine.getMainThreadVM(); + const this = vm.eventLoop(); + if (this.signal_handler == null) { + this.signal_handler = PosixSignalHandle.new(.{}); + @memset(&this.signal_handler.?.signals, 0); + } + } + } + pub const Debug = if (Environment.isDebug) struct { is_inside_tick_queue: bool = false, js_call_count_outside_tick_queue: usize = 0, @@ -1256,6 +1270,9 @@ pub const EventLoop = struct { var any: *bun.bundle_v2.DeferredBatchTask = task.get(bun.bundle_v2.DeferredBatchTask).?; any.runOnJSThread(); }, + @field(Task.Tag, typeBaseName(@typeName(PosixSignalTask))) => { + PosixSignalTask.runFromJSThread(@intCast(task.asUintptr()), global); + }, else => { bun.Output.panic("Unexpected tag: {s}", .{@tagName(task.tag())}); @@ -1310,6 +1327,12 @@ pub const EventLoop = struct { pub fn tickConcurrentWithCount(this: *EventLoop) usize { this.updateCounts(); + if (comptime Environment.isPosix) { + if (this.signal_handler) |signal_handler| { + signal_handler.drain(this); + } + } + var concurrent = this.concurrent_tasks.popBatch(); const count = concurrent.count; if (count == 0) @@ -2293,3 +2316,99 @@ pub const EventLoopTaskPtr = union { js: *ConcurrentTask, mini: *JSC.AnyTaskWithExtraContext, }; + +pub const PosixSignalHandle = struct { + const buffer_size = 8192; + + signals: [buffer_size]u8 = undefined, + + // Producer index (signal handler writes). + tail: std.atomic.Value(u16) = std.atomic.Value(u16).init(0), + // Consumer index (main thread reads). + head: std.atomic.Value(u16) = std.atomic.Value(u16).init(0), + + const log = bun.Output.scoped(.PosixSignalHandle, true); + + pub usingnamespace bun.New(@This()); + + /// Called by the signal handler (single producer). + /// Returns `true` if enqueued successfully, or `false` if the ring is full. + pub fn enqueue(this: *PosixSignalHandle, signal: u8) bool { + // Read the current tail and head (Acquire to ensure we have up‐to‐date values). + const old_tail = this.tail.load(.acquire); + const head_val = this.head.load(.acquire); + + // Compute the next tail (wrapping around buffer_size). + const next_tail = (old_tail +% 1) % buffer_size; + + // Check if the ring is full. + if (next_tail == (head_val % buffer_size)) { + // The ring buffer is full. + // We cannot block or wait here (since we're in a signal handler). + // So we just drop the signal or log if desired. + log("signal queue is full; dropping", .{}); + return false; + } + + // Store the signal into the ring buffer slot (Release to ensure data is visible). + @atomicStore(u8, &this.signals[old_tail % buffer_size], signal, .release); + + // Publish the new tail (Release so that the consumer sees the updated tail). + this.tail.store(old_tail +% 1, .release); + + JSC.VirtualMachine.getMainThreadVM().eventLoop().wakeup(); + + return true; + } + + /// This is the signal handler entry point. Calls enqueue on the ring buffer. + /// Note: Must be minimal logic here. Only do atomics & signal‐safe calls. + export fn Bun__onPosixSignal(number: i32) void { + const vm = JSC.VirtualMachine.getMainThreadVM(); + _ = vm.eventLoop().signal_handler.?.enqueue(@intCast(number)); + } + + /// Called by the main thread (single consumer). + /// Returns `null` if the ring is empty, or the next signal otherwise. + pub fn dequeue(this: *PosixSignalHandle) ?u8 { + // Read the current head and tail. + const old_head = this.head.load(.acquire); + const tail_val = this.tail.load(.acquire); + + // If head == tail, the ring is empty. + if (old_head == tail_val) { + return null; // No available items + } + + const slot_index = old_head % buffer_size; + // Acquire load of the stored signal to get the item. + const signal = @atomicRmw(u8, &this.signals[slot_index], .Xchg, 0, .acq_rel); + + // Publish the updated head (Release). + this.head.store(old_head +% 1, .release); + + return signal; + } + + /// Drain as many signals as possible and enqueue them as tasks in the event loop. + /// Called by the main thread. + pub fn drain(this: *PosixSignalHandle, event_loop: *JSC.EventLoop) void { + while (this.dequeue()) |signal| { + // Example: wrap the signal into a Task structure + var posix_signal_task: PosixSignalTask = undefined; + var task = JSC.Task.init(&posix_signal_task); + task.setUintptr(signal); + event_loop.enqueueTask(task); + } + } +}; + +pub const PosixSignalTask = struct { + number: u8, + extern "C" fn Bun__onSignalForJS(number: i32, globalObject: *JSC.JSGlobalObject) void; + + pub usingnamespace bun.New(@This()); + pub fn runFromJSThread(number: u8, globalObject: *JSC.JSGlobalObject) void { + Bun__onSignalForJS(number, globalObject); + } +}; diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 5d36c6c718..3d4a95e5a7 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -972,6 +972,7 @@ pub const VirtualMachine = struct { pub const VMHolder = struct { pub threadlocal var vm: ?*VirtualMachine = null; pub threadlocal var cached_global_object: ?*JSGlobalObject = null; + pub var main_thread_vm: *VirtualMachine = undefined; pub export fn Bun__setDefaultGlobalObject(global: *JSGlobalObject) void { if (vm) |vm_instance| { vm_instance.global = global; @@ -994,6 +995,10 @@ pub const VirtualMachine = struct { return VMHolder.vm.?; } + pub fn getMainThreadVM() *VirtualMachine { + return VMHolder.main_thread_vm; + } + pub fn mimeType(this: *VirtualMachine, str: []const u8) ?bun.http.MimeType { return this.rareData().mimeTypeFromString(this.allocator, str); } @@ -1957,6 +1962,7 @@ pub const VirtualMachine = struct { graph: ?*bun.StandaloneModuleGraph = null, debugger: bun.CLI.Command.Debugger = .{ .unspecified = {} }, + is_main_thread: bool = false, }; pub var is_smol_mode = false; @@ -1982,7 +1988,9 @@ pub const VirtualMachine = struct { opts.env_loader, ); var vm = VMHolder.vm.?; - + if (opts.is_main_thread) { + VMHolder.main_thread_vm = vm; + } vm.* = VirtualMachine{ .global = undefined, .transpiler_store = RuntimeTranspilerStore.init(), diff --git a/src/bun_js.zig b/src/bun_js.zig index 29198e5a73..602b010af6 100644 --- a/src/bun_js.zig +++ b/src/bun_js.zig @@ -64,6 +64,7 @@ pub const Run = struct { .log = ctx.log, .args = ctx.args, .graph = graph_ptr, + .is_main_thread = true, }), .arena = arena, .ctx = ctx, @@ -198,6 +199,7 @@ pub const Run = struct { .smol = ctx.runtime_options.smol, .eval = ctx.runtime_options.eval.eval_and_print, .debugger = ctx.runtime_options.debugger, + .is_main_thread = true, }, ), .arena = arena, diff --git a/src/cli/test_command.zig b/src/cli/test_command.zig index a918be8adc..a1229b5edc 100644 --- a/src/cli/test_command.zig +++ b/src/cli/test_command.zig @@ -1261,6 +1261,7 @@ pub const TestCommand = struct { .store_fd = true, .smol = ctx.runtime_options.smol, .debugger = ctx.runtime_options.debugger, + .is_main_thread = true, }, ); vm.argv = ctx.passthrough; diff --git a/src/tagged_pointer.zig b/src/tagged_pointer.zig index ef9122582f..f81aa656b3 100644 --- a/src/tagged_pointer.zig +++ b/src/tagged_pointer.zig @@ -153,6 +153,14 @@ pub fn TaggedPointerUnion(comptime Types: anytype) type { return this.repr.get(Type); } + pub inline fn setUintptr(this: *This, value: AddressableSize) void { + this.repr._ptr = value; + } + + pub inline fn asUintptr(this: This) AddressableSize { + return this.repr._ptr; + } + pub inline fn is(this: This, comptime Type: type) bool { comptime assert_type(Type); return this.repr.data == comptime @intFromEnum(@field(Tag, typeBaseName(@typeName(Type)))); diff --git a/test/regression/issue/ctrl-c.test.ts b/test/regression/issue/ctrl-c.test.ts index 1a511a6df7..232e9f17d2 100644 --- a/test/regression/issue/ctrl-c.test.ts +++ b/test/regression/issue/ctrl-c.test.ts @@ -1,5 +1,50 @@ import { expect, it, test } from "bun:test"; import { bunEnv, bunExe, isWindows, tempDirWithFiles } from "harness"; +import { join } from "path"; + +test.skipIf(isWindows)("verify that we can call sigint 4096 times", () => { + const dir = tempDirWithFiles("ctrlc", { + "index.js": /*js*/ ` + let count = 0; + process.exitCode = 1; + + const handler = () => { + count++; + console.count("SIGINT"); + if (count === 1024 * 4) { + process.off("SIGINT", handler); + process.exitCode = 0; + clearTimeout(timer); + } + }; + process.on("SIGINT", handler); + var timer = setTimeout(() => {}, 999999); + var remaining = 1024 * 4; + + function go() { + for (var i = 0, end = Math.min(1024, remaining); i < end; i++) { + process.kill(process.pid, "SIGINT"); + } + remaining -= i; + + if (remaining > 0) { + setTimeout(go, 10); + } + } + go(); + `, + }); + + const result = Bun.spawnSync({ + cmd: [bunExe(), join(dir, "index.js")], + cwd: dir, + env: bunEnv, + stdout: "inherit", + stderr: "inherit", + }); + expect(result.exitCode).toBe(0); + expect(result.signalCode).toBeUndefined(); +}); test.skipIf(isWindows)("verify that we forward SIGINT from parent to child in bun run", () => { const dir = tempDirWithFiles("ctrlc", { @@ -16,12 +61,12 @@ test.skipIf(isWindows)("verify that we forward SIGINT from parent to child in bu { "name": "ctrlc", "scripts": { - "start": "${bunExe()} index.js" + "start": " ${bunExe()} index.js" } } `, }); - + console.log(dir); const result = Bun.spawnSync({ cmd: [bunExe(), "start"], cwd: dir, @@ -90,14 +135,18 @@ for (const mode of [ killed: proc.killed, exitCode: proc.exitCode, signalCode: proc.signalCode, - }).toEqual(isWindows ? { - killed: true, - exitCode: 1, - signalCode: null, - } : { - killed: true, - exitCode: null, - signalCode: "SIGINT", - }); + }).toEqual( + isWindows + ? { + killed: true, + exitCode: 1, + signalCode: null, + } + : { + killed: true, + exitCode: null, + signalCode: "SIGINT", + }, + ); }); } From 1e196728411ed95c579e843d7b9a50414d5324db Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 13 Dec 2024 21:20:35 -0800 Subject: [PATCH 002/125] fix clangd --- .clangd | 3 +++ .vscode/settings.json | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.clangd b/.clangd index f736d521d0..b0ceeaa684 100644 --- a/.clangd +++ b/.clangd @@ -3,3 +3,6 @@ Index: CompileFlags: CompilationDatabase: build/debug + +Diagnostics: + UnusedIncludes: None diff --git a/.vscode/settings.json b/.vscode/settings.json index deead7e531..eca14849b6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -63,7 +63,6 @@ "editor.tabSize": 4, "editor.defaultFormatter": "xaver.clang-format", }, - "clangd.arguments": ["-header-insertion=never", "-no-unused-includes"], // JavaScript "prettier.enable": true, From ac12438f69c0713d2a8ee1e1f986a2a1701c2ed4 Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Fri, 13 Dec 2024 21:51:02 -0800 Subject: [PATCH 003/125] node: fix test-zlib-from-gzip-with-trailing-garbage.js (#15757) --- src/bun.js/node/node_zlib_binding.zig | 12 +++- ...st-zlib-from-gzip-with-trailing-garbage.js | 66 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 test/js/node/test/parallel/test-zlib-from-gzip-with-trailing-garbage.js diff --git a/src/bun.js/node/node_zlib_binding.zig b/src/bun.js/node/node_zlib_binding.zig index 8531c209d5..19f5e7d556 100644 --- a/src/bun.js/node/node_zlib_binding.zig +++ b/src/bun.js/node/node_zlib_binding.zig @@ -497,7 +497,17 @@ const ZlibContext = struct { return .{ .msg = message, .err = @intFromEnum(this.err), - .code = @tagName(this.err), + .code = switch (this.err) { + .Ok => "Z_OK", + .StreamEnd => "Z_STREAM_END", + .NeedDict => "Z_NEED_DICT", + .ErrNo => "Z_ERRNO", + .StreamError => "Z_STREAM_ERROR", + .DataError => "Z_DATA_ERROR", + .MemError => "Z_MEM_ERROR", + .BufError => "Z_BUF_ERROR", + .VersionError => "Z_VERSION_ERROR", + }, }; } diff --git a/test/js/node/test/parallel/test-zlib-from-gzip-with-trailing-garbage.js b/test/js/node/test/parallel/test-zlib-from-gzip-with-trailing-garbage.js new file mode 100644 index 0000000000..477a6c544f --- /dev/null +++ b/test/js/node/test/parallel/test-zlib-from-gzip-with-trailing-garbage.js @@ -0,0 +1,66 @@ +'use strict'; +// Test unzipping a gzip file that has trailing garbage + +const common = require('../common'); +const assert = require('assert'); +const zlib = require('zlib'); + +// Should ignore trailing null-bytes +let data = Buffer.concat([ + zlib.gzipSync('abc'), + zlib.gzipSync('def'), + Buffer.alloc(10), +]); + +assert.strictEqual(zlib.gunzipSync(data).toString(), 'abcdef'); + +zlib.gunzip(data, common.mustSucceed((result) => { + assert.strictEqual( + result.toString(), + 'abcdef', + `result '${result.toString()}' should match original string` + ); +})); + +// If the trailing garbage happens to look like a gzip header, it should +// throw an error. +data = Buffer.concat([ + zlib.gzipSync('abc'), + zlib.gzipSync('def'), + Buffer.from([0x1f, 0x8b, 0xff, 0xff]), + Buffer.alloc(10), +]); + +assert.throws( + () => zlib.gunzipSync(data), + /^Error: unknown compression method$/ +); + +zlib.gunzip(data, common.mustCall((err, result) => { + common.expectsError({ + code: 'Z_DATA_ERROR', + name: 'Error', + message: 'unknown compression method' + })(err); + assert.strictEqual(result, undefined); +})); + +// In this case the trailing junk is too short to be a gzip segment +// So we ignore it and decompression succeeds. +data = Buffer.concat([ + zlib.gzipSync('abc'), + zlib.gzipSync('def'), + Buffer.from([0x1f, 0x8b, 0xff, 0xff]), +]); + +assert.throws( + () => zlib.gunzipSync(data), + /^Error: unknown compression method$/ +); + +zlib.gunzip(data, common.mustCall((err, result) => { + assert(err instanceof Error); + assert.strictEqual(err.code, 'Z_DATA_ERROR'); + assert.strictEqual(err.message, 'unknown compression method'); + assert.strictEqual(result, undefined); +})); From c7020c2edcb09792b65eb91b69b321b128a1e9f3 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 13 Dec 2024 22:30:26 -0800 Subject: [PATCH 004/125] Make --expose gc work in nodetests --- test/js/node/test/common/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/js/node/test/common/index.js b/test/js/node/test/common/index.js index 9a044595e8..c5822beb34 100644 --- a/test/js/node/test/common/index.js +++ b/test/js/node/test/common/index.js @@ -119,6 +119,10 @@ if (process.argv.length === 2 && // If the binary is build without `intl` the inspect option is // invalid. The test itself should handle this case. (process.features.inspector || !flag.startsWith('--inspect'))) { + if (flag === "--expose-gc" && process.versions.bun) { + globalThis.gc ??= Bun.gc; + continue; + } console.log( 'NOTE: The test started as a child_process using these flags:', inspect(flags), From 3df39f4bb73d1941a2cc00071f60c5e60d7dc2c6 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Fri, 13 Dec 2024 22:40:12 -0800 Subject: [PATCH 005/125] bun.lock: fix `--frozen-lockfile` and resolving extra dependencies (#15748) --- src/install/bun.lock.zig | 224 ++++++++++-- src/install/install.zig | 24 +- src/install/lockfile.zig | 303 +++++++++++++--- src/install/migration.zig | 2 +- test/cli/install/bun-add.test.ts | 8 +- .../bun-install-registry.test.ts.snap | 35 ++ .../registry/bun-install-registry.test.ts | 85 ++++- test/harness.ts | 8 + .../dev-server-ssr-100.test.ts.snap | 162 ++++----- .../__snapshots__/dev-server.test.ts.snap | 162 ++++----- .../__snapshots__/next-build.test.ts.snap | 324 ++++++++---------- 11 files changed, 872 insertions(+), 465 deletions(-) diff --git a/src/install/bun.lock.zig b/src/install/bun.lock.zig index c399aecc75..2e1a407f8c 100644 --- a/src/install/bun.lock.zig +++ b/src/install/bun.lock.zig @@ -35,6 +35,7 @@ const Meta = BinaryLockfile.Package.Meta; const Negatable = Npm.Negatable; const DependencyID = Install.DependencyID; const invalid_dependency_id = Install.invalid_dependency_id; +const DependencyIDSlice = BinaryLockfile.DependencyIDSlice; /// A property key in the `packages` field of the lockfile pub const PkgPath = struct { @@ -213,6 +214,9 @@ pub const PkgPath = struct { }; } + // TODO(dylan-conway): The structure of this map can change + // now that a path buffer is used. Parent isn't needed, and + // keys don't need to be iterated. pub const Map = struct { root: Node, @@ -515,10 +519,33 @@ pub const Stringifier = struct { try decIndent(writer, indent); try writer.writeAll("},\n"); + const TreeSortCtx = struct { + pub const Item = struct { []const DependencyID, string, usize }; + + pub fn isLessThan(_: void, l: Item, r: Item) bool { + _, const l_rel_path, const l_depth = l; + _, const r_rel_path, const r_depth = r; + return switch (std.math.order(l_depth, r_depth)) { + .lt => true, + .gt => false, + .eq => strings.order(l_rel_path, r_rel_path) == .lt, + }; + } + }; + + var tree_sort_buf: std.ArrayListUnmanaged(TreeSortCtx.Item) = .{}; + defer tree_sort_buf.deinit(allocator); + var pkgs_iter = BinaryLockfile.Tree.Iterator(.pkg_path).init(lockfile); // find trusted and patched dependencies. also overrides while (pkgs_iter.next({})) |node| { + try tree_sort_buf.append(allocator, .{ + node.dependencies, + try allocator.dupe(u8, node.relative_path), + node.depth, + }); + for (node.dependencies) |dep_id| { const pkg_id = resolution_buf[dep_id]; if (pkg_id == invalid_package_id) continue; @@ -570,6 +597,13 @@ pub const Stringifier = struct { pkgs_iter.reset(); + std.sort.pdq( + TreeSortCtx.Item, + tree_sort_buf.items, + {}, + TreeSortCtx.isLessThan, + ); + if (found_trusted_dependencies.count() > 0) { try writeIndent(writer, indent); try writer.writeAll( @@ -661,9 +695,10 @@ pub const Stringifier = struct { try writeIndent(writer, indent); try writer.writeAll("\"packages\": {"); var first = true; - while (pkgs_iter.next({})) |node| { + for (tree_sort_buf.items) |item| { + const dependencies, const relative_path, const depth = item; deps_sort_buf.clearRetainingCapacity(); - try deps_sort_buf.appendSlice(allocator, node.dependencies); + try deps_sort_buf.appendSlice(allocator, dependencies); std.sort.pdq( DependencyID, @@ -690,15 +725,15 @@ pub const Stringifier = struct { try writer.writeByte('\n'); try incIndent(writer, indent); } else { - try writer.writeAll(",\n"); + try writer.writeAll(",\n\n"); try writeIndent(writer, indent); } try writer.writeByte('"'); // relative_path is empty string for root resolutions - try writer.writeAll(node.relative_path); + try writer.writeAll(relative_path); - if (node.depth != 0) { + if (depth != 0) { try writer.writeByte('/'); } @@ -824,7 +859,9 @@ pub const Stringifier = struct { try writePackageDepsAndMeta(writer, dep_id, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, buf, &optional_peers_buf); - try writer.writeByte(']'); + try writer.print(", {}]", .{ + bun.fmt.formatJSONStringUTF8(repo.resolved.slice(buf), .{ .quote = true }), + }); }, else => unreachable, } @@ -900,7 +937,7 @@ pub const Stringifier = struct { if (optional_peers_buf.items.len > 0) { bun.debugAssert(any); try writer.writeAll( - \\, "optionalPeerDependencies": [ + \\, "optionalPeers": [ ); for (optional_peers_buf.items, 0..) |optional_peer, i| { @@ -1050,7 +1087,7 @@ pub const Stringifier = struct { ); try writeIndent(writer, indent); try writer.writeAll( - \\"optionalPeerDependencies": [ + \\"optionalPeers": [ \\ ); indent.* += 1; @@ -1093,12 +1130,6 @@ pub const Stringifier = struct { } }; -const dependency_groups = [3]struct { []const u8, Dependency.Behavior }{ - .{ "dependencies", Dependency.Behavior.normal }, - .{ "peerDependencies", Dependency.Behavior.normal }, - .{ "optionalDependencies", Dependency.Behavior.normal }, -}; - const workspace_dependency_groups = [4]struct { []const u8, Dependency.Behavior }{ .{ "dependencies", Dependency.Behavior.normal }, .{ "devDependencies", Dependency.Behavior.dev }, @@ -1108,6 +1139,7 @@ const workspace_dependency_groups = [4]struct { []const u8, Dependency.Behavior const ParseError = OOM || error{ InvalidLockfileVersion, + UnknownLockfileVersion, InvalidOptionalValue, InvalidPeerValue, InvalidDefaultRegistry, @@ -1147,9 +1179,22 @@ pub fn parseIntoBinaryLockfile( return error.InvalidLockfileVersion; }; - const lockfile_version: u32 = switch (lockfile_version_expr.data) { - .e_number => |num| @intFromFloat(std.math.divExact(f64, num.value, 1) catch return error.InvalidLockfileVersion), - else => return error.InvalidLockfileVersion, + const lockfile_version: u32 = lockfile_version: { + err: { + switch (lockfile_version_expr.data) { + .e_number => |num| { + if (num.value < 0 or num.value > std.math.maxInt(u32)) { + break :err; + } + + break :lockfile_version @intFromFloat(std.math.divExact(f64, num.value, 1) catch break :err); + }, + else => {}, + } + } + + try log.addError(source, lockfile_version_expr.loc, "Invalid lockfile version"); + return error.InvalidLockfileVersion; }; lockfile.text_lockfile_version = std.meta.intToEnum(Version, lockfile_version) catch { @@ -1323,13 +1368,12 @@ pub fn parseIntoBinaryLockfile( defer optional_peers_buf.deinit(allocator); if (maybe_root_pkg) |root_pkg| { - // TODO(dylan-conway): maybe sort this. behavior is already sorted, but names are not const maybe_name = if (root_pkg.get("name")) |name| name.asString(allocator) orelse { try log.addError(source, name.loc, "Expected a string"); return error.InvalidWorkspaceObject; } else null; - const off, const len = try parseAppendDependencies(lockfile, allocator, &root_pkg, &string_buf, log, source, &optional_peers_buf); + const off, var len = try parseAppendDependencies(lockfile, allocator, &root_pkg, &string_buf, log, source, &optional_peers_buf); var pkg: BinaryLockfile.Package = .{}; pkg.meta.id = 0; @@ -1340,10 +1384,39 @@ pub fn parseIntoBinaryLockfile( pkg.name_hash = name_hash; } + workspaces: for (lockfile.workspace_paths.values()) |workspace_path| { + for (workspaces.data.e_object.properties.slice()) |prop| { + const key = prop.key.?; + const value = prop.value.?; + const path = key.asString(allocator).?; + if (!strings.eqlLong(path, workspace_path.slice(string_buf.bytes.items), true)) continue; + + const name = value.get("name").?.asString(allocator).?; + const name_hash = String.Builder.stringHash(name); + + var dep: Dependency = .{}; + dep.name = try string_buf.appendWithHash(name, name_hash); + dep.name_hash = name_hash; + dep.behavior = Dependency.Behavior.workspace; + dep.version = .{ + .tag = .workspace, + .value = .{ + .workspace = try string_buf.append(path), + }, + }; + + try lockfile.buffers.dependencies.append(allocator, dep); + len += 1; + continue :workspaces; + } + } + pkg.dependencies = .{ .off = off, .len = len }; pkg.resolutions = .{ .off = off, .len = len }; + pkg.meta.id = 0; try lockfile.packages.append(allocator, pkg); + try lockfile.getOrPutID(0, pkg.name_hash); } else { try log.addError(source, workspaces.loc, "Expected root package"); return error.InvalidWorkspaceObject; @@ -1409,11 +1482,10 @@ pub fn parseIntoBinaryLockfile( }; if (res.tag == .npm) { - if (pkg_info.len < 2) { + if (i >= pkg_info.len) { try log.addError(source, value.loc, "Missing npm registry"); return error.InvalidPackageInfo; } - const registry_expr = pkg_info.at(i); i += 1; @@ -1441,6 +1513,11 @@ pub fn parseIntoBinaryLockfile( // dependencies, os, cpu, libc switch (res.tag) { .npm, .folder, .git, .github, .local_tarball, .remote_tarball, .symlink, .workspace => { + if (i >= pkg_info.len) { + try log.addError(source, value.loc, "Missing dependencies object"); + return error.InvalidPackageInfo; + } + const deps_os_cpu_libc_obj = pkg_info.at(i); i += 1; if (!deps_os_cpu_libc_obj.isObject()) { @@ -1448,7 +1525,6 @@ pub fn parseIntoBinaryLockfile( return error.InvalidPackageInfo; } - // TODO(dylan-conway): maybe sort this. behavior is already sorted, but names are not const off, const len = try parseAppendDependencies(lockfile, allocator, deps_os_cpu_libc_obj, &string_buf, log, source, &optional_peers_buf); pkg.dependencies = .{ .off = off, .len = len }; @@ -1473,6 +1549,10 @@ pub fn parseIntoBinaryLockfile( // integrity switch (res.tag) { .npm => { + if (i >= pkg_info.len) { + try log.addError(source, value.loc, "Missing integrity"); + return error.InvalidPackageInfo; + } const integrity_expr = pkg_info.at(i); i += 1; const integrity_str = integrity_expr.asString(allocator) orelse { @@ -1482,6 +1562,23 @@ pub fn parseIntoBinaryLockfile( pkg.meta.integrity = Integrity.parse(integrity_str); }, + inline .git, .github => |tag| { + // .bun-tag + if (i >= pkg_info.len) { + try log.addError(source, value.loc, "Missing git dependency tag"); + return error.InvalidPackageInfo; + } + + const bun_tag = pkg_info.at(i); + i += 1; + + const bun_tag_str = bun_tag.asString(allocator) orelse { + try log.addError(source, bun_tag.loc, "Expected a string"); + return error.InvalidPackageInfo; + }; + + @field(res.value, @tagName(tag)).resolved = try string_buf.append(bun_tag_str); + }, else => {}, } @@ -1536,7 +1633,9 @@ pub fn parseIntoBinaryLockfile( const dep = lockfile.buffers.dependencies.items[dep_id]; if (pkg_map.root.nodes.getPtr(dep.name.slice(string_buf.bytes.items))) |dep_node| { - dep_node.dep_id = dep_id; + if (dep_node.dep_id == invalid_dependency_id) { + dep_node.dep_id = dep_id; + } lockfile.buffers.resolutions.items[dep_id] = dep_node.pkg_id; } } @@ -1545,6 +1644,8 @@ pub fn parseIntoBinaryLockfile( } + var path_buf: bun.PathBuffer = undefined; + // then each package dependency for (pkgs_expr.data.e_object.properties.slice()) |prop| { const key = prop.key.?; @@ -1566,17 +1667,74 @@ pub fn parseIntoBinaryLockfile( deps: for (pkg_deps[pkg_id].begin()..pkg_deps[pkg_id].end()) |_dep_id| { const dep_id: DependencyID = @intCast(_dep_id); const dep = lockfile.buffers.dependencies.items[dep_id]; + const dep_name = dep.name.slice(string_buf.bytes.items); - var curr: ?*PkgPath.Map.Node = pkg_map_entry; - while (curr) |node| { - if (node.nodes.getPtr(dep.name.slice(string_buf.bytes.items))) |dep_node| { - dep_node.dep_id = dep_id; - lockfile.buffers.resolutions.items[dep_id] = dep_node.pkg_id; + @memcpy(path_buf[0..pkg_path.len], pkg_path); + path_buf[pkg_path.len] = '/'; + var offset = pkg_path.len + 1; + var valid = true; + while (valid) { + @memcpy(path_buf[offset..][0..dep_name.len], dep_name); + const res_path = path_buf[0 .. offset + dep_name.len]; + + if (try pkg_map.get(res_path)) |entry| { + if (entry.dep_id == invalid_dependency_id) { + entry.dep_id = dep_id; + } + lockfile.buffers.resolutions.items[dep_id] = entry.pkg_id; continue :deps; } - curr = node.parent orelse if (curr != &pkg_map.root) &pkg_map.root else null; + + if (offset == 0) { + if (dep.behavior.isOptionalPeer()) { + continue :deps; + } + try log.addError(source, key.loc, "Unable to resolve dependencies for package"); + return error.InvalidPackageInfo; + } + + const slash = strings.lastIndexOfChar(path_buf[0 .. offset - 1], '/') orelse { + offset = 0; + continue; + }; + + // might be a scoped package + const at = strings.lastIndexOfChar(path_buf[0 .. offset - 1], '@') orelse { + offset = slash + 1; + continue; + }; + + if (at > slash) { + valid = false; + continue; + } + + const next_slash = strings.lastIndexOfChar(path_buf[0..slash], '/') orelse { + if (at != 0) { + try log.addError(source, key.loc, "Invalid package path"); + return error.InvalidPackageKey; + } + offset = 0; + continue; + }; + + if (next_slash > at) { + // there's a scoped package but it exists farther up + offset = slash + 1; + continue; + } + + if (next_slash + 1 != at) { + valid = false; + continue; + } + + offset = at; } + + try log.addError(source, key.loc, "Invalid package path"); + return error.InvalidPackageKey; } } @@ -1606,10 +1764,12 @@ pub fn parseIntoBinaryLockfile( tree_id += 1; } } + } else { + lockfile.initEmpty(allocator); + return; } - lockfile.buffers.string_bytes = string_buf.bytes.moveToUnmanaged(); - lockfile.string_pool = string_buf.pool; + string_buf.apply(lockfile); } fn parseAppendDependencies( @@ -1623,7 +1783,7 @@ fn parseAppendDependencies( ) ParseError!struct { u32, u32 } { defer optional_peers_buf.clearRetainingCapacity(); - if (obj.get("optionalPeerDependencies")) |optional_peers| { + if (obj.get("optionalPeers")) |optional_peers| { if (!optional_peers.isArray()) { try log.addError(source, optional_peers.loc, "Expected an array"); return error.InvalidPackageInfo; diff --git a/src/install/install.zig b/src/install/install.zig index 2ff59a5060..bcc3d8cb50 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -14659,6 +14659,8 @@ pub const PackageManager = struct { manager.log.reset(); // This operation doesn't perform any I/O, so it should be relatively cheap. + const lockfile_before_clean = manager.lockfile; + manager.lockfile = try manager.lockfile.cleanWithLogger( manager, manager.update_requests, @@ -14751,14 +14753,22 @@ pub const PackageManager = struct { const packages_len_before_install = manager.lockfile.packages.len; - if (manager.options.enable.frozen_lockfile and load_result != .not_found) { - if (manager.lockfile.hasMetaHashChanged(PackageManager.verbose_install or manager.options.do.print_meta_hash_string, packages_len_before_install) catch false) { - if (comptime log_level != .silent) { - Output.prettyErrorln("error: lockfile had changes, but lockfile is frozen", .{}); - Output.note("try re-running without --frozen-lockfile and commit the updated lockfile", .{}); + if (manager.options.enable.frozen_lockfile and load_result != .not_found) frozen_lockfile: { + if (load_result.loadedFromTextLockfile()) { + if (manager.lockfile.eql(lockfile_before_clean, manager.allocator) catch bun.outOfMemory()) { + break :frozen_lockfile; + } + } else { + if (!(manager.lockfile.hasMetaHashChanged(PackageManager.verbose_install or manager.options.do.print_meta_hash_string, packages_len_before_install) catch false)) { + break :frozen_lockfile; } - Global.crash(); } + + if (comptime log_level != .silent) { + Output.prettyErrorln("error: lockfile had changes, but lockfile is frozen", .{}); + Output.note("try re-running without --frozen-lockfile and commit the updated lockfile", .{}); + } + Global.crash(); } var install_summary = PackageInstall.Summary{ @@ -15174,7 +15184,7 @@ pub const bun_install_js_bindings = struct { const cwd = try args[0].toSliceOrNull(globalObject); defer cwd.deinit(); - var dir = bun.openDirAbsolute(cwd.slice()) catch |err| { + var dir = bun.openDirAbsoluteNotForDeletingOrRenaming(cwd.slice()) catch |err| { return globalObject.throw("failed to open: {s}, '{s}'", .{ @errorName(err), cwd.slice() }); }; defer dir.close(); diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index a1f7e748fc..14493dcd78 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -242,6 +242,14 @@ pub const LoadResult = union(enum) { } }; + pub fn loadedFromTextLockfile(this: LoadResult) bool { + return switch (this) { + .not_found => false, + .err => |err| err.format == .text, + .ok => |ok| ok.format == .text, + }; + } + pub const Step = enum { open_file, read_file, parse_file, migrating }; }; @@ -321,6 +329,7 @@ pub fn loadFromDir( if (lockfile_format == .text) { const source = logger.Source.initPathString("bun.lock", buf); + initializeStore(); const json = JSON.parsePackageJSONUTF8(&source, log, allocator) catch |err| { return .{ .err = .{ @@ -374,6 +383,7 @@ pub fn loadFromDir( }; const source = logger.Source.initPathString("bun.lock", text_lockfile_bytes); + initializeStore(); const json = JSON.parsePackageJSONUTF8(&source, log, allocator) catch |err| { Output.panic("failed to print valid json from binary lockfile: {s}", .{@errorName(err)}); }; @@ -474,11 +484,18 @@ pub const Tree = struct { pub const root_dep_id: DependencyID = invalid_package_id - 1; pub const invalid_id: Id = std.math.maxInt(Id); - const dependency_loop = invalid_id - 1; - const hoisted = invalid_id - 2; - const error_id = hoisted; - const SubtreeError = error{ OutOfMemory, DependencyLoop }; + pub const HoistResult = union(enum) { + dependency_loop, + hoisted, + dest_id: Id, + replace: struct { + dest_id: Id, + dep_id: DependencyID, + }, + }; + + const SubtreeError = OOM || error{DependencyLoop}; // max number of node_modules folders pub const max_depth = (bun.MAX_PATH_BYTES / "node_modules".len) + 1; @@ -646,6 +663,7 @@ pub const Tree = struct { log: *logger.Log, lockfile: *Lockfile, prefer_dev_dependencies: bool = false, + sort_buf: std.ArrayListUnmanaged(DependencyID) = .{}, pub fn maybeReportError(this: *Builder, comptime fmt: string, args: anytype) void { this.log.addErrorFmt(null, logger.Loc.Empty, this.allocator, fmt, args) catch {}; @@ -694,6 +712,7 @@ pub const Tree = struct { } } this.queue.deinit(); + this.sort_buf.deinit(this.allocator); return dependency_ids; } @@ -729,18 +748,45 @@ pub const Tree = struct { const max_package_id = @as(PackageID, @truncate(name_hashes.len)); const resolutions = builder.lockfile.packages.items(.resolution); - var dep_id = resolution_list.off; - const end = dep_id + resolution_list.len; + builder.sort_buf.clearRetainingCapacity(); + try builder.sort_buf.ensureUnusedCapacity(builder.allocator, resolution_list.len); - while (dep_id < end) : (dep_id += 1) { + for (resolution_list.begin()..resolution_list.end()) |dep_id| { + builder.sort_buf.appendAssumeCapacity(@intCast(dep_id)); + } + + const DepSorter = struct { + lockfile: *const Lockfile, + + pub fn isLessThan(sorter: @This(), l: DependencyID, r: DependencyID) bool { + const deps_buf = sorter.lockfile.buffers.dependencies.items; + const string_buf = sorter.lockfile.buffers.string_bytes.items; + + const l_dep_name = deps_buf[l].name.slice(string_buf); + const r_dep_name = deps_buf[r].name.slice(string_buf); + + return strings.order(l_dep_name, r_dep_name) == .lt; + } + }; + + std.sort.pdq( + DependencyID, + builder.sort_buf.items, + DepSorter{ + .lockfile = builder.lockfile, + }, + DepSorter.isLessThan, + ); + + for (builder.sort_buf.items) |dep_id| { const pid = builder.resolutions[dep_id]; // Skip unresolved packages, e.g. "peerDependencies" if (pid >= max_package_id) continue; const dependency = builder.dependencies[dep_id]; // Do not hoist folder dependencies - const destination = if (resolutions[pid].tag == .folder) - next.id + const res: HoistResult = if (resolutions[pid].tag == .folder) + .{ .dest_id = next.id } else try next.hoistDependency( true, @@ -751,14 +797,23 @@ pub const Tree = struct { builder, ); - switch (destination) { - Tree.dependency_loop, Tree.hoisted => continue, - else => { - dependency_lists[destination].append(builder.allocator, dep_id) catch unreachable; - trees[destination].dependencies.len += 1; + switch (res) { + .dependency_loop, .hoisted => continue, + .replace => |replacement| { + var dep_ids = dependency_lists[replacement.dest_id].items; + for (0..dep_ids.len) |i| { + if (dep_ids[i] == replacement.dep_id) { + dep_ids[i] = dep_id; + break; + } + } + }, + .dest_id => |dest_id| { + dependency_lists[dest_id].append(builder.allocator, dep_id) catch bun.outOfMemory(); + trees[dest_id].dependencies.len += 1; if (builder.resolution_lists[pid].len > 0) { try builder.queue.writeItem(.{ - .tree_id = destination, + .tree_id = dest_id, .dependency_id = dep_id, }); } @@ -776,6 +831,7 @@ pub const Tree = struct { // 1 (return hoisted) - de-duplicate (skip) the package // 2 (return id) - move the package to the top directory // 3 (return dependency_loop) - leave the package at the same (relative) directory + // 4 (replace) - replace the existing (same name) parent dependency fn hoistDependency( this: *Tree, comptime as_defined: bool, @@ -784,15 +840,16 @@ pub const Tree = struct { dependency_lists: []Lockfile.DependencyIDList, trees: []Tree, builder: *Builder, - ) !Id { - const this_dependencies = this.dependencies.get(dependency_lists[this.id].items); - for (this_dependencies) |dep_id| { + ) !HoistResult { + const this_dependencies = this.dependencies.mut(dependency_lists[this.id].items); + for (0..this_dependencies.len) |i| { + const dep_id = this_dependencies[i]; const dep = builder.dependencies[dep_id]; if (dep.name_hash != dependency.name_hash) continue; if (builder.resolutions[dep_id] == package_id) { // this dependency is the same package as the other, hoist - return hoisted; // 1 + return .hoisted; // 1 } if (comptime as_defined) { @@ -800,10 +857,10 @@ pub const Tree = struct { // choose dev dep over other if enabled if (dep.behavior.isDev() != dependency.behavior.isDev()) { if (builder.prefer_dev_dependencies and dep.behavior.isDev()) { - return hoisted; // 1 + return .hoisted; // 1 } - return dependency_loop; // 3 + return .dependency_loop; // 3 } } @@ -815,7 +872,7 @@ pub const Tree = struct { const resolution: Resolution = builder.lockfile.packages.items(.resolution)[builder.resolutions[dep_id]]; const version = dependency.version.value.npm.version; if (resolution.tag == .npm and version.satisfies(resolution.value.npm.version, builder.buf(), builder.buf())) { - return hoisted; // 1 + return .hoisted; // 1 } } @@ -823,7 +880,7 @@ pub const Tree = struct { // to hoist other peers even if they don't satisfy the version if (builder.lockfile.isWorkspaceRootDependency(dep_id)) { // TODO: warning about peer dependency version mismatch - return hoisted; // 1 + return .hoisted; // 1 } } @@ -839,11 +896,26 @@ pub const Tree = struct { return error.DependencyLoop; } - return dependency_loop; // 3 + if (dependency.version.tag == .npm and dep.version.tag == .npm) { + + // if the dependency is wildcard, use the existing dependency + // in the parent + if (dependency.version.value.npm.version.@"is *"()) { + return .hoisted; + } + + // if the parent dependency is wildcard, replace with the + // current dependency + if (dep.version.value.npm.version.@"is *"()) { + return .{ .replace = .{ .dest_id = this.id, .dep_id = dep_id } }; // 4 + } + } + + return .dependency_loop; // 3 } // this dependency was not found in this tree, try hoisting or placing in the next parent - if (this.parent < error_id) { + if (this.parent != invalid_id) { const id = trees[this.parent].hoistDependency( false, package_id, @@ -852,11 +924,11 @@ pub const Tree = struct { trees, builder, ) catch unreachable; - if (!as_defined or id != dependency_loop) return id; // 1 or 2 + if (!as_defined or id != .dependency_loop) return id; // 1 or 2 } // place the dependency in the current tree - return this.id; // 2 + return .{ .dest_id = this.id }; // 2 } }; @@ -906,26 +978,35 @@ pub fn maybeCloneFilteringRootPackages( } fn preprocessUpdateRequests(old: *Lockfile, manager: *PackageManager, updates: []PackageManager.UpdateRequest, exact_versions: bool) !void { - const root_deps_list: Lockfile.DependencySlice = old.packages.items(.dependencies)[0]; + const workspace_package_id = manager.root_package_id.get(old, manager.workspace_name_hash); + const root_deps_list: Lockfile.DependencySlice = old.packages.items(.dependencies)[workspace_package_id]; + if (@as(usize, root_deps_list.off) < old.buffers.dependencies.items.len) { var string_builder = old.stringBuilder(); { const root_deps: []const Dependency = root_deps_list.get(old.buffers.dependencies.items); - const old_resolutions_list = old.packages.items(.resolutions)[0]; + const old_resolutions_list = old.packages.items(.resolutions)[workspace_package_id]; const old_resolutions: []const PackageID = old_resolutions_list.get(old.buffers.resolutions.items); const resolutions_of_yore: []const Resolution = old.packages.items(.resolution); for (updates) |update| { - if (update.version.tag == .uninitialized) { + if (update.package_id == invalid_package_id) { for (root_deps, old_resolutions) |dep, old_resolution| { if (dep.name_hash == String.Builder.stringHash(update.name)) { if (old_resolution > old.packages.len) continue; const res = resolutions_of_yore[old_resolution]; + if (res.tag != .npm or update.version.tag != .dist_tag) continue; + + // TODO(dylan-conway): this will need to handle updating dependencies (exact, ^, or ~) and aliases + const len = switch (exact_versions) { - false => std.fmt.count("^{}", .{res.value.npm.version.fmt(old.buffers.string_bytes.items)}), - true => std.fmt.count("{}", .{res.value.npm.version.fmt(old.buffers.string_bytes.items)}), + else => |exact| std.fmt.count("{s}{}", .{ + if (exact) "" else "^", + res.value.npm.version.fmt(old.buffers.string_bytes.items), + }), }; + if (len >= String.max_inline_len) { string_builder.cap += len; } @@ -943,20 +1024,27 @@ fn preprocessUpdateRequests(old: *Lockfile, manager: *PackageManager, updates: [ const root_deps: []Dependency = root_deps_list.mut(old.buffers.dependencies.items); const old_resolutions_list_lists = old.packages.items(.resolutions); - const old_resolutions_list = old_resolutions_list_lists[0]; + const old_resolutions_list = old_resolutions_list_lists[workspace_package_id]; const old_resolutions: []const PackageID = old_resolutions_list.get(old.buffers.resolutions.items); const resolutions_of_yore: []const Resolution = old.packages.items(.resolution); for (updates) |*update| { - if (update.version.tag == .uninitialized) { + if (update.package_id == invalid_package_id) { for (root_deps, old_resolutions) |*dep, old_resolution| { if (dep.name_hash == String.Builder.stringHash(update.name)) { if (old_resolution > old.packages.len) continue; const res = resolutions_of_yore[old_resolution]; + if (res.tag != .npm or update.version.tag != .dist_tag) continue; + + // TODO(dylan-conway): this will need to handle updating dependencies (exact, ^, or ~) and aliases + const buf = switch (exact_versions) { - false => std.fmt.bufPrint(&temp_buf, "^{}", .{res.value.npm.version.fmt(old.buffers.string_bytes.items)}) catch break, - true => std.fmt.bufPrint(&temp_buf, "{}", .{res.value.npm.version.fmt(old.buffers.string_bytes.items)}) catch break, + else => |exact| std.fmt.bufPrint(&temp_buf, "{s}{}", .{ + if (exact) "" else "^", + res.value.npm.version.fmt(old.buffers.string_bytes.items), + }) catch break, }; + const external_version = string_builder.append(ExternalString, buf); const sliced = external_version.value.sliced(old.buffers.string_bytes.items); dep.version = Dependency.parse( @@ -2167,7 +2255,6 @@ pub fn saveToDisk(this: *Lockfile, save_format: LoadResult.LockfileFormat, verbo assert(FileSystem.instance_loaded); } - const timer = std.time.Timer.start() catch unreachable; const bytes = if (save_format == .text) TextLockfile.Stringifier.saveFromBinary(bun.default_allocator, this) catch |err| { switch (err) { @@ -2188,8 +2275,6 @@ pub fn saveToDisk(this: *Lockfile, save_format: LoadResult.LockfileFormat, verbo break :bytes bytes.items; }; defer bun.default_allocator.free(bytes); - _ = timer; - // std.debug.print("time to write {s}: {}\n", .{ @tagName(save_format), bun.fmt.fmtDuration(timer.read()) }); var tmpname_buf: [512]u8 = undefined; var base64_bytes: [8]u8 = undefined; @@ -2341,7 +2426,7 @@ pub fn appendPackageDedupe(this: *Lockfile, pkg: *Package, buf: string) OOM!Pack return new_id; } - const resolutions = this.packages.items(.resolution); + var resolutions = this.packages.items(.resolution); return switch (entry.value_ptr.*) { .id => |existing_id| { @@ -2354,6 +2439,8 @@ pub fn appendPackageDedupe(this: *Lockfile, pkg: *Package, buf: string) OOM!Pack pkg.meta.id = new_id; try this.packages.append(this.allocator, pkg.*); + resolutions = this.packages.items(.resolution); + var ids = try PackageIDList.initCapacity(this.allocator, 8); ids.items.len = 2; @@ -2380,6 +2467,8 @@ pub fn appendPackageDedupe(this: *Lockfile, pkg: *Package, buf: string) OOM!Pack pkg.meta.id = new_id; try this.packages.append(this.allocator, pkg.*); + resolutions = this.packages.items(.resolution); + for (existing_ids.items, 0..) |existing_id, i| { if (pkg.resolution.order(&resolutions[existing_id], buf, buf) == .gt) { try existing_ids.insert(this.allocator, i, new_id); @@ -6608,6 +6697,140 @@ pub const Serializer = struct { } }; +pub const EqlSorter = struct { + string_buf: string, + pkg_names: []const String, + + // Basically placement id + pub const IdPair = struct { + pkg_id: PackageID, + tree_id: Tree.Id, + tree_path: string, + }; + + pub fn isLessThan(this: @This(), l: IdPair, r: IdPair) bool { + switch (strings.order(l.tree_path, r.tree_path)) { + .lt => return true, + .gt => return false, + .eq => {}, + } + + // they exist in the same tree, name can't be the same so string + // compare. + const l_name = this.pkg_names[l.pkg_id]; + const r_name = this.pkg_names[r.pkg_id]; + return l_name.order(&r_name, this.string_buf, this.string_buf) == .lt; + } +}; + +pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) OOM!bool { + const l_hoisted_deps = l.buffers.hoisted_dependencies.items; + const r_hoisted_deps = r.buffers.hoisted_dependencies.items; + const l_string_buf = l.buffers.string_bytes.items; + const r_string_buf = r.buffers.string_bytes.items; + + const l_len = l_hoisted_deps.len; + const r_len = r_hoisted_deps.len; + + if (l_len != r_len) return false; + + const sort_buf = try allocator.alloc(EqlSorter.IdPair, l_len + r_len); + defer l.allocator.free(sort_buf); + var l_buf = sort_buf[0..l_len]; + var r_buf = sort_buf[r_len..]; + + var path_buf: bun.PathBuffer = undefined; + var depth_buf: Tree.DepthBuf = undefined; + + var i: usize = 0; + for (l.buffers.trees.items) |l_tree| { + const rel_path, _ = Tree.relativePathAndDepth(l, l_tree.id, &path_buf, &depth_buf, .pkg_path); + const tree_path = try allocator.dupe(u8, rel_path); + for (l_tree.dependencies.get(l_hoisted_deps)) |l_dep_id| { + if (l_dep_id == invalid_dependency_id) continue; + const l_pkg_id = l.buffers.resolutions.items[l_dep_id]; + if (l_pkg_id == invalid_package_id) continue; + l_buf[i] = .{ + .pkg_id = l_pkg_id, + .tree_id = l_tree.id, + .tree_path = tree_path, + }; + i += 1; + } + } + l_buf = l_buf[0..i]; + + i = 0; + for (r.buffers.trees.items) |r_tree| { + const rel_path, _ = Tree.relativePathAndDepth(r, r_tree.id, &path_buf, &depth_buf, .pkg_path); + const tree_path = try allocator.dupe(u8, rel_path); + for (r_tree.dependencies.get(r_hoisted_deps)) |r_dep_id| { + if (r_dep_id == invalid_dependency_id) continue; + const r_pkg_id = r.buffers.resolutions.items[r_dep_id]; + if (r_pkg_id == invalid_package_id) continue; + r_buf[i] = .{ + .pkg_id = r_pkg_id, + .tree_id = r_tree.id, + .tree_path = tree_path, + }; + i += 1; + } + } + r_buf = r_buf[0..i]; + + if (l_buf.len != r_buf.len) return false; + + const l_pkgs = l.packages.slice(); + const r_pkgs = r.packages.slice(); + const l_pkg_names = l_pkgs.items(.name); + const r_pkg_names = r_pkgs.items(.name); + + std.sort.pdq( + EqlSorter.IdPair, + l_buf, + EqlSorter{ + .pkg_names = l_pkg_names, + .string_buf = l_string_buf, + }, + EqlSorter.isLessThan, + ); + + std.sort.pdq( + EqlSorter.IdPair, + r_buf, + EqlSorter{ + .pkg_names = r_pkg_names, + .string_buf = r_string_buf, + }, + EqlSorter.isLessThan, + ); + + const l_pkg_name_hashes = l_pkgs.items(.name_hash); + const l_pkg_resolutions = l_pkgs.items(.resolution); + const r_pkg_name_hashes = r_pkgs.items(.name_hash); + const r_pkg_resolutions = r_pkgs.items(.resolution); + + for (l_buf, r_buf) |l_ids, r_ids| { + const l_pkg_id = l_ids.pkg_id; + const r_pkg_id = r_ids.pkg_id; + if (l_pkg_name_hashes[l_pkg_id] != r_pkg_name_hashes[r_pkg_id]) { + return false; + } + const l_res = l_pkg_resolutions[l_pkg_id]; + const r_res = r_pkg_resolutions[r_pkg_id]; + + if (l_res.tag == .uninitialized or r_res.tag == .uninitialized) { + if (l_res.tag != r_res.tag) { + return false; + } + } else if (!l_res.eql(&r_res, l_string_buf, r_string_buf)) { + return false; + } + } + + return true; +} + pub fn hasMetaHashChanged(this: *Lockfile, print_name_version_string: bool, packages_len: usize) !bool { const previous_meta_hash = this.meta_hash; this.meta_hash = try this.generateMetaHash(print_name_version_string, packages_len); diff --git a/src/install/migration.zig b/src/install/migration.zig index ca04d48732..664df225a2 100644 --- a/src/install/migration.zig +++ b/src/install/migration.zig @@ -1085,7 +1085,7 @@ pub fn migrateNPMLockfile( .was_migrated = true, .loaded_from_binary_lockfile = false, .serializer_result = .{}, - .format = .text, + .format = .binary, }, }; } diff --git a/test/cli/install/bun-add.test.ts b/test/cli/install/bun-add.test.ts index f670bc6827..89c4a9e312 100644 --- a/test/cli/install/bun-add.test.ts +++ b/test/cli/install/bun-add.test.ts @@ -1224,7 +1224,6 @@ it("should install version tagged with `latest` by default", async () => { }); const err2 = await new Response(stderr2).text(); expect(err2).not.toContain("error:"); - expect(err2).toContain("Saved lockfile"); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ expect.stringContaining("bun install v1."), @@ -1234,8 +1233,8 @@ it("should install version tagged with `latest` by default", async () => { "1 package installed", ]); expect(await exited2).toBe(0); - expect(urls.sort()).toEqual([`${root_url}/baz`, `${root_url}/baz-0.0.3.tgz`]); - expect(requested).toBe(4); + expect(urls.sort()).toEqual([`${root_url}/baz-0.0.3.tgz`]); + expect(requested).toBe(3); expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".cache", "baz"]); expect(await file(join(package_dir, "node_modules", "baz", "package.json")).json()).toEqual({ name: "baz", @@ -1607,8 +1606,7 @@ it("should add dependency without duplication", async () => { "installed bar@0.0.2", ]); expect(await exited2).toBe(0); - expect(urls.sort()).toBeEmpty(); - expect(requested).toBe(2); + expect(requested).toBe(3); expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".cache", "bar"]); expect(await readdirSorted(join(package_dir, "node_modules", "bar"))).toEqual(["package.json"]); expect(await file(join(package_dir, "node_modules", "bar", "package.json")).json()).toEqual({ diff --git a/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap b/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap index 3793083aef..74b5db9224 100644 --- a/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap +++ b/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap @@ -159,7 +159,9 @@ exports[`text lockfile workspace sorting 1`] = ` }, "packages": { "b": ["b@workspace:packages/b", { "dependencies": { "no-deps": "1.0.0" } }], + "c": ["c@workspace:packages/c", { "dependencies": { "no-deps": "1.0.0" } }], + "no-deps": ["no-deps@1.0.0", "http://localhost:1234/no-deps/-/no-deps-1.0.0.tgz", {}, "sha512-v4w12JRjUGvfHDUP8vFDwu0gUWu04j0cv9hLb1Abf9VdaXu4XcrddYFTMVBVvmldKViGWH7jrb6xPJRF0wq6gw=="], } } @@ -196,10 +198,43 @@ exports[`text lockfile workspace sorting 2`] = ` }, "packages": { "a": ["a@workspace:packages/a", { "dependencies": { "no-deps": "1.0.0" } }], + "b": ["b@workspace:packages/b", { "dependencies": { "no-deps": "1.0.0" } }], + "c": ["c@workspace:packages/c", { "dependencies": { "no-deps": "1.0.0" } }], + "no-deps": ["no-deps@1.0.0", "http://localhost:1234/no-deps/-/no-deps-1.0.0.tgz", {}, "sha512-v4w12JRjUGvfHDUP8vFDwu0gUWu04j0cv9hLb1Abf9VdaXu4XcrddYFTMVBVvmldKViGWH7jrb6xPJRF0wq6gw=="], } } " `; + +exports[`text lockfile --frozen-lockfile 1`] = ` +"{ + "lockfileVersion": 0, + "workspaces": { + "": { + "dependencies": { + "a-dep": "^1.0.2", + "no-deps": "^1.0.0", + }, + }, + "packages/pkg1": { + "name": "package1", + "dependencies": { + "peer-deps-too": "1.0.0", + }, + }, + }, + "packages": { + "a-dep": ["a-dep@1.0.10", "http://localhost:1234/a-dep/-/a-dep-1.0.10.tgz", {}, "sha512-NeQ6Ql9jRW8V+VOiVb+PSQAYOvVoSimW+tXaR0CoJk4kM9RIk/XlAUGCsNtn5XqjlDO4hcH8NcyaL507InevEg=="], + + "no-deps": ["no-deps@1.1.0", "http://localhost:1234/no-deps/-/no-deps-1.1.0.tgz", {}, "sha512-ebG2pipYAKINcNI3YxdsiAgFvNGp2gdRwxAKN2LYBm9+YxuH/lHH2sl+GKQTuGiNfCfNZRMHUyyLPEJD6HWm7w=="], + + "package1": ["package1@workspace:packages/pkg1", { "dependencies": { "peer-deps-too": "1.0.0" } }], + + "peer-deps-too": ["peer-deps-too@1.0.0", "http://localhost:1234/peer-deps-too/-/peer-deps-too-1.0.0.tgz", { "peerDependencies": { "no-deps": "*" } }, "sha512-sBx0TKrsB8FkRN2lzkDjMuctPGEKn1TmNUBv3dJOtnZM8nd255o5ZAPRpAI2XFLHZAavBlK/e73cZNwnUxlRog=="], + } +} +" +`; diff --git a/test/cli/install/registry/bun-install-registry.test.ts b/test/cli/install/registry/bun-install-registry.test.ts index 03677d7d26..e475c49d87 100644 --- a/test/cli/install/registry/bun-install-registry.test.ts +++ b/test/cli/install/registry/bun-install-registry.test.ts @@ -1733,17 +1733,14 @@ describe("text lockfile", () => { ), ]); - let { stdout, stderr, exited } = spawn({ + let { exited } = spawn({ cmd: [bunExe(), "install", "--save-text-lockfile"], cwd: packageDir, - stdout: "pipe", - stderr: "pipe", + stdout: "ignore", + stderr: "ignore", env, }); - let out = await Bun.readableStreamToText(stdout); - let err = await Bun.readableStreamToText(stderr); - console.log({ out, err }); expect(await exited).toBe(0); expect( @@ -1761,22 +1758,86 @@ describe("text lockfile", () => { }), ); - ({ stdout, stderr, exited } = spawn({ + ({ exited } = spawn({ cmd: [bunExe(), "install"], cwd: packageDir, - stdout: "pipe", - stderr: "pipe", + stdout: "ignore", + stderr: "ignore", env, })); - out = await Bun.readableStreamToText(stdout); - err = await Bun.readableStreamToText(stderr); - console.log({ out, err }); expect(await exited).toBe(0); const lockfile = await Bun.file(join(packageDir, "bun.lock")).text(); expect(lockfile.replaceAll(/localhost:\d+/g, "localhost:1234")).toMatchSnapshot(); }); + + test("--frozen-lockfile", async () => { + await Promise.all([ + write( + join(packageDir, "package.json"), + JSON.stringify({ + name: "foo", + workspaces: ["packages/*"], + dependencies: { + "no-deps": "^1.0.0", + "a-dep": "^1.0.2", + }, + }), + ), + write( + join(packageDir, "packages", "pkg1", "package.json"), + JSON.stringify({ + name: "package1", + dependencies: { + "peer-deps-too": "1.0.0", + }, + }), + ), + ]); + + let { stderr, exited } = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile"], + cwd: packageDir, + stdout: "ignore", + stderr: "pipe", + env, + }); + + let err = await Bun.readableStreamToText(stderr); + expect(err).toContain("Saved lockfile"); + expect(err).not.toContain("error:"); + + expect(await exited).toBe(0); + + const firstLockfile = await Bun.file(join(packageDir, "bun.lock")).text(); + + expect(firstLockfile.replace(/localhost:\d+/g, "localhost:1234")).toMatchSnapshot(); + + await rm(join(packageDir, "node_modules"), { recursive: true, force: true }); + + ({ stderr, exited } = spawn({ + cmd: [bunExe(), "install", "--frozen-lockfile"], + cwd: packageDir, + stdout: "ignore", + stderr: "pipe", + env, + })); + + err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("Saved lockfile"); + expect(err).not.toContain("error:"); + expect(await exited).toBe(0); + + expect(await readdirSorted(join(packageDir, "node_modules"))).toEqual([ + "a-dep", + "no-deps", + "package1", + "peer-deps-too", + ]); + + expect(await Bun.file(join(packageDir, "bun.lock")).text()).toBe(firstLockfile); + }); }); describe("optionalDependencies", () => { diff --git a/test/harness.ts b/test/harness.ts index 27a2bd0911..dd70b7bbed 100644 --- a/test/harness.ts +++ b/test/harness.ts @@ -548,6 +548,10 @@ Received ${JSON.stringify({ name: onDisk.name, version: onDisk.version })}`, case "npm": const name = dep.is_alias ? dep.npm.name : dep.name; if (!Bun.deepMatch({ name, version: pkg.resolution.value }, resolved)) { + if (dep.literal === "*") { + // allow any version, just needs to be resolvable + continue; + } if (dep.behavior.peer && dep.npm) { // allow peer dependencies to not match exactly, but still satisfy if (Bun.semver.satisfies(pkg.resolution.value, dep.npm.version)) continue; @@ -587,6 +591,10 @@ Received ${JSON.stringify({ name: onDisk.name, version: onDisk.version })}`, case "npm": const name = dep.is_alias ? dep.npm.name : dep.name; if (!Bun.deepMatch({ name, version: pkg.resolution.value }, resolved)) { + if (dep.literal === "*") { + // allow any version, just needs to be resolvable + continue; + } // workspaces don't need a version if (treePkg.resolution.tag === "workspace" && !resolved.version) continue; if (dep.behavior.peer && dep.npm) { diff --git a/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap b/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap index da10c802c8..34dee403a4 100644 --- a/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap @@ -20772,7 +20772,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 374, }, "array-includes": { - "id": 806, + "id": 445, "package_id": 384, }, "array-union": { @@ -20792,7 +20792,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 382, }, "array.prototype.flatmap": { - "id": 808, + "id": 448, "package_id": 380, }, "array.prototype.toreversed": { @@ -21068,11 +21068,11 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 316, }, "es-errors": { - "id": 858, + "id": 690, "package_id": 312, }, "es-iterator-helpers": { - "id": 812, + "id": 740, "package_id": 409, }, "es-object-atoms": { @@ -21084,7 +21084,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 369, }, "es-shim-unscopables": { - "id": 860, + "id": 692, "package_id": 381, }, "es-to-primitive": { @@ -21120,7 +21120,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 302, }, "eslint-module-utils": { - "id": 452, + "id": 438, "package_id": 376, }, "eslint-plugin-import": { @@ -21164,7 +21164,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 279, }, "estraverse": { - "id": 432, + "id": 415, "package_id": 166, }, "esutils": { @@ -21248,7 +21248,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 51, }, "function-bind": { - "id": 761, + "id": 55, "package_id": 21, }, "function.prototype.name": { @@ -21412,7 +21412,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 329, }, "is-core-module": { - "id": 454, + "id": 675, "package_id": 19, }, "is-data-view": { @@ -21556,7 +21556,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 174, }, "jsx-ast-utils": { - "id": 814, + "id": 742, "package_id": 408, }, "keyv": { @@ -21680,11 +21680,11 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 355, }, "object.entries": { - "id": 816, + "id": 745, "package_id": 405, }, "object.fromentries": { - "id": 817, + "id": 457, "package_id": 375, }, "object.groupby": { @@ -21696,7 +21696,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 434, }, "object.values": { - "id": 819, + "id": 459, "package_id": 310, }, "once": { @@ -21924,7 +21924,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "package_id": 112, }, "semver": { - "id": 822, + "id": 460, "package_id": 309, }, "set-function-length": { @@ -22260,29 +22260,14 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "dependencies": { - "@types/node": { - "id": 863, - "package_id": 183, + "debug": { + "id": 674, + "package_id": 377, }, }, "depth": 1, "id": 3, - "path": "node_modules/@types/ws/node_modules", - }, - { - "dependencies": { - "doctrine": { - "id": 811, - "package_id": 379, - }, - "resolve": { - "id": 821, - "package_id": 431, - }, - }, - "depth": 1, - "id": 4, - "path": "node_modules/eslint-plugin-react/node_modules", + "path": "node_modules/eslint-import-resolver-node/node_modules", }, { "dependencies": { @@ -22296,19 +22281,23 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 4, "path": "node_modules/eslint-plugin-import/node_modules", }, { "dependencies": { - "debug": { - "id": 674, - "package_id": 377, + "doctrine": { + "id": 811, + "package_id": 379, + }, + "resolve": { + "id": 821, + "package_id": 431, }, }, "depth": 1, - "id": 6, - "path": "node_modules/eslint-import-resolver-node/node_modules", + "id": 5, + "path": "node_modules/eslint-plugin-react/node_modules", }, { "dependencies": { @@ -22322,7 +22311,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 6, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22333,7 +22322,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 7, "path": "node_modules/chokidar/node_modules", }, { @@ -22344,7 +22333,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 8, "path": "node_modules/fast-glob/node_modules", }, { @@ -22355,20 +22344,9 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 9, "path": "node_modules/postcss-load-config/node_modules", }, - { - "dependencies": { - "debug": { - "id": 672, - "package_id": 377, - }, - }, - "depth": 1, - "id": 11, - "path": "node_modules/eslint-module-utils/node_modules", - }, { "dependencies": { "minimatch": { @@ -22377,7 +22355,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 10, "path": "node_modules/glob/node_modules", }, { @@ -22392,9 +22370,20 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 13, + "id": 11, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, + { + "dependencies": { + "debug": { + "id": 672, + "package_id": 377, + }, + }, + "depth": 1, + "id": 12, + "path": "node_modules/eslint-module-utils/node_modules", + }, { "dependencies": { "lru-cache": { @@ -22403,7 +22392,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 14, + "id": 13, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22414,7 +22403,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 15, + "id": 14, "path": "node_modules/rimraf/node_modules", }, { @@ -22425,7 +22414,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 16, + "id": 15, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22436,9 +22425,20 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 17, + "id": 16, "path": "node_modules/path-scurry/node_modules", }, + { + "dependencies": { + "brace-expansion": { + "id": 720, + "package_id": 70, + }, + }, + "depth": 2, + "id": 17, + "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", + }, { "dependencies": { "lru-cache": { @@ -22450,28 +22450,6 @@ exports[`ssr works for 100-ish requests 1`] = ` "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, - { - "dependencies": { - "brace-expansion": { - "id": 720, - "package_id": 70, - }, - }, - "depth": 2, - "id": 19, - "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", - }, - { - "dependencies": { - "@types/node": { - "id": 254, - "package_id": 183, - }, - }, - "depth": 1, - "id": 20, - "path": "node_modules/@types/yauzl/node_modules", - }, { "dependencies": { "emoji-regex": { @@ -22480,7 +22458,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 19, "path": "node_modules/string-width/node_modules", }, { @@ -22499,7 +22477,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 20, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22510,7 +22488,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 23, + "id": 21, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22521,7 +22499,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 24, + "id": 22, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22532,7 +22510,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 23, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22543,7 +22521,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 26, + "id": 24, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22562,7 +22540,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 27, + "id": 25, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22573,7 +22551,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 3, - "id": 28, + "id": 26, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22584,7 +22562,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 3, - "id": 29, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22595,7 +22573,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 4, - "id": 30, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], diff --git a/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap b/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap index 7b40a27d78..e6a7d3b26d 100644 --- a/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap @@ -20772,7 +20772,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 374, }, "array-includes": { - "id": 806, + "id": 445, "package_id": 384, }, "array-union": { @@ -20792,7 +20792,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 382, }, "array.prototype.flatmap": { - "id": 808, + "id": 448, "package_id": 380, }, "array.prototype.toreversed": { @@ -21068,11 +21068,11 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 316, }, "es-errors": { - "id": 858, + "id": 690, "package_id": 312, }, "es-iterator-helpers": { - "id": 812, + "id": 740, "package_id": 409, }, "es-object-atoms": { @@ -21084,7 +21084,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 369, }, "es-shim-unscopables": { - "id": 860, + "id": 692, "package_id": 381, }, "es-to-primitive": { @@ -21120,7 +21120,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 302, }, "eslint-module-utils": { - "id": 452, + "id": 438, "package_id": 376, }, "eslint-plugin-import": { @@ -21164,7 +21164,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 279, }, "estraverse": { - "id": 432, + "id": 415, "package_id": 166, }, "esutils": { @@ -21248,7 +21248,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 51, }, "function-bind": { - "id": 761, + "id": 55, "package_id": 21, }, "function.prototype.name": { @@ -21412,7 +21412,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 329, }, "is-core-module": { - "id": 454, + "id": 675, "package_id": 19, }, "is-data-view": { @@ -21556,7 +21556,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 174, }, "jsx-ast-utils": { - "id": 814, + "id": 742, "package_id": 408, }, "keyv": { @@ -21680,11 +21680,11 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 355, }, "object.entries": { - "id": 816, + "id": 745, "package_id": 405, }, "object.fromentries": { - "id": 817, + "id": 457, "package_id": 375, }, "object.groupby": { @@ -21696,7 +21696,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 434, }, "object.values": { - "id": 819, + "id": 459, "package_id": 310, }, "once": { @@ -21924,7 +21924,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "package_id": 112, }, "semver": { - "id": 822, + "id": 460, "package_id": 309, }, "set-function-length": { @@ -22260,29 +22260,14 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "dependencies": { - "@types/node": { - "id": 863, - "package_id": 183, + "debug": { + "id": 674, + "package_id": 377, }, }, "depth": 1, "id": 3, - "path": "node_modules/@types/ws/node_modules", - }, - { - "dependencies": { - "doctrine": { - "id": 811, - "package_id": 379, - }, - "resolve": { - "id": 821, - "package_id": 431, - }, - }, - "depth": 1, - "id": 4, - "path": "node_modules/eslint-plugin-react/node_modules", + "path": "node_modules/eslint-import-resolver-node/node_modules", }, { "dependencies": { @@ -22296,19 +22281,23 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 4, "path": "node_modules/eslint-plugin-import/node_modules", }, { "dependencies": { - "debug": { - "id": 674, - "package_id": 377, + "doctrine": { + "id": 811, + "package_id": 379, + }, + "resolve": { + "id": 821, + "package_id": 431, }, }, "depth": 1, - "id": 6, - "path": "node_modules/eslint-import-resolver-node/node_modules", + "id": 5, + "path": "node_modules/eslint-plugin-react/node_modules", }, { "dependencies": { @@ -22322,7 +22311,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 6, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22333,7 +22322,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 7, "path": "node_modules/chokidar/node_modules", }, { @@ -22344,7 +22333,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 8, "path": "node_modules/fast-glob/node_modules", }, { @@ -22355,20 +22344,9 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 9, "path": "node_modules/postcss-load-config/node_modules", }, - { - "dependencies": { - "debug": { - "id": 672, - "package_id": 377, - }, - }, - "depth": 1, - "id": 11, - "path": "node_modules/eslint-module-utils/node_modules", - }, { "dependencies": { "minimatch": { @@ -22377,7 +22355,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 10, "path": "node_modules/glob/node_modules", }, { @@ -22392,9 +22370,20 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 13, + "id": 11, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, + { + "dependencies": { + "debug": { + "id": 672, + "package_id": 377, + }, + }, + "depth": 1, + "id": 12, + "path": "node_modules/eslint-module-utils/node_modules", + }, { "dependencies": { "lru-cache": { @@ -22403,7 +22392,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 14, + "id": 13, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22414,7 +22403,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 15, + "id": 14, "path": "node_modules/rimraf/node_modules", }, { @@ -22425,7 +22414,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 16, + "id": 15, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22436,9 +22425,20 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 17, + "id": 16, "path": "node_modules/path-scurry/node_modules", }, + { + "dependencies": { + "brace-expansion": { + "id": 720, + "package_id": 70, + }, + }, + "depth": 2, + "id": 17, + "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", + }, { "dependencies": { "lru-cache": { @@ -22450,28 +22450,6 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, - { - "dependencies": { - "brace-expansion": { - "id": 720, - "package_id": 70, - }, - }, - "depth": 2, - "id": 19, - "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", - }, - { - "dependencies": { - "@types/node": { - "id": 254, - "package_id": 183, - }, - }, - "depth": 1, - "id": 20, - "path": "node_modules/@types/yauzl/node_modules", - }, { "dependencies": { "emoji-regex": { @@ -22480,7 +22458,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 19, "path": "node_modules/string-width/node_modules", }, { @@ -22499,7 +22477,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 20, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22510,7 +22488,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 23, + "id": 21, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22521,7 +22499,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 24, + "id": 22, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22532,7 +22510,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 23, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22543,7 +22521,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 26, + "id": 24, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22562,7 +22540,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 27, + "id": 25, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22573,7 +22551,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 3, - "id": 28, + "id": 26, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22584,7 +22562,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 3, - "id": 29, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22595,7 +22573,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 4, - "id": 30, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], diff --git a/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap b/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap index c23871f444..4f39ea6a16 100644 --- a/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap @@ -20772,7 +20772,7 @@ exports[`next build works: bun 1`] = ` "package_id": 374, }, "array-includes": { - "id": 806, + "id": 445, "package_id": 384, }, "array-union": { @@ -20792,7 +20792,7 @@ exports[`next build works: bun 1`] = ` "package_id": 382, }, "array.prototype.flatmap": { - "id": 808, + "id": 448, "package_id": 380, }, "array.prototype.toreversed": { @@ -21068,11 +21068,11 @@ exports[`next build works: bun 1`] = ` "package_id": 316, }, "es-errors": { - "id": 858, + "id": 690, "package_id": 312, }, "es-iterator-helpers": { - "id": 812, + "id": 740, "package_id": 409, }, "es-object-atoms": { @@ -21084,7 +21084,7 @@ exports[`next build works: bun 1`] = ` "package_id": 369, }, "es-shim-unscopables": { - "id": 860, + "id": 692, "package_id": 381, }, "es-to-primitive": { @@ -21120,7 +21120,7 @@ exports[`next build works: bun 1`] = ` "package_id": 302, }, "eslint-module-utils": { - "id": 452, + "id": 438, "package_id": 376, }, "eslint-plugin-import": { @@ -21164,7 +21164,7 @@ exports[`next build works: bun 1`] = ` "package_id": 279, }, "estraverse": { - "id": 432, + "id": 415, "package_id": 166, }, "esutils": { @@ -21248,7 +21248,7 @@ exports[`next build works: bun 1`] = ` "package_id": 51, }, "function-bind": { - "id": 761, + "id": 55, "package_id": 21, }, "function.prototype.name": { @@ -21412,7 +21412,7 @@ exports[`next build works: bun 1`] = ` "package_id": 329, }, "is-core-module": { - "id": 454, + "id": 675, "package_id": 19, }, "is-data-view": { @@ -21556,7 +21556,7 @@ exports[`next build works: bun 1`] = ` "package_id": 174, }, "jsx-ast-utils": { - "id": 814, + "id": 742, "package_id": 408, }, "keyv": { @@ -21680,11 +21680,11 @@ exports[`next build works: bun 1`] = ` "package_id": 355, }, "object.entries": { - "id": 816, + "id": 745, "package_id": 405, }, "object.fromentries": { - "id": 817, + "id": 457, "package_id": 375, }, "object.groupby": { @@ -21696,7 +21696,7 @@ exports[`next build works: bun 1`] = ` "package_id": 434, }, "object.values": { - "id": 819, + "id": 459, "package_id": 310, }, "once": { @@ -21924,7 +21924,7 @@ exports[`next build works: bun 1`] = ` "package_id": 112, }, "semver": { - "id": 822, + "id": 460, "package_id": 309, }, "set-function-length": { @@ -22260,29 +22260,14 @@ exports[`next build works: bun 1`] = ` }, { "dependencies": { - "@types/node": { - "id": 863, - "package_id": 183, + "debug": { + "id": 674, + "package_id": 377, }, }, "depth": 1, "id": 3, - "path": "node_modules/@types/ws/node_modules", - }, - { - "dependencies": { - "doctrine": { - "id": 811, - "package_id": 379, - }, - "resolve": { - "id": 821, - "package_id": 431, - }, - }, - "depth": 1, - "id": 4, - "path": "node_modules/eslint-plugin-react/node_modules", + "path": "node_modules/eslint-import-resolver-node/node_modules", }, { "dependencies": { @@ -22296,19 +22281,23 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 4, "path": "node_modules/eslint-plugin-import/node_modules", }, { "dependencies": { - "debug": { - "id": 674, - "package_id": 377, + "doctrine": { + "id": 811, + "package_id": 379, + }, + "resolve": { + "id": 821, + "package_id": 431, }, }, "depth": 1, - "id": 6, - "path": "node_modules/eslint-import-resolver-node/node_modules", + "id": 5, + "path": "node_modules/eslint-plugin-react/node_modules", }, { "dependencies": { @@ -22322,7 +22311,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 6, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22333,7 +22322,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 7, "path": "node_modules/chokidar/node_modules", }, { @@ -22344,7 +22333,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 8, "path": "node_modules/fast-glob/node_modules", }, { @@ -22355,20 +22344,9 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 9, "path": "node_modules/postcss-load-config/node_modules", }, - { - "dependencies": { - "debug": { - "id": 672, - "package_id": 377, - }, - }, - "depth": 1, - "id": 11, - "path": "node_modules/eslint-module-utils/node_modules", - }, { "dependencies": { "minimatch": { @@ -22377,7 +22355,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 10, "path": "node_modules/glob/node_modules", }, { @@ -22392,9 +22370,20 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 13, + "id": 11, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, + { + "dependencies": { + "debug": { + "id": 672, + "package_id": 377, + }, + }, + "depth": 1, + "id": 12, + "path": "node_modules/eslint-module-utils/node_modules", + }, { "dependencies": { "lru-cache": { @@ -22403,7 +22392,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 14, + "id": 13, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22414,7 +22403,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 15, + "id": 14, "path": "node_modules/rimraf/node_modules", }, { @@ -22425,7 +22414,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 16, + "id": 15, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22436,9 +22425,20 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 17, + "id": 16, "path": "node_modules/path-scurry/node_modules", }, + { + "dependencies": { + "brace-expansion": { + "id": 720, + "package_id": 70, + }, + }, + "depth": 2, + "id": 17, + "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", + }, { "dependencies": { "lru-cache": { @@ -22450,28 +22450,6 @@ exports[`next build works: bun 1`] = ` "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, - { - "dependencies": { - "brace-expansion": { - "id": 720, - "package_id": 70, - }, - }, - "depth": 2, - "id": 19, - "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", - }, - { - "dependencies": { - "@types/node": { - "id": 254, - "package_id": 183, - }, - }, - "depth": 1, - "id": 20, - "path": "node_modules/@types/yauzl/node_modules", - }, { "dependencies": { "emoji-regex": { @@ -22480,7 +22458,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 19, "path": "node_modules/string-width/node_modules", }, { @@ -22499,7 +22477,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 20, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22510,7 +22488,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 23, + "id": 21, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22521,7 +22499,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 24, + "id": 22, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22532,7 +22510,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 23, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22543,7 +22521,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 26, + "id": 24, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22562,7 +22540,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 27, + "id": 25, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22573,7 +22551,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 3, - "id": 28, + "id": 26, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22584,7 +22562,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 3, - "id": 29, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22595,7 +22573,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 4, - "id": 30, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], @@ -43376,7 +43354,7 @@ exports[`next build works: node 1`] = ` "package_id": 374, }, "array-includes": { - "id": 806, + "id": 445, "package_id": 384, }, "array-union": { @@ -43396,7 +43374,7 @@ exports[`next build works: node 1`] = ` "package_id": 382, }, "array.prototype.flatmap": { - "id": 808, + "id": 448, "package_id": 380, }, "array.prototype.toreversed": { @@ -43672,11 +43650,11 @@ exports[`next build works: node 1`] = ` "package_id": 316, }, "es-errors": { - "id": 858, + "id": 690, "package_id": 312, }, "es-iterator-helpers": { - "id": 812, + "id": 740, "package_id": 409, }, "es-object-atoms": { @@ -43688,7 +43666,7 @@ exports[`next build works: node 1`] = ` "package_id": 369, }, "es-shim-unscopables": { - "id": 860, + "id": 692, "package_id": 381, }, "es-to-primitive": { @@ -43724,7 +43702,7 @@ exports[`next build works: node 1`] = ` "package_id": 302, }, "eslint-module-utils": { - "id": 452, + "id": 438, "package_id": 376, }, "eslint-plugin-import": { @@ -43768,7 +43746,7 @@ exports[`next build works: node 1`] = ` "package_id": 279, }, "estraverse": { - "id": 432, + "id": 415, "package_id": 166, }, "esutils": { @@ -43852,7 +43830,7 @@ exports[`next build works: node 1`] = ` "package_id": 51, }, "function-bind": { - "id": 761, + "id": 55, "package_id": 21, }, "function.prototype.name": { @@ -44016,7 +43994,7 @@ exports[`next build works: node 1`] = ` "package_id": 329, }, "is-core-module": { - "id": 454, + "id": 675, "package_id": 19, }, "is-data-view": { @@ -44160,7 +44138,7 @@ exports[`next build works: node 1`] = ` "package_id": 174, }, "jsx-ast-utils": { - "id": 814, + "id": 742, "package_id": 408, }, "keyv": { @@ -44284,11 +44262,11 @@ exports[`next build works: node 1`] = ` "package_id": 355, }, "object.entries": { - "id": 816, + "id": 745, "package_id": 405, }, "object.fromentries": { - "id": 817, + "id": 457, "package_id": 375, }, "object.groupby": { @@ -44300,7 +44278,7 @@ exports[`next build works: node 1`] = ` "package_id": 434, }, "object.values": { - "id": 819, + "id": 459, "package_id": 310, }, "once": { @@ -44528,7 +44506,7 @@ exports[`next build works: node 1`] = ` "package_id": 112, }, "semver": { - "id": 822, + "id": 460, "package_id": 309, }, "set-function-length": { @@ -44864,29 +44842,14 @@ exports[`next build works: node 1`] = ` }, { "dependencies": { - "@types/node": { - "id": 863, - "package_id": 183, + "debug": { + "id": 674, + "package_id": 377, }, }, "depth": 1, "id": 3, - "path": "node_modules/@types/ws/node_modules", - }, - { - "dependencies": { - "doctrine": { - "id": 811, - "package_id": 379, - }, - "resolve": { - "id": 821, - "package_id": 431, - }, - }, - "depth": 1, - "id": 4, - "path": "node_modules/eslint-plugin-react/node_modules", + "path": "node_modules/eslint-import-resolver-node/node_modules", }, { "dependencies": { @@ -44900,19 +44863,23 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 4, "path": "node_modules/eslint-plugin-import/node_modules", }, { "dependencies": { - "debug": { - "id": 674, - "package_id": 377, + "doctrine": { + "id": 811, + "package_id": 379, + }, + "resolve": { + "id": 821, + "package_id": 431, }, }, "depth": 1, - "id": 6, - "path": "node_modules/eslint-import-resolver-node/node_modules", + "id": 5, + "path": "node_modules/eslint-plugin-react/node_modules", }, { "dependencies": { @@ -44926,7 +44893,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 6, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -44937,7 +44904,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 7, "path": "node_modules/chokidar/node_modules", }, { @@ -44948,7 +44915,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 8, "path": "node_modules/fast-glob/node_modules", }, { @@ -44959,20 +44926,9 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 9, "path": "node_modules/postcss-load-config/node_modules", }, - { - "dependencies": { - "debug": { - "id": 672, - "package_id": 377, - }, - }, - "depth": 1, - "id": 11, - "path": "node_modules/eslint-module-utils/node_modules", - }, { "dependencies": { "minimatch": { @@ -44981,7 +44937,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 10, "path": "node_modules/glob/node_modules", }, { @@ -44996,9 +44952,20 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 13, + "id": 11, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, + { + "dependencies": { + "debug": { + "id": 672, + "package_id": 377, + }, + }, + "depth": 1, + "id": 12, + "path": "node_modules/eslint-module-utils/node_modules", + }, { "dependencies": { "lru-cache": { @@ -45007,7 +44974,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 14, + "id": 13, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -45018,7 +44985,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 15, + "id": 14, "path": "node_modules/rimraf/node_modules", }, { @@ -45029,7 +44996,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 16, + "id": 15, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -45040,9 +45007,20 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 17, + "id": 16, "path": "node_modules/path-scurry/node_modules", }, + { + "dependencies": { + "brace-expansion": { + "id": 720, + "package_id": 70, + }, + }, + "depth": 2, + "id": 17, + "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", + }, { "dependencies": { "lru-cache": { @@ -45054,28 +45032,6 @@ exports[`next build works: node 1`] = ` "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, - { - "dependencies": { - "brace-expansion": { - "id": 720, - "package_id": 70, - }, - }, - "depth": 2, - "id": 19, - "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", - }, - { - "dependencies": { - "@types/node": { - "id": 254, - "package_id": 183, - }, - }, - "depth": 1, - "id": 20, - "path": "node_modules/@types/yauzl/node_modules", - }, { "dependencies": { "emoji-regex": { @@ -45084,7 +45040,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 19, "path": "node_modules/string-width/node_modules", }, { @@ -45103,7 +45059,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 20, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -45114,7 +45070,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 23, + "id": 21, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -45125,7 +45081,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 24, + "id": 22, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -45136,7 +45092,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 23, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -45147,7 +45103,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 26, + "id": 24, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -45166,7 +45122,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 27, + "id": 25, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -45177,7 +45133,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 3, - "id": 28, + "id": 26, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -45188,7 +45144,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 3, - "id": 29, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -45199,7 +45155,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 4, - "id": 30, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], From ebc33327d34140499d3256ca2212a1441688fa26 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 14 Dec 2024 01:56:55 -0800 Subject: [PATCH 006/125] Delete incorrect debug assertion --- src/install/semver.zig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/install/semver.zig b/src/install/semver.zig index 84c7fdba0d..8cd6cb0bc4 100644 --- a/src/install/semver.zig +++ b/src/install/semver.zig @@ -1443,9 +1443,7 @@ pub const Version = extern struct { .none => {}, .pre => { result.tag.pre = sliced_string.sub(input[start..i]).external(); - if (comptime Environment.isDebug) { - assert(!strings.containsChar(result.tag.pre.slice(sliced_string.buf), '-')); - } + state = State.none; }, .build => { From 0d97c8157f39b92cf9872fd933ea0afa9d2ae90b Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 14 Dec 2024 01:57:08 -0800 Subject: [PATCH 007/125] Add debugger to entitlements plist --- entitlements.debug.plist | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/entitlements.debug.plist b/entitlements.debug.plist index c5acc7444a..ab2dcf4b47 100644 --- a/entitlements.debug.plist +++ b/entitlements.debug.plist @@ -14,5 +14,7 @@ com.apple.security.get-task-allow + com.apple.security.cs.debugger + - \ No newline at end of file + From 5326a998c7492c09f4fa710187428ba83c981fe8 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 14 Dec 2024 04:48:57 -0800 Subject: [PATCH 008/125] Don't open node_modules 1,618 times (#15762) --- src/cli/pm_trusted_command.zig | 8 +- src/install/install.zig | 153 ++++++++++++++++++++++++--------- src/install/lockfile.zig | 8 +- 3 files changed, 120 insertions(+), 49 deletions(-) diff --git a/src/cli/pm_trusted_command.zig b/src/cli/pm_trusted_command.zig index a26f46a4f0..1341a9aa47 100644 --- a/src/cli/pm_trusted_command.zig +++ b/src/cli/pm_trusted_command.zig @@ -97,11 +97,11 @@ pub const UntrustedCommand = struct { const package_id = pm.lockfile.buffers.resolutions.items[dep_id]; const resolution = &resolutions[package_id]; var package_scripts = scripts[package_id]; - + var not_lazy: PackageManager.LazyPackageDestinationDir = .{ .dir = node_modules_dir }; const maybe_scripts_list = package_scripts.getList( pm.log, pm.lockfile, - node_modules_dir, + ¬_lazy, abs_node_modules_path.items, alias, resolution, @@ -262,11 +262,11 @@ pub const TrustCommand = struct { } const resolution = &resolutions[package_id]; var package_scripts = scripts[package_id]; - + var not_lazy = PackageManager.LazyPackageDestinationDir{ .dir = node_modules_dir }; const maybe_scripts_list = package_scripts.getList( pm.log, pm.lockfile, - node_modules_dir, + ¬_lazy, abs_node_modules_path.items, alias, resolution, diff --git a/src/install/install.zig b/src/install/install.zig index bcc3d8cb50..59d8ec6541 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -1210,12 +1210,7 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { const package_json_path: [:0]u8 = this.destination_dir_subpath_buf[0 .. this.destination_dir_subpath.len + std.fs.path.sep_str.len + "package.json".len :0]; defer this.destination_dir_subpath_buf[this.destination_dir_subpath.len] = 0; - var destination_dir = this.node_modules.openDir(root_node_modules_dir) catch return null; - defer { - if (std.fs.cwd().fd != destination_dir.fd) destination_dir.close(); - } - - var package_json_file = File.openat(destination_dir, package_json_path, bun.O.RDONLY, 0).unwrap() catch return null; + var package_json_file = this.node_modules.openPackageJSON(root_node_modules_dir, package_json_path) catch return null; defer package_json_file.close(); // Heuristic: most package.jsons will be less than 2048 bytes. @@ -1339,6 +1334,9 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { .valid = true, .update_lockfile_pointers = true, }; + } else if (bin.isUnset()) { + // It's not unset. There's no bin. + bin.unset = 0; } return .{ @@ -12081,6 +12079,40 @@ pub const PackageManager = struct { } } + pub const LazyPackageDestinationDir = union(enum) { + dir: std.fs.Dir, + node_modules_path: struct { + node_modules: *NodeModulesFolder, + root_node_modules_dir: std.fs.Dir, + }, + closed: void, + + pub fn getDir(this: *LazyPackageDestinationDir) !std.fs.Dir { + return switch (this.*) { + .dir => |dir| dir, + .node_modules_path => |lazy| brk: { + const dir = try lazy.node_modules.openDir(lazy.root_node_modules_dir); + this.* = .{ .dir = dir }; + break :brk dir; + }, + .closed => @panic("LazyPackageDestinationDir is closed! This should never happen. Why did this happen?! It's not your fault. Its our fault. We're sorry."), + }; + } + + pub fn close(this: *LazyPackageDestinationDir) void { + switch (this.*) { + .dir => { + if (this.dir.fd != std.fs.cwd().fd) { + this.dir.close(); + } + }, + .node_modules_path, .closed => {}, + } + + this.* = .{ .closed = {} }; + } + }; + pub const NodeModulesFolder = struct { tree_id: Lockfile.Tree.Id = 0, path: std.ArrayList(u8) = std.ArrayList(u8).init(bun.default_allocator), @@ -12089,9 +12121,40 @@ pub const PackageManager = struct { this.path.clearAndFree(); } + noinline fn openPackageJSONFileWithoutOpeningDirectories(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, package_json_path: [:0]const u8) bun.sys.Maybe(bun.sys.File) { + var path_buf: bun.PathBuffer = undefined; + const parts: [2][]const u8 = .{ this.path.items, package_json_path }; + return bun.sys.File.openat(bun.toFD(root_node_modules_dir), bun.path.joinZBuf(&path_buf, &parts, .auto), bun.O.RDONLY, 0); + } + + pub fn openPackageJSON(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, package_json_path: [:0]const u8) !bun.sys.File { + if (this.path.items.len + package_json_path.len * 2 < bun.MAX_PATH_BYTES) { + // If we do not run the risk of ENAMETOOLONG, then let's just avoid opening the extra directories altogether. + switch (this.openPackageJSONFileWithoutOpeningDirectories(root_node_modules_dir, package_json_path)) { + .err => |e| { + switch (e.getErrno()) { + // Just incase we're wrong, let's try the fallback + .PERM, .ACCES, .INVAL, .NAMETOOLONG => { + // Use fallback + }, + else => return e.toZigErr(), + } + }, + .result => |file| return file, + } + } + + const dir = try this.openDir(root_node_modules_dir); + defer { + _ = bun.sys.close(bun.toFD(dir)); + } + + return try bun.sys.File.openat(bun.toFD(dir), package_json_path, bun.O.RDONLY, 0).unwrap(); + } + pub fn openDir(this: *const NodeModulesFolder, root: std.fs.Dir) !std.fs.Dir { if (comptime Environment.isPosix) { - return root.openDir(this.path.items, .{ .iterate = true, .access_sub_paths = true }); + return (try bun.sys.openat(bun.toFD(root), &try std.posix.toPosixPath(this.path.items), bun.O.DIRECTORY, 0).unwrap()).asDir(); } return (try bun.sys.openDirAtWindowsA(bun.toFD(root), this.path.items, .{ @@ -12194,7 +12257,7 @@ pub const PackageManager = struct { pub fn incrementTreeInstallCount( this: *PackageInstaller, tree_id: Lockfile.Tree.Id, - maybe_destination_dir: ?std.fs.Dir, + maybe_destination_dir: ?*LazyPackageDestinationDir, comptime should_install_packages: bool, comptime log_level: Options.LogLevel, ) void { @@ -12221,21 +12284,23 @@ pub const PackageManager = struct { this.completed_trees.set(tree_id); - if (maybe_destination_dir orelse (this.node_modules.makeAndOpenDir(this.root_node_modules_folder) catch null)) |_destination_dir| { - var destination_dir = _destination_dir; - defer { - if (maybe_destination_dir == null) { - destination_dir.close(); + if (maybe_destination_dir) |maybe| { + if (maybe.getDir() catch null) |_destination_dir| { + var destination_dir = _destination_dir; + defer { + if (maybe_destination_dir == null) { + destination_dir.close(); + } } - } - this.seen_bin_links.clearRetainingCapacity(); + this.seen_bin_links.clearRetainingCapacity(); - if (tree.binaries.count() > 0) { - var link_target_buf: bun.PathBuffer = undefined; - var link_dest_buf: bun.PathBuffer = undefined; - var link_rel_buf: bun.PathBuffer = undefined; - this.linkTreeBins(tree, tree_id, destination_dir, &link_target_buf, &link_dest_buf, &link_rel_buf, log_level); + if (tree.binaries.count() > 0) { + var link_target_buf: bun.PathBuffer = undefined; + var link_dest_buf: bun.PathBuffer = undefined; + var link_rel_buf: bun.PathBuffer = undefined; + this.linkTreeBins(tree, tree_id, destination_dir, &link_target_buf, &link_dest_buf, &link_rel_buf, log_level); + } } } @@ -12635,7 +12700,7 @@ pub const PackageManager = struct { alias: string, package_id: PackageID, resolution_tag: Resolution.Tag, - node_modules_folder: std.fs.Dir, + node_modules_folder: *LazyPackageDestinationDir, comptime log_level: Options.LogLevel, ) usize { if (comptime Environment.allow_assert) { @@ -13083,6 +13148,8 @@ pub const PackageManager = struct { if (std.fs.cwd().fd != destination_dir.fd) destination_dir.close(); } + var lazy_package_dir: LazyPackageDestinationDir = .{ .dir = destination_dir }; + const install_result = switch (resolution.tag) { .symlink, .workspace => installer.installFromLink(this.skip_delete, destination_dir), else => result: { @@ -13146,7 +13213,7 @@ pub const PackageManager = struct { if (this.enqueueLifecycleScripts( alias.slice(this.lockfile.buffers.string_bytes.items), log_level, - destination_dir, + &lazy_package_dir, package_id, dep.behavior.optional, resolution, @@ -13174,7 +13241,7 @@ pub const PackageManager = struct { alias.slice(this.lockfile.buffers.string_bytes.items), package_id, resolution.tag, - destination_dir, + &lazy_package_dir, log_level, ); if (count > 0) { @@ -13192,7 +13259,7 @@ pub const PackageManager = struct { }, } - if (!pkg_has_patch) this.incrementTreeInstallCount(this.current_tree_id, destination_dir, !is_pending_package_install, log_level); + if (!pkg_has_patch) this.incrementTreeInstallCount(this.current_tree_id, &lazy_package_dir, !is_pending_package_install, log_level); }, .fail => |cause| { if (comptime Environment.allow_assert) { @@ -13201,7 +13268,7 @@ pub const PackageManager = struct { // even if the package failed to install, we still need to increment the install // counter for this tree - if (!pkg_has_patch) this.incrementTreeInstallCount(this.current_tree_id, destination_dir, !is_pending_package_install, log_level); + if (!pkg_has_patch) this.incrementTreeInstallCount(this.current_tree_id, &lazy_package_dir, !is_pending_package_install, log_level); if (cause.err == error.DanglingSymlink) { Output.prettyErrorln( @@ -13220,7 +13287,15 @@ pub const PackageManager = struct { }; if (!Singleton.node_modules_is_ok) { if (!Environment.isWindows) { - const stat = bun.sys.fstat(bun.toFD(destination_dir)).unwrap() catch |err| { + const stat = bun.sys.fstat(bun.toFD(lazy_package_dir.getDir() catch |err| { + Output.err("EACCES", "Permission denied while installing {s}", .{ + this.names[package_id].slice(this.lockfile.buffers.string_bytes.items), + }); + if (Environment.isDebug) { + Output.err(err, "Failed to stat node_modules", .{}); + } + Global.exit(1); + })).unwrap() catch |err| { Output.err("EACCES", "Permission denied while installing {s}", .{ this.names[package_id].slice(this.lockfile.buffers.string_bytes.items), }); @@ -13274,23 +13349,18 @@ pub const PackageManager = struct { this.trees[this.current_tree_id].binaries.add(dependency_id) catch bun.outOfMemory(); } - var destination_dir = this.node_modules.makeAndOpenDir(this.root_node_modules_folder) catch |err| { - if (log_level != .silent) { - Output.err(err, "Failed to open node_modules folder for {s} in {s}", .{ - pkg_name.slice(this.lockfile.buffers.string_bytes.items), - bun.fmt.fmtPath(u8, this.node_modules.path.items, .{}), - }); - } - this.summary.fail += 1; - if (!pkg_has_patch) this.incrementTreeInstallCount(this.current_tree_id, null, !is_pending_package_install, log_level); - return; + var destination_dir: LazyPackageDestinationDir = .{ + .node_modules_path = .{ + .node_modules = &this.node_modules, + .root_node_modules_dir = this.root_node_modules_folder, + }, }; defer { - if (std.fs.cwd().fd != destination_dir.fd) destination_dir.close(); + destination_dir.close(); } - defer if (!pkg_has_patch) this.incrementTreeInstallCount(this.current_tree_id, destination_dir, !is_pending_package_install, log_level); + defer if (!pkg_has_patch) this.incrementTreeInstallCount(this.current_tree_id, &destination_dir, !is_pending_package_install, log_level); const dep = this.lockfile.buffers.dependencies.items[dependency_id]; const truncated_dep_name_hash: TruncatedPackageNameHash = @truncate(dep.name_hash); @@ -13309,7 +13379,7 @@ pub const PackageManager = struct { if (this.enqueueLifecycleScripts( alias.slice(this.lockfile.buffers.string_bytes.items), log_level, - destination_dir, + &destination_dir, package_id, dep.behavior.optional, resolution, @@ -13346,7 +13416,8 @@ pub const PackageManager = struct { this.manager.scopeForPackageName(pkg_name), pkg_name_hash, &expired, - .load_from_memory_fallback_to_disk, + // Do not fallback to disk. These files are much larger than the package.json + .load_from_memory, )) |manifest| { if (manifest.findByVersion(resolution.value.npm.version)) |find| { return find.package.bin.cloneAppend(manifest.string_buf, manifest.extern_strings_bin_entries, this.lockfile); @@ -13398,7 +13469,7 @@ pub const PackageManager = struct { this: *PackageInstaller, folder_name: string, comptime log_level: Options.LogLevel, - node_modules_folder: std.fs.Dir, + node_modules_folder: *LazyPackageDestinationDir, package_id: PackageID, optional: bool, resolution: *const Resolution, diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 14493dcd78..6563a01ab6 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -3367,7 +3367,7 @@ pub const Package = extern struct { this: *Package.Scripts, log: *logger.Log, lockfile: *Lockfile, - node_modules: std.fs.Dir, + node_modules: *PackageManager.LazyPackageDestinationDir, abs_node_modules_path: string, folder_name: string, resolution: *const Resolution, @@ -3427,13 +3427,13 @@ pub const Package = extern struct { allocator: std.mem.Allocator, string_builder: *Lockfile.StringBuilder, log: *logger.Log, - node_modules: std.fs.Dir, + node_modules: *PackageManager.LazyPackageDestinationDir, folder_name: string, ) !void { const json = brk: { const json_src = brk2: { const json_path = bun.path.joinZ([_]string{ folder_name, "package.json" }, .auto); - const buf = try bun.sys.File.readFrom(node_modules, json_path, allocator).unwrap(); + const buf = try bun.sys.File.readFrom(try node_modules.getDir(), json_path, allocator).unwrap(); break :brk2 logger.Source.initPathString(json_path, buf); }; @@ -3455,7 +3455,7 @@ pub const Package = extern struct { this: *Package.Scripts, log: *logger.Log, lockfile: *Lockfile, - node_modules: std.fs.Dir, + node_modules: *PackageManager.LazyPackageDestinationDir, abs_folder_path: string, folder_name: string, resolution_tag: Resolution.Tag, From 3ce6ffa6bebb129f19bbb3e8f4a6d01e4b57cbd3 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 14 Dec 2024 19:42:23 -0800 Subject: [PATCH 009/125] Make git dependencies faster + further optimize bun install (#15771) --- src/bun.js/node/node_os.zig | 6 +- src/install/install.zig | 87 ++++++++++++++--------- src/install/resolvers/folder_resolver.zig | 2 +- src/io/PipeReader.zig | 2 +- src/sys.zig | 37 +++++++--- 5 files changed, 86 insertions(+), 48 deletions(-) diff --git a/src/bun.js/node/node_os.zig b/src/bun.js/node/node_os.zig index a7c4da6691..ef2dfab3f1 100644 --- a/src/bun.js/node/node_os.zig +++ b/src/bun.js/node/node_os.zig @@ -82,7 +82,7 @@ pub const OS = struct { if (std.fs.openFileAbsolute("/proc/stat", .{})) |file| { defer file.close(); - const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf).unwrap(); + const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); defer file_buf.clearRetainingCapacity(); const contents = file_buf.items[0..read]; @@ -124,7 +124,7 @@ pub const OS = struct { if (std.fs.openFileAbsolute("/proc/cpuinfo", .{})) |file| { defer file.close(); - const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf).unwrap(); + const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); defer file_buf.clearRetainingCapacity(); const contents = file_buf.items[0..read]; @@ -175,7 +175,7 @@ pub const OS = struct { if (std.fs.openFileAbsolute(path, .{})) |file| { defer file.close(); - const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf).unwrap(); + const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); defer file_buf.clearRetainingCapacity(); const contents = file_buf.items[0..read]; diff --git a/src/install/install.zig b/src/install/install.zig index 59d8ec6541..46623de9a2 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -1140,20 +1140,15 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { var git_tag_stack_fallback = std.heap.stackFallback(2048, bun.default_allocator); const allocator = git_tag_stack_fallback.get(); - var destination_dir = this.node_modules.openDir(root_node_modules_dir) catch return .{}; - defer { - if (std.fs.cwd().fd != destination_dir.fd) destination_dir.close(); - } - - const bun_tag_file = File.readFrom( - destination_dir, + var bun_tag_file = this.node_modules.readSmallFile( + root_node_modules_dir, bun_tag_path, allocator, - ).unwrap() catch return .{}; - defer allocator.free(bun_tag_file); + ) catch return .{}; + defer bun_tag_file.bytes.deinit(); return .{ - .valid = strings.eqlLong(repo.resolved.slice(this.lockfile.buffers.string_bytes.items), bun_tag_file, true), + .valid = strings.eqlLong(repo.resolved.slice(this.lockfile.buffers.string_bytes.items), bun_tag_file.bytes.items, true), }; } @@ -1183,11 +1178,9 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { // Only check for destination directory in node_modules. We can't use package.json because // it might not exist fn verifyTransitiveSymlinkedFolder(this: *@This(), root_node_modules_dir: std.fs.Dir) VerifyResult { - var destination_dir = this.node_modules.openDir(root_node_modules_dir) catch return .{}; - defer destination_dir.close(); - - const exists = bun.sys.directoryExistsAt(destination_dir.fd, this.destination_dir_subpath).unwrap() catch return .{}; - return if (exists) .{ .valid = true } else .{}; + return .{ + .valid = this.node_modules.directoryExistsAt(root_node_modules_dir, this.destination_dir_subpath), + }; } const VerifyResult = struct { @@ -1210,7 +1203,7 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { const package_json_path: [:0]u8 = this.destination_dir_subpath_buf[0 .. this.destination_dir_subpath.len + std.fs.path.sep_str.len + "package.json".len :0]; defer this.destination_dir_subpath_buf[this.destination_dir_subpath.len] = 0; - var package_json_file = this.node_modules.openPackageJSON(root_node_modules_dir, package_json_path) catch return null; + var package_json_file = this.node_modules.openFile(root_node_modules_dir, package_json_path) catch return null; defer package_json_file.close(); // Heuristic: most package.jsons will be less than 2048 bytes. @@ -12121,16 +12114,49 @@ pub const PackageManager = struct { this.path.clearAndFree(); } - noinline fn openPackageJSONFileWithoutOpeningDirectories(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, package_json_path: [:0]const u8) bun.sys.Maybe(bun.sys.File) { + // Since the stack size of these functions are rather large, let's not let them be inlined. + noinline fn directoryExistsAtWithoutOpeningDirectories(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, file_path: [:0]const u8) bool { var path_buf: bun.PathBuffer = undefined; - const parts: [2][]const u8 = .{ this.path.items, package_json_path }; + const parts: [2][]const u8 = .{ this.path.items, file_path }; + return bun.sys.directoryExistsAt(bun.toFD(root_node_modules_dir), bun.path.joinZBuf(&path_buf, &parts, .auto)).unwrapOr(false); + } + + pub fn directoryExistsAt(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, file_path: [:0]const u8) bool { + if (file_path.len + this.path.items.len * 2 < bun.MAX_PATH_BYTES) { + return this.directoryExistsAtWithoutOpeningDirectories(root_node_modules_dir, file_path); + } + + const dir = this.openDir(root_node_modules_dir) catch return false; + defer { + _ = bun.sys.close(bun.toFD(dir)); + } + + return bun.sys.directoryExistsAt(bun.toFD(dir), file_path).unwrapOr(false); + } + + // Since the stack size of these functions are rather large, let's not let them be inlined. + noinline fn openFileWithoutOpeningDirectories(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, file_path: [:0]const u8) bun.sys.Maybe(bun.sys.File) { + var path_buf: bun.PathBuffer = undefined; + const parts: [2][]const u8 = .{ this.path.items, file_path }; return bun.sys.File.openat(bun.toFD(root_node_modules_dir), bun.path.joinZBuf(&path_buf, &parts, .auto), bun.O.RDONLY, 0); } - pub fn openPackageJSON(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, package_json_path: [:0]const u8) !bun.sys.File { - if (this.path.items.len + package_json_path.len * 2 < bun.MAX_PATH_BYTES) { + pub fn readFile(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, file_path: [:0]const u8, allocator: std.mem.Allocator) !bun.sys.File.ReadToEndResult { + const file = try this.openFile(root_node_modules_dir, file_path); + defer file.close(); + return file.readToEnd(allocator); + } + + pub fn readSmallFile(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, file_path: [:0]const u8, allocator: std.mem.Allocator) !bun.sys.File.ReadToEndResult { + const file = try this.openFile(root_node_modules_dir, file_path); + defer file.close(); + return file.readToEndSmall(allocator); + } + + pub fn openFile(this: *const NodeModulesFolder, root_node_modules_dir: std.fs.Dir, file_path: [:0]const u8) !bun.sys.File { + if (this.path.items.len + file_path.len * 2 < bun.MAX_PATH_BYTES) { // If we do not run the risk of ENAMETOOLONG, then let's just avoid opening the extra directories altogether. - switch (this.openPackageJSONFileWithoutOpeningDirectories(root_node_modules_dir, package_json_path)) { + switch (this.openFileWithoutOpeningDirectories(root_node_modules_dir, file_path)) { .err => |e| { switch (e.getErrno()) { // Just incase we're wrong, let's try the fallback @@ -12149,7 +12175,7 @@ pub const PackageManager = struct { _ = bun.sys.close(bun.toFD(dir)); } - return try bun.sys.File.openat(bun.toFD(dir), package_json_path, bun.O.RDONLY, 0).unwrap(); + return try bun.sys.File.openat(bun.toFD(dir), file_path, bun.O.RDONLY, 0).unwrap(); } pub fn openDir(this: *const NodeModulesFolder, root: std.fs.Dir) !std.fs.Dir { @@ -12284,18 +12310,13 @@ pub const PackageManager = struct { this.completed_trees.set(tree_id); - if (maybe_destination_dir) |maybe| { - if (maybe.getDir() catch null) |_destination_dir| { - var destination_dir = _destination_dir; - defer { - if (maybe_destination_dir == null) { - destination_dir.close(); - } - } + // Avoid opening this directory if we don't need to. + if (tree.binaries.count() > 0) { + // Don't close this directory in here. It will be closed by the caller. + if (maybe_destination_dir) |maybe| { + if (maybe.getDir() catch null) |destination_dir| { + this.seen_bin_links.clearRetainingCapacity(); - this.seen_bin_links.clearRetainingCapacity(); - - if (tree.binaries.count() > 0) { var link_target_buf: bun.PathBuffer = undefined; var link_dest_buf: bun.PathBuffer = undefined; var link_rel_buf: bun.PathBuffer = undefined; diff --git a/src/install/resolvers/folder_resolver.zig b/src/install/resolvers/folder_resolver.zig index 30ff41f9c3..4528a41a27 100644 --- a/src/install/resolvers/folder_resolver.zig +++ b/src/install/resolvers/folder_resolver.zig @@ -200,7 +200,7 @@ pub const FolderResolution = union(Tag) { body.data.reset(); var man = body.data.list.toManaged(manager.allocator); defer body.data.list = man.moveToUnmanaged(); - _ = try file.readToEndWithArrayList(&man).unwrap(); + _ = try file.readToEndWithArrayList(&man, true).unwrap(); } break :brk logger.Source.initPathString(abs, body.data.list.items); diff --git a/src/io/PipeReader.zig b/src/io/PipeReader.zig index b7b8ebfbdc..38394793a5 100644 --- a/src/io/PipeReader.zig +++ b/src/io/PipeReader.zig @@ -806,7 +806,7 @@ const PosixBufferedReader = struct { pub fn finalBuffer(this: *PosixBufferedReader) *std.ArrayList(u8) { if (this.flags.memfd and this.handle == .fd) { defer this.handle.close(null, {}); - _ = bun.sys.File.readToEndWithArrayList(.{ .handle = this.handle.fd }, this.buffer()).unwrap() catch |err| { + _ = bun.sys.File.readToEndWithArrayList(.{ .handle = this.handle.fd }, this.buffer(), false).unwrap() catch |err| { bun.Output.debugWarn("error reading from memfd\n{}", .{err}); return this.buffer(); }; diff --git a/src/sys.zig b/src/sys.zig index 0fca595558..aa9df098d5 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -3411,15 +3411,19 @@ pub const File = struct { return .{ .result = buf[0..read_amount] }; } - pub fn readToEndWithArrayList(this: File, list: *std.ArrayList(u8)) Maybe(usize) { - const size = switch (this.getEndPos()) { - .err => |err| { - return .{ .err = err }; - }, - .result => |s| s, - }; - - list.ensureTotalCapacityPrecise(size + 16) catch bun.outOfMemory(); + pub fn readToEndWithArrayList(this: File, list: *std.ArrayList(u8), probably_small: bool) Maybe(usize) { + if (probably_small) { + list.ensureUnusedCapacity(64) catch bun.outOfMemory(); + } else { + list.ensureTotalCapacityPrecise( + switch (this.getEndPos()) { + .err => |err| { + return .{ .err = err }; + }, + .result => |s| s, + } + 16, + ) catch bun.outOfMemory(); + } var total: i64 = 0; while (true) { @@ -3447,9 +3451,22 @@ pub const File = struct { return .{ .result = @intCast(total) }; } + + /// Use this function on potentially large files. + /// Calls fstat() on the file to get the size of the file and avoids reallocations + extra read() calls. pub fn readToEnd(this: File, allocator: std.mem.Allocator) ReadToEndResult { var list = std.ArrayList(u8).init(allocator); - return switch (readToEndWithArrayList(this, &list)) { + return switch (readToEndWithArrayList(this, &list, false)) { + .err => |err| .{ .err = err, .bytes = list }, + .result => .{ .err = null, .bytes = list }, + }; + } + + /// Use this function on small files < 1024 bytes. + /// This will skip the fstat() call. + pub fn readToEndSmall(this: File, allocator: std.mem.Allocator) ReadToEndResult { + var list = std.ArrayList(u8).init(allocator); + return switch (readToEndWithArrayList(this, &list, true)) { .err => |err| .{ .err = err, .bytes = list }, .result => .{ .err = null, .bytes = list }, }; From c218bffd94b42beb857a539207f59db8d855829a Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 14 Dec 2024 22:52:17 -0800 Subject: [PATCH 010/125] Add "bin" field to `bun.lock` (#15763) Co-authored-by: Dylan Conway --- src/bun.js/ConsoleObject.zig | 2 +- src/bun.js/javascript.zig | 4 +- src/bun.js/test/pretty_format.zig | 2 +- src/cli/init_command.zig | 2 +- src/fmt.zig | 2 +- src/install/bin.zig | 97 +++++- src/install/bun.lock.zig | 135 +++++--- src/install/install.zig | 216 +++--------- src/install/lockfile.zig | 50 ++- src/install/semver.zig | 23 ++ src/json_parser.zig | 123 ++----- .../bun-install-registry.test.ts.snap | 46 +++ .../registry/bun-install-registry.test.ts | 307 ++++++++++++++++++ 13 files changed, 668 insertions(+), 341 deletions(-) diff --git a/src/bun.js/ConsoleObject.zig b/src/bun.js/ConsoleObject.zig index 5f08103018..12a2506a41 100644 --- a/src/bun.js/ConsoleObject.zig +++ b/src/bun.js/ConsoleObject.zig @@ -1879,7 +1879,7 @@ pub const Formatter = struct { writer.print( comptime Output.prettyFmt("{s}: ", enable_ansi_colors), - .{bun.fmt.formatJSONString(key.slice())}, + .{bun.fmt.formatJSONStringLatin1(key.slice())}, ); } } else if (Environment.isDebug and is_private_symbol) { diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 3d4a95e5a7..9fb2fefe70 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -3000,7 +3000,7 @@ pub const VirtualMachine = struct { "{s} resolving preload {}", .{ @errorName(e), - bun.fmt.formatJSONString(preload), + bun.fmt.formatJSONStringLatin1(preload), }, ) catch unreachable; return e; @@ -3012,7 +3012,7 @@ pub const VirtualMachine = struct { this.allocator, "preload not found {}", .{ - bun.fmt.formatJSONString(preload), + bun.fmt.formatJSONStringLatin1(preload), }, ) catch unreachable; return error.ModuleNotFound; diff --git a/src/bun.js/test/pretty_format.zig b/src/bun.js/test/pretty_format.zig index dd119384c7..7cfeb3e212 100644 --- a/src/bun.js/test/pretty_format.zig +++ b/src/bun.js/test/pretty_format.zig @@ -861,7 +861,7 @@ pub const JestPrettyFormat = struct { writer.print( comptime Output.prettyFmt("{s}: ", enable_ansi_colors), - .{bun.fmt.formatJSONString(key.slice())}, + .{bun.fmt.formatJSONStringLatin1(key.slice())}, ); } } else { diff --git a/src/cli/init_command.zig b/src/cli/init_command.zig index 86f6efd224..0504a2c6dd 100644 --- a/src/cli/init_command.zig +++ b/src/cli/init_command.zig @@ -435,7 +435,7 @@ pub const InitCommand = struct { " \"'", fields.entry_point, )) { - Output.prettyln(" bun run {any}", .{bun.fmt.formatJSONString(fields.entry_point)}); + Output.prettyln(" bun run {any}", .{bun.fmt.formatJSONStringLatin1(fields.entry_point)}); } else { Output.prettyln(" bun run {s}", .{fields.entry_point}); } diff --git a/src/fmt.zig b/src/fmt.zig index 33d25bef1d..986a90bb8d 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -250,7 +250,7 @@ const JSONFormatterUTF8 = struct { }; /// Expects latin1 -pub fn formatJSONString(text: []const u8) JSONFormatter { +pub fn formatJSONStringLatin1(text: []const u8) JSONFormatter { return .{ .input = text }; } diff --git a/src/install/bin.zig b/src/install/bin.zig index 9837f80206..d0162e6383 100644 --- a/src/install/bin.zig +++ b/src/install/bin.zig @@ -28,16 +28,11 @@ const Lockfile = Install.Lockfile; /// - map where keys are names of the binaries and values are file paths to the binaries pub const Bin = extern struct { tag: Tag = Tag.none, - unset: u8 = 0, - _padding_tag: [2]u8 = .{0} ** 2, + _padding_tag: [3]u8 = .{0} ** 3, // Largest member must be zero initialized value: Value = Value{ .map = ExternalStringList{} }, - pub fn isUnset(this: *const Bin) bool { - return this.unset != 0; - } - pub fn count(this: *const Bin, buf: []const u8, extern_strings: []const ExternalString, comptime StringBuilder: type, builder: StringBuilder) u32 { switch (this.tag) { .file => builder.count(this.value.file.slice(buf)), @@ -59,26 +54,67 @@ pub const Bin = extern struct { return 0; } + pub fn eql( + l: *const Bin, + r: *const Bin, + l_buf: string, + l_extern_strings: []const ExternalString, + r_buf: string, + r_extern_strings: []const ExternalString, + ) bool { + if (l.tag != r.tag) return false; + + return switch (l.tag) { + .none => true, + .file => l.value.file.eql(r.value.file, l_buf, r_buf), + .dir => l.value.dir.eql(r.value.dir, l_buf, r_buf), + .named_file => l.value.named_file[0].eql(r.value.named_file[0], l_buf, r_buf) and + l.value.named_file[1].eql(r.value.named_file[1], l_buf, r_buf), + .map => { + const l_list = l.value.map.get(l_extern_strings); + const r_list = r.value.map.get(r_extern_strings); + if (l_list.len != r_list.len) return false; + + // assuming these maps are small without duplicate keys + var i: usize = 0; + outer: while (i < l_list.len) : (i += 2) { + var j: usize = 0; + while (j < r_list.len) : (j += 2) { + if (l_list[i].hash == r_list[j].hash) { + if (l_list[i + 1].hash != r_list[j + 1].hash) { + return false; + } + + continue :outer; + } + } + + // not found + return false; + } + + return true; + }, + }; + } + pub fn clone(this: *const Bin, buf: []const u8, prev_external_strings: []const ExternalString, all_extern_strings: []ExternalString, extern_strings_slice: []ExternalString, comptime StringBuilder: type, builder: StringBuilder) Bin { switch (this.tag) { .none => { return Bin{ .tag = .none, - .unset = this.unset, .value = Value.init(.{ .none = {} }), }; }, .file => { return Bin{ .tag = .file, - .unset = this.unset, .value = Value.init(.{ .file = builder.append(String, this.value.file.slice(buf)) }), }; }, .named_file => { return Bin{ .tag = .named_file, - .unset = this.unset, .value = Value.init( .{ .named_file = [2]String{ @@ -92,7 +128,6 @@ pub const Bin = extern struct { .dir => { return Bin{ .tag = .dir, - .unset = this.unset, .value = Value.init(.{ .dir = builder.append(String, this.value.dir.slice(buf)) }), }; }, @@ -103,7 +138,6 @@ pub const Bin = extern struct { return Bin{ .tag = .map, - .unset = this.unset, .value = Value.init(.{ .map = ExternalStringList.init(all_extern_strings, extern_strings_slice) }), }; }, @@ -118,7 +152,6 @@ pub const Bin = extern struct { const cloned: Bin = .{ .tag = this.tag, - .unset = this.unset, .value = switch (this.tag) { .none => Value.init(.{ .none = {} }), @@ -236,6 +269,46 @@ pub const Bin = extern struct { return .{}; } + /// Writes value of bin to a single line, either as a string or object. Cannot be `.none` because a value is expected to be + /// written to the json, as a property value or array value. + pub fn toSingleLineJson(this: *const Bin, buf: string, extern_strings: []const ExternalString, writer: anytype) @TypeOf(writer).Error!void { + bun.debugAssert(this.tag != .none); + switch (this.tag) { + .none => {}, + .file => { + try writer.print("{}", .{this.value.file.fmtJson(buf, .{})}); + }, + .named_file => { + try writer.writeByte('{'); + try writer.print(" {}: {} ", .{ + this.value.named_file[0].fmtJson(buf, .{}), + this.value.named_file[1].fmtJson(buf, .{}), + }); + try writer.writeByte('}'); + }, + .dir => { + try writer.print("{}", .{this.value.dir.fmtJson(buf, .{})}); + }, + .map => { + try writer.writeByte('{'); + const list = this.value.map.get(extern_strings); + var first = true; + var i: usize = 0; + while (i < list.len) : (i += 2) { + if (!first) { + try writer.writeByte(','); + } + first = false; + try writer.print(" {}: {}", .{ + list[i].value.fmtJson(buf, .{}), + list[i + 1].value.fmtJson(buf, .{}), + }); + } + try writer.writeAll(" }"); + }, + } + } + pub fn init() Bin { return bun.serializable(.{ .tag = .none, .value = Value.init(.{ .none = {} }) }); } diff --git a/src/install/bun.lock.zig b/src/install/bun.lock.zig index 2e1a407f8c..8f236189d2 100644 --- a/src/install/bun.lock.zig +++ b/src/install/bun.lock.zig @@ -36,6 +36,8 @@ const Negatable = Npm.Negatable; const DependencyID = Install.DependencyID; const invalid_dependency_id = Install.invalid_dependency_id; const DependencyIDSlice = BinaryLockfile.DependencyIDSlice; +const Bin = Install.Bin; +const ExternalString = Semver.ExternalString; /// A property key in the `packages` field of the lockfile pub const PkgPath = struct { @@ -421,6 +423,7 @@ pub const Stringifier = struct { const pkg_names: []String = pkgs.items(.name); const pkg_name_hashes: []PackageNameHash = pkgs.items(.name_hash); const pkg_metas: []BinaryLockfile.Package.Meta = pkgs.items(.meta); + const pkg_bins = pkgs.items(.bin); var temp_buf: std.ArrayListUnmanaged(u8) = .{}; defer temp_buf.deinit(allocator); @@ -744,8 +747,9 @@ pub const Stringifier = struct { dep_name, }); - const pkg_name = pkg_names[pkg_id].slice(buf); + const pkg_name = pkg_names[pkg_id]; const pkg_meta = pkg_metas[pkg_id]; + const pkg_bin = pkg_bins[pkg_id]; const pkg_deps_list = pkg_dep_lists[pkg_id]; pkg_deps_sort_buf.clearRetainingCapacity(); @@ -767,60 +771,69 @@ pub const Stringifier = struct { // folder -> [ "name@path", deps..., ... ] // workspace -> [ "name@workspace:path", version or "", deps..., ... ] // tarball -> [ "name@tarball", deps..., ... ] - // root -> [ "name@root:" ] + // root -> [ "name@root:", bins ] // git -> [ "name@git+repo", deps..., ... ] // github -> [ "name@github:user/repo", deps..., ... ] switch (res.tag) { .root => { - try writer.print("[\"{}@root:\"]", .{ - bun.fmt.formatJSONStringUTF8(pkg_name, .{ .quote = false }), + try writer.print("[\"{}@root:\", ", .{ + pkg_name.fmtJson(buf, .{ .quote = false }), // we don't read the root package version into the binary lockfile }); + + try writer.writeByte('{'); + if (pkg_bin.tag != .none) { + try writer.writeAll(if (pkg_bin.tag == .dir) " \"binDir\": " else " \"bin\": "); + try pkg_bin.toSingleLineJson(buf, lockfile.buffers.extern_strings.items, writer); + try writer.writeAll(" }]"); + } else { + try writer.writeAll("}]"); + } }, .folder => { - try writer.print("[\"{s}@file:{}\", ", .{ - pkg_name, - bun.fmt.formatJSONStringUTF8(res.value.folder.slice(buf), .{ .quote = false }), + try writer.print("[\"{}@file:{}\", ", .{ + pkg_name.fmtJson(buf, .{ .quote = false }), + res.value.folder.fmtJson(buf, .{ .quote = false }), }); - try writePackageDepsAndMeta(writer, dep_id, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, buf, &optional_peers_buf); + try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, .local_tarball => { - try writer.print("[\"{s}@{}\", ", .{ - pkg_name, - bun.fmt.formatJSONStringUTF8(res.value.local_tarball.slice(buf), .{ .quote = false }), + try writer.print("[\"{}@{}\", ", .{ + pkg_name.fmtJson(buf, .{ .quote = false }), + res.value.local_tarball.fmtJson(buf, .{ .quote = false }), }); - try writePackageDepsAndMeta(writer, dep_id, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, buf, &optional_peers_buf); + try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, .remote_tarball => { - try writer.print("[\"{s}@{}\", ", .{ - pkg_name, - bun.fmt.formatJSONStringUTF8(res.value.remote_tarball.slice(buf), .{ .quote = false }), + try writer.print("[\"{}@{}\", ", .{ + pkg_name.fmtJson(buf, .{ .quote = false }), + res.value.remote_tarball.fmtJson(buf, .{ .quote = false }), }); - try writePackageDepsAndMeta(writer, dep_id, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, buf, &optional_peers_buf); + try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, .symlink => { - try writer.print("[\"{s}@link:{}\", ", .{ - pkg_name, - bun.fmt.formatJSONStringUTF8(res.value.symlink.slice(buf), .{ .quote = false }), + try writer.print("[\"{}@link:{}\", ", .{ + pkg_name.fmtJson(buf, .{ .quote = false }), + res.value.symlink.fmtJson(buf, .{ .quote = false }), }); - try writePackageDepsAndMeta(writer, dep_id, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, buf, &optional_peers_buf); + try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, .npm => { - try writer.print("[\"{s}@{}\", ", .{ - pkg_name, + try writer.print("[\"{}@{}\", ", .{ + pkg_name.fmtJson(buf, .{ .quote = false }), res.value.npm.version.fmt(buf), }); @@ -832,35 +845,33 @@ pub const Stringifier = struct { res.value.npm.url.slice(buf), }); - try writePackageDepsAndMeta(writer, dep_id, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, buf, &optional_peers_buf); + try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.print(", \"{}\"]", .{ pkg_meta.integrity, }); }, .workspace => { - const workspace_path = res.value.workspace.slice(buf); - - try writer.print("[\"{s}@workspace:{}\", ", .{ - pkg_name, - bun.fmt.formatJSONStringUTF8(workspace_path, .{ .quote = false }), + try writer.print("[\"{}@workspace:{}\", ", .{ + pkg_name.fmtJson(buf, .{ .quote = false }), + res.value.workspace.fmtJson(buf, .{ .quote = false }), }); - try writePackageDepsAndMeta(writer, dep_id, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, buf, &optional_peers_buf); + try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, inline .git, .github => |tag| { const repo: Repository = @field(res.value, @tagName(tag)); - try writer.print("[\"{s}@{}\", ", .{ - pkg_name, + try writer.print("[\"{}@{}\", ", .{ + pkg_name.fmtJson(buf, .{ .quote = false }), repo.fmt(if (comptime tag == .git) "git+" else "github:", buf), }); - try writePackageDepsAndMeta(writer, dep_id, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, buf, &optional_peers_buf); + try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.print(", {}]", .{ - bun.fmt.formatJSONStringUTF8(repo.resolved.slice(buf), .{ .quote = true }), + repo.resolved.fmtJson(buf, .{}), }); }, else => unreachable, @@ -881,16 +892,17 @@ pub const Stringifier = struct { return writer_buf.list.items; } - /// Writes a single line object. + /// Writes a single line object. Contains dependencies, os, cpu, libc (soon), and bin /// { "devDependencies": { "one": "1.1.1", "two": "2.2.2" }, "os": "none" } - fn writePackageDepsAndMeta( + fn writePackageInfoObject( writer: anytype, - _: DependencyID, deps_buf: []const Dependency, pkg_dep_ids: []const DependencyID, meta: *const Meta, + bin: *const Install.Bin, buf: string, optional_peers_buf: *std.ArrayList(String), + extern_strings: []const ExternalString, ) OOM!void { defer optional_peers_buf.clearRetainingCapacity(); @@ -986,6 +998,16 @@ pub const Stringifier = struct { try Negatable(Npm.Architecture).toJson(meta.arch, writer); } + if (bin.tag != .none) { + if (any) { + try writer.writeByte(','); + } else { + any = true; + } + try writer.writeAll(if (bin.tag == .dir) " \"binDir\": " else " \"bin\": "); + try bin.toSingleLineJson(buf, extern_strings, writer); + } + if (any) { try writer.writeAll(" }"); } else { @@ -1518,23 +1540,29 @@ pub fn parseIntoBinaryLockfile( return error.InvalidPackageInfo; } - const deps_os_cpu_libc_obj = pkg_info.at(i); + const deps_os_cpu_libc_bin_obj = pkg_info.at(i); i += 1; - if (!deps_os_cpu_libc_obj.isObject()) { - try log.addError(source, deps_os_cpu_libc_obj.loc, "Expected an object"); + if (!deps_os_cpu_libc_bin_obj.isObject()) { + try log.addError(source, deps_os_cpu_libc_bin_obj.loc, "Expected an object"); return error.InvalidPackageInfo; } - const off, const len = try parseAppendDependencies(lockfile, allocator, deps_os_cpu_libc_obj, &string_buf, log, source, &optional_peers_buf); + const off, const len = try parseAppendDependencies(lockfile, allocator, deps_os_cpu_libc_bin_obj, &string_buf, log, source, &optional_peers_buf); pkg.dependencies = .{ .off = off, .len = len }; pkg.resolutions = .{ .off = off, .len = len }; + if (deps_os_cpu_libc_bin_obj.get("bin")) |bin| { + pkg.bin = try Bin.parseAppend(allocator, bin, &string_buf, &lockfile.buffers.extern_strings); + } else if (deps_os_cpu_libc_bin_obj.get("binDir")) |bin_dir| { + pkg.bin = try Bin.parseAppendFromDirectories(allocator, bin_dir, &string_buf); + } + if (res.tag != .workspace) { - if (deps_os_cpu_libc_obj.get("os")) |os| { + if (deps_os_cpu_libc_bin_obj.get("os")) |os| { pkg.meta.os = try Negatable(Npm.OperatingSystem).fromJson(allocator, os); } - if (deps_os_cpu_libc_obj.get("cpu")) |arch| { + if (deps_os_cpu_libc_bin_obj.get("cpu")) |arch| { pkg.meta.arch = try Negatable(Npm.Architecture).fromJson(allocator, arch); } // TODO(dylan-conway) @@ -1543,6 +1571,24 @@ pub fn parseIntoBinaryLockfile( // } } }, + .root => { + if (i >= pkg_info.len) { + try log.addError(source, value.loc, "Missing package binaries object"); + return error.InvalidPackageInfo; + } + const bin_obj = pkg_info.at(i); + i += 1; + if (!bin_obj.isObject()) { + try log.addError(source, bin_obj.loc, "Expected an object"); + return error.InvalidPackageInfo; + } + + if (bin_obj.get("bin")) |bin| { + pkg.bin = try Bin.parseAppend(allocator, bin, &string_buf, &lockfile.buffers.extern_strings); + } else if (bin_obj.get("binDir")) |bin_dir| { + pkg.bin = try Bin.parseAppendFromDirectories(allocator, bin_dir, &string_buf); + } + }, else => {}, } @@ -1585,11 +1631,6 @@ pub fn parseIntoBinaryLockfile( pkg.name = name; pkg.name_hash = name_hash; pkg.resolution = res; - - // set later - pkg.bin = .{ - .unset = 1, - }; pkg.scripts = .{}; const pkg_id = try lockfile.appendPackageDedupe(&pkg, string_buf.bytes.items); diff --git a/src/install/install.zig b/src/install/install.zig index 46623de9a2..f7fcd9d356 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -1095,7 +1095,7 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { fn verifyPatchHash( this: *@This(), root_node_modules_dir: std.fs.Dir, - ) VerifyResult { + ) bool { bun.debugAssert(!this.patch.isNull()); // hash from the .patch file, to be checked against bun tag @@ -1108,22 +1108,21 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { bunhashtag, }, .posix); - var destination_dir = this.node_modules.openDir(root_node_modules_dir) catch return .{}; + var destination_dir = this.node_modules.openDir(root_node_modules_dir) catch return false; defer { if (std.fs.cwd().fd != destination_dir.fd) destination_dir.close(); } if (comptime bun.Environment.isPosix) { - _ = bun.sys.fstatat(bun.toFD(destination_dir.fd), patch_tag_path).unwrap() catch return .{}; + _ = bun.sys.fstatat(bun.toFD(destination_dir.fd), patch_tag_path).unwrap() catch return false; } else { switch (bun.sys.openat(bun.toFD(destination_dir.fd), patch_tag_path, bun.O.RDONLY, 0)) { - .err => return .{}, + .err => return false, .result => |fd| _ = bun.sys.close(fd), } } - return .{ - .valid = true, - }; + + return true; } // 1. verify that .bun-tag exists (was it installed from bun?) @@ -1132,7 +1131,7 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { this: *@This(), repo: *const Repository, root_node_modules_dir: std.fs.Dir, - ) VerifyResult { + ) bool { bun.copy(u8, this.destination_dir_subpath_buf[this.destination_dir_subpath.len..], std.fs.path.sep_str ++ ".bun-tag"); this.destination_dir_subpath_buf[this.destination_dir_subpath.len + std.fs.path.sep_str.len + ".bun-tag".len] = 0; const bun_tag_path: [:0]u8 = this.destination_dir_subpath_buf[0 .. this.destination_dir_subpath.len + std.fs.path.sep_str.len + ".bun-tag".len :0]; @@ -1144,50 +1143,40 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { root_node_modules_dir, bun_tag_path, allocator, - ) catch return .{}; + ) catch return false; defer bun_tag_file.bytes.deinit(); - return .{ - .valid = strings.eqlLong(repo.resolved.slice(this.lockfile.buffers.string_bytes.items), bun_tag_file.bytes.items, true), - }; + return strings.eqlLong(repo.resolved.slice(this.lockfile.buffers.string_bytes.items), bun_tag_file.bytes.items, true); } pub fn verify( this: *@This(), resolution: *const Resolution, root_node_modules_dir: std.fs.Dir, - bin: *Bin, - ) VerifyResult { + ) bool { const verified = switch (resolution.tag) { .git => this.verifyGitResolution(&resolution.value.git, root_node_modules_dir), .github => this.verifyGitResolution(&resolution.value.github, root_node_modules_dir), .root => this.verifyTransitiveSymlinkedFolder(root_node_modules_dir), .folder => if (this.lockfile.isWorkspaceTreeId(this.node_modules.tree_id)) - this.verifyPackageJSONNameAndVersion(root_node_modules_dir, resolution.tag, bin) + this.verifyPackageJSONNameAndVersion(root_node_modules_dir, resolution.tag) else this.verifyTransitiveSymlinkedFolder(root_node_modules_dir), - else => this.verifyPackageJSONNameAndVersion(root_node_modules_dir, resolution.tag, bin), + else => this.verifyPackageJSONNameAndVersion(root_node_modules_dir, resolution.tag), }; if (comptime kind == .patch) return verified; if (this.patch.isNull()) return verified; - if (!verified.valid) return verified; + if (!verified) return false; return this.verifyPatchHash(root_node_modules_dir); } // Only check for destination directory in node_modules. We can't use package.json because // it might not exist - fn verifyTransitiveSymlinkedFolder(this: *@This(), root_node_modules_dir: std.fs.Dir) VerifyResult { - return .{ - .valid = this.node_modules.directoryExistsAt(root_node_modules_dir, this.destination_dir_subpath), - }; + fn verifyTransitiveSymlinkedFolder(this: *@This(), root_node_modules_dir: std.fs.Dir) bool { + return this.node_modules.directoryExistsAt(root_node_modules_dir, this.destination_dir_subpath); } - const VerifyResult = struct { - valid: bool = false, - update_lockfile_pointers: bool = false, - }; - fn getInstalledPackageJsonSource( this: *PackageInstall, root_node_modules_dir: std.fs.Dir, @@ -1239,7 +1228,7 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { return logger.Source.initPathString(bun.span(package_json_path), mutable.list.items[0..total]); } - fn verifyPackageJSONNameAndVersion(this: *PackageInstall, root_node_modules_dir: std.fs.Dir, resolution_tag: Resolution.Tag, bin: *Bin) VerifyResult { + fn verifyPackageJSONNameAndVersion(this: *PackageInstall, root_node_modules_dir: std.fs.Dir, resolution_tag: Resolution.Tag) bool { var body_pool = Npm.Registry.BodyPool.get(this.allocator); var mutable: MutableString = body_pool.data; defer { @@ -1252,7 +1241,7 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { // Don't keep it open while we're parsing the JSON. // The longer the file stays open, the more likely it causes issues for // other processes on Windows. - const source = this.getInstalledPackageJsonSource(root_node_modules_dir, &mutable, resolution_tag) orelse return .{}; + const source = this.getInstalledPackageJsonSource(root_node_modules_dir, &mutable, resolution_tag) orelse return false; var log = logger.Log.init(this.allocator); defer log.deinit(); @@ -1263,12 +1252,11 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { this.allocator, &source, &log, - if (bin.isUnset()) .check_for_bin else .ignore_bin, - ) catch return .{}; - _ = package_json_checker.parseExpr(false, false) catch return .{}; - if (log.errors > 0 or !package_json_checker.has_found_name) return .{}; + ) catch return false; + _ = package_json_checker.parseExpr() catch return false; + if (log.errors > 0 or !package_json_checker.has_found_name) return false; // workspaces aren't required to have a version - if (!package_json_checker.has_found_version and resolution_tag != .workspace) return .{}; + if (!package_json_checker.has_found_version and resolution_tag != .workspace) return false; const found_version = package_json_checker.found_version; @@ -1301,43 +1289,14 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { } // If we didn't find any of these characters, there's no point in checking the version again. // it will never match. - return .{}; + return false; }; - if (!strings.eql(found_version[offset..], this.package_version)) return .{}; + if (!strings.eql(found_version[offset..], this.package_version)) return false; } // lastly, check the name. - if (strings.eql(package_json_checker.found_name, this.package_name.slice(this.lockfile.buffers.string_bytes.items))) { - // only want to set bins if up-to-date - if (bin.isUnset() and package_json_checker.has_found_bin) { - var string_buf = this.lockfile.stringBuf(); - defer string_buf.apply(this.lockfile); - - switch (package_json_checker.found_bin) { - .bin => |expr| { - bin.* = Bin.parseAppend(this.lockfile.allocator, expr, &string_buf, &this.lockfile.buffers.extern_strings) catch bun.outOfMemory(); - }, - .dir => |expr| { - bin.* = Bin.parseAppendFromDirectories(this.lockfile.allocator, expr, &string_buf) catch bun.outOfMemory(); - }, - } - - return .{ - .valid = true, - .update_lockfile_pointers = true, - }; - } else if (bin.isUnset()) { - // It's not unset. There's no bin. - bin.unset = 0; - } - - return .{ - .valid = true, - }; - } - - return .{}; + return strings.eql(package_json_checker.found_name, this.package_name.slice(this.lockfile.buffers.string_bytes.items)); } pub const Result = union(Tag) { @@ -12249,7 +12208,7 @@ pub const PackageManager = struct { metas: []const Lockfile.Package.Meta, names: []const String, pkg_name_hashes: []const PackageNameHash, - bins: []Bin, + bins: []const Bin, resolutions: []Resolution, node: *Progress.Node, destination_dir_subpath_buf: bun.PathBuffer = undefined, @@ -13023,19 +12982,10 @@ pub const PackageManager = struct { }, } - const needs_install = this.force_install or this.skip_verify_installed_version_number or !needs_verify or remove_patch or verify: { - const verified = installer.verify( - resolution, - this.root_node_modules_folder, - &this.bins[package_id], - ); - - if (verified.update_lockfile_pointers) { - this.fixCachedLockfilePackageSlices(); - } - - break :verify !verified.valid; - }; + const needs_install = this.force_install or this.skip_verify_installed_version_number or !needs_verify or remove_patch or !installer.verify( + resolution, + this.root_node_modules_folder, + ); this.summary.skipped += @intFromBool(!needs_install); if (needs_install) { @@ -13207,17 +13157,6 @@ pub const PackageManager = struct { this.node.completeOne(); } - if (this.bins[package_id].isUnset()) { - this.bins[package_id] = this.getPackageBin( - &installer, - pkg_name.slice(this.lockfile.buffers.string_bytes.items), - pkg_name_hash, - resolution, - ) catch |err| switch (err) { - error.OutOfMemory => bun.outOfMemory(), - }; - } - if (this.bins[package_id].tag != .none) { this.trees[this.current_tree_id].binaries.add(dependency_id) catch bun.outOfMemory(); } @@ -13356,16 +13295,6 @@ pub const PackageManager = struct { }, } } else { - if (this.bins[package_id].isUnset()) { - this.bins[package_id] = this.getPackageBin( - &installer, - pkg_name.slice(this.lockfile.buffers.string_bytes.items), - pkg_name_hash, - resolution, - ) catch |err| switch (err) { - error.OutOfMemory => bun.outOfMemory(), - }; - } if (this.bins[package_id].tag != .none) { this.trees[this.current_tree_id].binaries.add(dependency_id) catch bun.outOfMemory(); } @@ -13421,70 +13350,6 @@ pub const PackageManager = struct { } } - fn getPackageBin( - this: *PackageInstaller, - installer: *PackageInstall, - pkg_name: string, - pkg_name_hash: PackageNameHash, - resolution: *const Resolution, - ) OOM!Bin { - defer this.fixCachedLockfilePackageSlices(); - - if (resolution.tag == .npm) { - var expired = false; - if (this.manager.manifests.byNameHashAllowExpired( - this.manager, - this.manager.scopeForPackageName(pkg_name), - pkg_name_hash, - &expired, - // Do not fallback to disk. These files are much larger than the package.json - .load_from_memory, - )) |manifest| { - if (manifest.findByVersion(resolution.value.npm.version)) |find| { - return find.package.bin.cloneAppend(manifest.string_buf, manifest.extern_strings_bin_entries, this.lockfile); - } - } - } - - // get it from package.json - var body_pool = Npm.Registry.BodyPool.get(this.lockfile.allocator); - var mutable = body_pool.data; - defer { - body_pool.data = mutable; - Npm.Registry.BodyPool.release(body_pool); - } - - const source = installer.getInstalledPackageJsonSource(this.root_node_modules_folder, &mutable, resolution.tag) orelse return .{}; - - initializeStore(); - - var log = logger.Log.init(this.lockfile.allocator); - defer log.deinit(); - - var bin_finder = JSON.PackageJSONVersionChecker.init( - this.lockfile.allocator, - &source, - &log, - .only_bin, - ) catch return .{}; - _ = bin_finder.parseExpr(false, false) catch return .{}; - - if (bin_finder.has_found_bin) { - var string_buf = this.lockfile.stringBuf(); - defer { - string_buf.apply(this.lockfile); - this.fixCachedLockfilePackageSlices(); - } - - return switch (bin_finder.found_bin) { - .bin => |bin| try Bin.parseAppend(this.lockfile.allocator, bin, &string_buf, &this.lockfile.buffers.extern_strings), - .dir => |dir| try Bin.parseAppendFromDirectories(this.lockfile.allocator, dir, &string_buf), - }; - } - - return .{}; - } - // returns true if scripts are enqueued fn enqueueLifecycleScripts( this: *PackageInstaller, @@ -14847,7 +14712,7 @@ pub const PackageManager = struct { if (manager.options.enable.frozen_lockfile and load_result != .not_found) frozen_lockfile: { if (load_result.loadedFromTextLockfile()) { - if (manager.lockfile.eql(lockfile_before_clean, manager.allocator) catch bun.outOfMemory()) { + if (manager.lockfile.eql(lockfile_before_clean, packages_len_before_install, manager.allocator) catch bun.outOfMemory()) { break :frozen_lockfile; } } else { @@ -14863,6 +14728,8 @@ pub const PackageManager = struct { Global.crash(); } + const lockfile_before_install = manager.lockfile; + var install_summary = PackageInstall.Summary{ .lockfile_used_for_install = manager.lockfile, }; @@ -14881,10 +14748,13 @@ pub const PackageManager = struct { const did_meta_hash_change = // If the lockfile was frozen, we already checked it !manager.options.enable.frozen_lockfile and + if (load_result.loadedFromTextLockfile()) + !try manager.lockfile.eql(lockfile_before_clean, packages_len_before_install, manager.allocator) + else try manager.lockfile.hasMetaHashChanged( - PackageManager.verbose_install or manager.options.do.print_meta_hash_string, - @min(packages_len_before_install, manager.lockfile.packages.len), - ); + PackageManager.verbose_install or manager.options.do.print_meta_hash_string, + @min(packages_len_before_install, manager.lockfile.packages.len), + ); const should_save_lockfile = did_meta_hash_change or had_any_diffs or @@ -14950,8 +14820,14 @@ pub const PackageManager = struct { manager.lockfile.saveToDisk(save_format, manager.options.log_level.isVerbose()); if (comptime Environment.allow_assert) { - if (manager.lockfile.hasMetaHashChanged(false, packages_len_before_install) catch false) { - Output.panic("Lockfile metahash non-deterministic after saving", .{}); + if (load_result.loadedFromTextLockfile()) { + if (!try manager.lockfile.eql(lockfile_before_install, packages_len_before_install, manager.allocator)) { + Output.panic("Lockfile non-deterministic after saving", .{}); + } + } else { + if (manager.lockfile.hasMetaHashChanged(false, packages_len_before_install) catch false) { + Output.panic("Lockfile metahash non-deterministic after saving", .{}); + } } } diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 6563a01ab6..c2da337247 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -3108,6 +3108,15 @@ pub const Package = extern struct { postprepare: String = .{}, filled: bool = false, + pub fn eql(l: *const Package.Scripts, r: *const Package.Scripts, l_buf: string, r_buf: string) bool { + return l.preinstall.eql(r.preinstall, l_buf, r_buf) and + l.install.eql(r.install, l_buf, r_buf) and + l.postinstall.eql(r.postinstall, l_buf, r_buf) and + l.preprepare.eql(r.preprepare, l_buf, r_buf) and + l.prepare.eql(r.prepare, l_buf, r_buf) and + l.postprepare.eql(r.postprepare, l_buf, r_buf); + } + pub const List = struct { items: [Lockfile.Scripts.names.len]?Lockfile.Scripts.Entry, first_index: u8, @@ -6702,13 +6711,12 @@ pub const EqlSorter = struct { pkg_names: []const String, // Basically placement id - pub const IdPair = struct { + pub const PathToId = struct { pkg_id: PackageID, - tree_id: Tree.Id, tree_path: string, }; - pub fn isLessThan(this: @This(), l: IdPair, r: IdPair) bool { + pub fn isLessThan(this: @This(), l: PathToId, r: PathToId) bool { switch (strings.order(l.tree_path, r.tree_path)) { .lt => return true, .gt => return false, @@ -6723,7 +6731,8 @@ pub const EqlSorter = struct { } }; -pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) OOM!bool { +/// `cut_off_pkg_id` should be removed when we stop appending packages to lockfile during install step +pub fn eql(l: *const Lockfile, r: *const Lockfile, cut_off_pkg_id: usize, allocator: std.mem.Allocator) OOM!bool { const l_hoisted_deps = l.buffers.hoisted_dependencies.items; const r_hoisted_deps = r.buffers.hoisted_dependencies.items; const l_string_buf = l.buffers.string_bytes.items; @@ -6734,7 +6743,7 @@ pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) if (l_len != r_len) return false; - const sort_buf = try allocator.alloc(EqlSorter.IdPair, l_len + r_len); + const sort_buf = try allocator.alloc(EqlSorter.PathToId, l_len + r_len); defer l.allocator.free(sort_buf); var l_buf = sort_buf[0..l_len]; var r_buf = sort_buf[r_len..]; @@ -6749,10 +6758,9 @@ pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) for (l_tree.dependencies.get(l_hoisted_deps)) |l_dep_id| { if (l_dep_id == invalid_dependency_id) continue; const l_pkg_id = l.buffers.resolutions.items[l_dep_id]; - if (l_pkg_id == invalid_package_id) continue; + if (l_pkg_id == invalid_package_id or l_pkg_id >= cut_off_pkg_id) continue; l_buf[i] = .{ .pkg_id = l_pkg_id, - .tree_id = l_tree.id, .tree_path = tree_path, }; i += 1; @@ -6767,10 +6775,9 @@ pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) for (r_tree.dependencies.get(r_hoisted_deps)) |r_dep_id| { if (r_dep_id == invalid_dependency_id) continue; const r_pkg_id = r.buffers.resolutions.items[r_dep_id]; - if (r_pkg_id == invalid_package_id) continue; + if (r_pkg_id == invalid_package_id or r_pkg_id >= cut_off_pkg_id) continue; r_buf[i] = .{ .pkg_id = r_pkg_id, - .tree_id = r_tree.id, .tree_path = tree_path, }; i += 1; @@ -6786,7 +6793,7 @@ pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) const r_pkg_names = r_pkgs.items(.name); std.sort.pdq( - EqlSorter.IdPair, + EqlSorter.PathToId, l_buf, EqlSorter{ .pkg_names = l_pkg_names, @@ -6796,7 +6803,7 @@ pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) ); std.sort.pdq( - EqlSorter.IdPair, + EqlSorter.PathToId, r_buf, EqlSorter{ .pkg_names = r_pkg_names, @@ -6807,8 +6814,15 @@ pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) const l_pkg_name_hashes = l_pkgs.items(.name_hash); const l_pkg_resolutions = l_pkgs.items(.resolution); + const l_pkg_bins = l_pkgs.items(.bin); + const l_pkg_scripts = l_pkgs.items(.scripts); const r_pkg_name_hashes = r_pkgs.items(.name_hash); const r_pkg_resolutions = r_pkgs.items(.resolution); + const r_pkg_bins = r_pkgs.items(.bin); + const r_pkg_scripts = r_pkgs.items(.scripts); + + const l_extern_strings = l.buffers.extern_strings.items; + const r_extern_strings = r.buffers.extern_strings.items; for (l_buf, r_buf) |l_ids, r_ids| { const l_pkg_id = l_ids.pkg_id; @@ -6826,6 +6840,20 @@ pub fn eql(l: *const Lockfile, r: *const Lockfile, allocator: std.mem.Allocator) } else if (!l_res.eql(&r_res, l_string_buf, r_string_buf)) { return false; } + + if (!l_pkg_bins[l_pkg_id].eql( + &r_pkg_bins[r_pkg_id], + l_string_buf, + l_extern_strings, + r_string_buf, + r_extern_strings, + )) { + return false; + } + + if (!l_pkg_scripts[l_pkg_id].eql(&r_pkg_scripts[r_pkg_id], l_string_buf, r_string_buf)) { + return false; + } } return true; diff --git a/src/install/semver.zig b/src/install/semver.zig index 8cd6cb0bc4..2dbc1a8a6c 100644 --- a/src/install/semver.zig +++ b/src/install/semver.zig @@ -160,6 +160,29 @@ pub const String = extern struct { } }; + /// Escapes for json. Expects string to be prequoted + pub inline fn fmtJson(self: *const String, buf: []const u8, opts: JsonFormatter.Options) JsonFormatter { + return .{ + .buf = buf, + .str = self, + .opts = opts, + }; + } + + pub const JsonFormatter = struct { + str: *const String, + buf: string, + opts: Options, + + pub const Options = struct { + quote: bool = true, + }; + + pub fn format(formatter: JsonFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + try writer.print("{}", .{bun.fmt.formatJSONStringUTF8(formatter.str.slice(formatter.buf), .{ .quote = formatter.opts.quote })}); + } + }; + pub fn Sorter(comptime direction: enum { asc, desc }) type { return struct { lhs_buf: []const u8, diff --git a/src/json_parser.zig b/src/json_parser.zig index 22ef5f4632..c3fbf960e3 100644 --- a/src/json_parser.zig +++ b/src/json_parser.zig @@ -347,16 +347,14 @@ fn JSONLikeParser_( }; } -// This is a special JSON parser that stops as soon as it finds combinations of +// This is a special JSON parser that stops as soon as it finds // { // "name": "NAME_IN_HERE", // "version": "VERSION_IN_HERE", -// "bin": ... or "directories": { "bin": ... } // } -// and then returns the name, version, and bin -// More precisely, it stops as soon as it finds a top-level "name" and "version" (and/or "bin"). -// In most cases, it should perform zero heap allocations because it does not create arrays or objects (It just skips them). -// If searching for "bin", objects are only created if the key is top level "bin". "bin" within "directories" can only be a string. +// and then returns the name and version. +// More precisely, it stops as soon as it finds a top-level "name" and "version" property which are strings +// In most cases, it should perform zero heap allocations because it does not create arrays or objects (It just skips them) pub const PackageJSONVersionChecker = struct { const Lexer = js_lexer.NewLexer(opts); @@ -371,14 +369,9 @@ pub const PackageJSONVersionChecker = struct { found_name: []const u8 = "", found_version: []const u8 = "", - found_bin: union(enum) { - bin: Expr, - dir: Expr, - } = .{ .bin = Expr.empty }, has_found_name: bool = false, has_found_version: bool = false, - has_found_bin: bool = false, name_loc: logger.Loc = logger.Loc.Empty, @@ -389,24 +382,21 @@ pub const PackageJSONVersionChecker = struct { .allow_comments = true, }; - pub fn init(allocator: std.mem.Allocator, source: *const logger.Source, log: *logger.Log, checks: enum { check_for_bin, ignore_bin, only_bin }) !Parser { + pub fn init(allocator: std.mem.Allocator, source: *const logger.Source, log: *logger.Log) !Parser { return Parser{ .lexer = try Lexer.init(log, source.*, allocator), .allocator = allocator, .log = log, .source = source, - .has_found_bin = checks == .ignore_bin, - .has_found_name = checks == .only_bin, - .has_found_version = checks == .only_bin, }; } const Parser = @This(); - pub fn parseExpr(p: *Parser, collect_props: bool, parent_is_directories: bool) anyerror!Expr { + pub fn parseExpr(p: *Parser) anyerror!Expr { const loc = p.lexer.loc(); - if (p.has_found_name and p.has_found_version and p.has_found_bin) return newExpr(E.Missing{}, loc); + if (p.has_found_name and p.has_found_version) return newExpr(E.Missing{}, loc); switch (p.lexer.token) { .t_false => { @@ -453,7 +443,7 @@ pub const PackageJSONVersionChecker = struct { } } - _ = try p.parseExpr(false, false); + _ = try p.parseExpr(); has_exprs = true; } @@ -465,8 +455,6 @@ pub const PackageJSONVersionChecker = struct { p.depth += 1; defer p.depth -= 1; - var properties = std.ArrayList(G.Property).init(p.allocator); - var has_properties = false; while (p.lexer.token != .t_close_brace) { if (has_properties) { @@ -483,95 +471,40 @@ pub const PackageJSONVersionChecker = struct { try p.lexer.expect(.t_colon); - var collect_prop_props = false; - var is_directories = false; - - if (!p.has_found_bin and - p.depth == 1 and - // next is going to be a top level property - // with an object value. check if it is "bin" - // or "directories" - p.lexer.token == .t_open_brace and - key.data == .e_string) - { - if (strings.eqlComptime(key.data.e_string.data, "bin")) { - collect_prop_props = true; - } else if (strings.eqlComptime(key.data.e_string.data, "directories")) { - is_directories = true; - } - - // if bin is in directories it can only be a string, so - // don't need to set collect_prop_props when depth == 2 - // and in parent_is_directories == true. - - } - - const value = try p.parseExpr(collect_prop_props, is_directories); + const value = try p.parseExpr(); if (p.depth == 1) { // if you have multiple "name" fields in the package.json.... // first one wins - if (key.data == .e_string) { - if (value.data == .e_string) { - if (!p.has_found_name and strings.eqlComptime(key.data.e_string.data, "name")) { - const len = @min( - value.data.e_string.data.len, - p.found_name_buf.len, - ); + if (key.data == .e_string and value.data == .e_string) { + if (!p.has_found_name and strings.eqlComptime(key.data.e_string.data, "name")) { + const len = @min( + value.data.e_string.data.len, + p.found_name_buf.len, + ); - bun.copy(u8, &p.found_name_buf, value.data.e_string.data[0..len]); - p.found_name = p.found_name_buf[0..len]; - p.has_found_name = true; - p.name_loc = value.loc; - } else if (!p.has_found_version and strings.eqlComptime(key.data.e_string.data, "version")) { - const len = @min( - value.data.e_string.data.len, - p.found_version_buf.len, - ); - bun.copy(u8, &p.found_version_buf, value.data.e_string.data[0..len]); - p.found_version = p.found_version_buf[0..len]; - p.has_found_version = true; - } - } - - if (!p.has_found_bin and strings.eqlComptime(key.data.e_string.data, "bin")) { - p.found_bin = .{ - .bin = value, - }; - p.has_found_bin = true; - } - } - } else if (parent_is_directories) { - if (key.data == .e_string) { - if (!p.has_found_bin and strings.eqlComptime(key.data.e_string.data, "bin")) { - p.found_bin = .{ - .dir = value, - }; - p.has_found_bin = true; + bun.copy(u8, &p.found_name_buf, value.data.e_string.data[0..len]); + p.found_name = p.found_name_buf[0..len]; + p.has_found_name = true; + p.name_loc = value.loc; + } else if (!p.has_found_version and strings.eqlComptime(key.data.e_string.data, "version")) { + const len = @min( + value.data.e_string.data.len, + p.found_version_buf.len, + ); + bun.copy(u8, &p.found_version_buf, value.data.e_string.data[0..len]); + p.found_version = p.found_version_buf[0..len]; + p.has_found_version = true; } } } - if (p.has_found_name and p.has_found_version and p.has_found_bin) return newExpr(E.Missing{}, loc); + if (p.has_found_name and p.has_found_version) return newExpr(E.Missing{}, loc); has_properties = true; - if (collect_props) { - properties.append(.{ - .key = key, - .value = value, - .kind = .normal, - .initializer = null, - }) catch bun.outOfMemory(); - } } try p.lexer.expect(.t_close_brace); - - if (collect_props) { - return newExpr(E.Object{ - .properties = G.Property.List.fromList(properties), - }, loc); - } return newExpr(E.Missing{}, loc); }, else => { diff --git a/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap b/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap index 74b5db9224..6b04de3ea8 100644 --- a/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap +++ b/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap @@ -238,3 +238,49 @@ exports[`text lockfile --frozen-lockfile 1`] = ` } " `; + +exports[`binaries each type of binary serializes correctly to text lockfile 1`] = ` +"{ + "lockfileVersion": 0, + "workspaces": { + "": { + "dependencies": { + "dir-bin": "./dir-bin", + "file-bin": "./file-bin", + "map-bin": "./map-bin", + "named-file-bin": "./named-file-bin", + }, + }, + }, + "packages": { + "dir-bin": ["dir-bin@file:dir-bin", { "binDir": "./bins" }], + + "file-bin": ["file-bin@file:file-bin", { "bin": "./file-bin.js" }], + + "map-bin": ["map-bin@file:map-bin", { "bin": { "map-bin-1": "./map-bin-1.js", "map-bin-2": "./map-bin-2.js" } }], + + "named-file-bin": ["named-file-bin@file:named-file-bin", { "bin": { "named-file-bin": "./named-file-bin.js" } }], + } +} +" +`; + +exports[`binaries root resolution bins 1`] = ` +"{ + "lockfileVersion": 0, + "workspaces": { + "": { + "dependencies": { + "fooooo": ".", + "no-deps": "1.0.0", + }, + }, + }, + "packages": { + "fooooo": ["fooooo@root:", { "bin": "fooooo.js" }], + + "no-deps": ["no-deps@1.0.0", "http://localhost:1234/no-deps/-/no-deps-1.0.0.tgz", {}, "sha512-v4w12JRjUGvfHDUP8vFDwu0gUWu04j0cv9hLb1Abf9VdaXu4XcrddYFTMVBVvmldKViGWH7jrb6xPJRF0wq6gw=="], + } +} +" +`; diff --git a/test/cli/install/registry/bun-install-registry.test.ts b/test/cli/install/registry/bun-install-registry.test.ts index e475c49d87..203397a828 100644 --- a/test/cli/install/registry/bun-install-registry.test.ts +++ b/test/cli/install/registry/bun-install-registry.test.ts @@ -3279,6 +3279,313 @@ describe("binaries", () => { }); } + test("each type of binary serializes correctly to text lockfile", async () => { + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "foo", + version: "1.1.1", + dependencies: { + "file-bin": "./file-bin", + "named-file-bin": "./named-file-bin", + "dir-bin": "./dir-bin", + "map-bin": "./map-bin", + }, + }), + ), + write( + join(packageDir, "file-bin", "package.json"), + JSON.stringify({ + name: "file-bin", + version: "1.1.1", + bin: "./file-bin.js", + }), + ), + write(join(packageDir, "file-bin", "file-bin.js"), `#!/usr/bin/env node\nconsole.log("file-bin")`), + write( + join(packageDir, "named-file-bin", "package.json"), + JSON.stringify({ + name: "named-file-bin", + version: "1.1.1", + bin: { "named-file-bin": "./named-file-bin.js" }, + }), + ), + write( + join(packageDir, "named-file-bin", "named-file-bin.js"), + `#!/usr/bin/env node\nconsole.log("named-file-bin")`, + ), + write( + join(packageDir, "dir-bin", "package.json"), + JSON.stringify({ + name: "dir-bin", + version: "1.1.1", + directories: { + bin: "./bins", + }, + }), + ), + write(join(packageDir, "dir-bin", "bins", "dir-bin-1.js"), `#!/usr/bin/env node\nconsole.log("dir-bin-1")`), + write( + join(packageDir, "map-bin", "package.json"), + JSON.stringify({ + name: "map-bin", + version: "1.1.1", + bin: { + "map-bin-1": "./map-bin-1.js", + "map-bin-2": "./map-bin-2.js", + }, + }), + ), + write(join(packageDir, "map-bin", "map-bin-1.js"), `#!/usr/bin/env node\nconsole.log("map-bin-1")`), + write(join(packageDir, "map-bin", "map-bin-2.js"), `#!/usr/bin/env node\nconsole.log("map-bin-2")`), + ]); + + let { stderr, exited } = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile"], + cwd: packageDir, + stdout: "ignore", + stderr: "pipe", + env, + }); + + let err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + + expect(await exited).toBe(0); + + const firstLockfile = (await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + + expect(join(packageDir, "node_modules", ".bin", "file-bin")).toBeValidBin(join("..", "file-bin", "file-bin.js")); + expect(join(packageDir, "node_modules", ".bin", "named-file-bin")).toBeValidBin( + join("..", "named-file-bin", "named-file-bin.js"), + ); + expect(join(packageDir, "node_modules", ".bin", "dir-bin-1.js")).toBeValidBin( + join("..", "dir-bin", "bins", "dir-bin-1.js"), + ); + expect(join(packageDir, "node_modules", ".bin", "map-bin-1")).toBeValidBin(join("..", "map-bin", "map-bin-1.js")); + expect(join(packageDir, "node_modules", ".bin", "map-bin-2")).toBeValidBin(join("..", "map-bin", "map-bin-2.js")); + + await rm(join(packageDir, "node_modules", ".bin"), { recursive: true, force: true }); + + // now install from the lockfile, only linking bins + ({ stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "ignore", + stderr: "pipe", + env, + })); + + err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + expect(err).not.toContain("Saved lockfile"); + + expect(await exited).toBe(0); + + expect(firstLockfile).toBe( + (await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll(/localhost:\d+/g, "localhost:1234"), + ); + expect(firstLockfile).toMatchSnapshot(); + + expect(join(packageDir, "node_modules", ".bin", "file-bin")).toBeValidBin(join("..", "file-bin", "file-bin.js")); + expect(join(packageDir, "node_modules", ".bin", "named-file-bin")).toBeValidBin( + join("..", "named-file-bin", "named-file-bin.js"), + ); + expect(join(packageDir, "node_modules", ".bin", "dir-bin-1.js")).toBeValidBin( + join("..", "dir-bin", "bins", "dir-bin-1.js"), + ); + expect(join(packageDir, "node_modules", ".bin", "map-bin-1")).toBeValidBin(join("..", "map-bin", "map-bin-1.js")); + expect(join(packageDir, "node_modules", ".bin", "map-bin-2")).toBeValidBin(join("..", "map-bin", "map-bin-2.js")); + }); + + test.todo("text lockfile updates with new bin entry for folder dependencies", async () => { + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "foo", + dependencies: { + "change-bin": "./change-bin", + }, + }), + ), + write( + join(packageDir, "change-bin", "package.json"), + JSON.stringify({ + name: "change-bin", + version: "1.0.0", + bin: { + "change-bin-1": "./change-bin-1.js", + }, + }), + ), + write(join(packageDir, "change-bin", "change-bin-1.js"), `#!/usr/bin/env node\nconsole.log("change-bin-1")`), + ]); + + let { stderr, exited } = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile"], + cwd: packageDir, + stdout: "ignore", + stderr: "pipe", + env, + }); + + let err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + expect(err).toContain("Saved lockfile"); + + expect(await exited).toBe(0); + + const firstLockfile = (await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + + expect(join(packageDir, "node_modules", ".bin", "change-bin-1")).toBeValidBin( + join("..", "change-bin", "change-bin-1.js"), + ); + + await Promise.all([ + write( + join(packageDir, "change-bin", "package.json"), + JSON.stringify({ + name: "change-bin", + version: "1.0.0", + bin: { + "change-bin-1": "./change-bin-1.js", + "change-bin-2": "./change-bin-2.js", + }, + }), + ), + write(join(packageDir, "change-bin", "change-bin-2.js"), `#!/usr/bin/env node\nconsole.log("change-bin-2")`), + ]); + + ({ stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "ignore", + stderr: "pipe", + env, + })); + + err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + + // it should save + expect(err).toContain("Saved lockfile"); + + expect(await exited).toBe(0); + + const secondLockfile = (await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + expect(firstLockfile).not.toBe(secondLockfile); + + expect(secondLockfile).toMatchSnapshot(); + + expect(join(packageDir, "node_modules", ".bin", "change-bin-1")).toBeValidBin( + join("..", "change-bin", "change-bin-1.js"), + ); + + expect(join(packageDir, "node_modules", ".bin", "change-bin-2")).toBeValidBin( + join("..", "change-bin", "change-bin-2.js"), + ); + }); + + test("root resolution bins", async () => { + // As of writing this test, the only way to get a root resolution + // is to migrate a package-lock.json with a root resolution. For now, + // we'll just mock the bun.lock. + + await Promise.all([ + write( + join(packageDir, "package.json"), + JSON.stringify({ + name: "fooooo", + version: "2.2.2", + dependencies: { + "fooooo": ".", + "no-deps": "1.0.0", + }, + bin: "fooooo.js", + }), + ), + write(join(packageDir, "fooooo.js"), `#!/usr/bin/env node\nconsole.log("fooooo")`), + write( + join(packageDir, "bun.lock"), + JSON.stringify({ + "lockfileVersion": 0, + "workspaces": { + "": { + "dependencies": { + "fooooo": ".", + // out of date, no no-deps + }, + }, + }, + "packages": { + "fooooo": ["fooooo@root:", { bin: "fooooo.js" }], + }, + }), + ), + ]); + + let { stderr, stdout, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env, + }); + + let err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + expect(err).toContain("Saved lockfile"); + + let out = await Bun.readableStreamToText(stdout); + expect(out).toContain("no-deps@1.0.0"); + + expect(await exited).toBe(0); + + const firstLockfile = (await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + + expect(join(packageDir, "node_modules", ".bin", "fooooo")).toBeValidBin(join("..", "fooooo", "fooooo.js")); + + await rm(join(packageDir, "node_modules", ".bin"), { recursive: true, force: true }); + + ({ stderr, stdout, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env, + })); + + err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + expect(err).not.toContain("Saved lockfile"); + + out = await Bun.readableStreamToText(stdout); + expect(out).not.toContain("no-deps@1.0.0"); + + expect(await exited).toBe(0); + + expect(firstLockfile).toBe( + (await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll(/localhost:\d+/g, "localhost:1234"), + ); + expect(firstLockfile).toMatchSnapshot(); + + expect(join(packageDir, "node_modules", ".bin", "fooooo")).toBeValidBin(join("..", "fooooo", "fooooo.js")); + }); + async function runBin(binName: string, expected: string, global: boolean) { const args = global ? [`./global-bin-dir/${binName}`] : [bunExe(), binName]; const result = Bun.spawn({ From 00a8392656a5c39a1d031ff856a82e3b12c4a29b Mon Sep 17 00:00:00 2001 From: Brian Donovan <1938+eventualbuddha@users.noreply.github.com> Date: Sat, 14 Dec 2024 23:50:03 -0800 Subject: [PATCH 011/125] docs(bun-native-plugin-rs): fix typos (#15764) --- packages/bun-native-plugin-rs/README.md | 4 ++-- packages/bun-native-plugin-rs/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/bun-native-plugin-rs/README.md b/packages/bun-native-plugin-rs/README.md index 6c57a2c9d1..bf4c23143f 100644 --- a/packages/bun-native-plugin-rs/README.md +++ b/packages/bun-native-plugin-rs/README.md @@ -1,4 +1,4 @@ -> ⚠️ Note: This is an advanced and experimental API recommended only for plugin developers who are familiar with systems proramming and the C ABI. Use with caution. +> ⚠️ Note: This is an advanced and experimental API recommended only for plugin developers who are familiar with systems programming and the C ABI. Use with caution. # Bun Native Plugins @@ -42,7 +42,7 @@ use napi_derive::napi; /// Define the plugin and its name define_bun_plugin!("replace-foo-with-bar"); -/// Here we'll implement `onBeforeParse` with code that replaces all occurences of +/// Here we'll implement `onBeforeParse` with code that replaces all occurrences of /// `foo` with `bar`. /// /// We use the #[bun] macro to generate some of the boilerplate code. diff --git a/packages/bun-native-plugin-rs/src/lib.rs b/packages/bun-native-plugin-rs/src/lib.rs index 1a8f85941c..bed9c52089 100644 --- a/packages/bun-native-plugin-rs/src/lib.rs +++ b/packages/bun-native-plugin-rs/src/lib.rs @@ -1,4 +1,4 @@ -//! > ⚠️ Note: This is an advanced and experimental API recommended only for plugin developers who are familiar with systems proramming and the C ABI. Use with caution. +//! > ⚠️ Note: This is an advanced and experimental API recommended only for plugin developers who are familiar with systems programming and the C ABI. Use with caution. //! //! # Bun Native Plugins //! @@ -44,7 +44,7 @@ //! /// Use `no_mangle` so that we can reference this symbol by name later //! /// when registering this native plugin in JS. //! /// -//! /// Here we'll create a dummy plugin which replaces all occurences of +//! /// Here we'll create a dummy plugin which replaces all occurrences of //! /// `foo` with `bar` //! #[no_mangle] //! pub extern "C" fn on_before_parse_plugin_impl( From 65f515658959a07f19215991bd0f1c86799bb6f4 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 15 Dec 2024 00:47:59 -0800 Subject: [PATCH 012/125] Deflake process test --- test/js/node/process/process.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/js/node/process/process.test.js b/test/js/node/process/process.test.js index 09f9bb28f4..811abfb4bb 100644 --- a/test/js/node/process/process.test.js +++ b/test/js/node/process/process.test.js @@ -123,8 +123,8 @@ it("process.hrtime()", async () => { const end = process.hrtime(start); expect(end[0]).toBe(0); - // Flaky on Ubuntu. - await Bun.sleep(0); + // Flaky on Ubuntu & Windows. + await Bun.sleep(16); const end2 = process.hrtime(); expect(end2[1] > start[1]).toBe(true); From 8a64038fae816dd3f3813b71dd88d37003fcec3e Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 15 Dec 2024 00:55:18 -0800 Subject: [PATCH 013/125] Deflake require.cache test --- test/cli/run/esm-fixture-leak-small.mjs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/cli/run/esm-fixture-leak-small.mjs b/test/cli/run/esm-fixture-leak-small.mjs index a045d59c5d..38abc2121a 100644 --- a/test/cli/run/esm-fixture-leak-small.mjs +++ b/test/cli/run/esm-fixture-leak-small.mjs @@ -20,12 +20,22 @@ setTimeout(() => { let diff = process.memoryUsage.rss() - baseline; diff = (diff / 1024 / 1024) | 0; console.log({ leaked: diff + " MB" }); + // This test seems to be more flaky on slow filesystems. // This used to be 40 MB, but the original version of Bun which this triggered on would reach 120 MB - // so we can increase it to 60 and still catch the leak. - if (diff > 60) { + // so we can increase it to 100 and still catch the leak. + // + // ❯ bunx bun@1.0.0 --smol test/cli/run/esm-fixture-leak-small.mjs + // { + // leaked: "100 MB" + // } + // ❯ bunx bun@1.1.0 --smol test/cli/run/esm-fixture-leak-small.mjs + // { + // leaked: "38 MB", + // } + if (diff >= 100) { console.log("\n--fail--\n"); process.exit(1); } else { console.log("\n--pass--\n"); } -}, 16); +}, 24); From 6a24a067416bb0859e9986c3a0e835745bac7f4e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 15 Dec 2024 04:38:39 -0800 Subject: [PATCH 014/125] deps: update c-ares to v1.34.4 (#15773) Co-authored-by: Jarred-Sumner --- cmake/targets/BuildCares.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/targets/BuildCares.cmake b/cmake/targets/BuildCares.cmake index 373369b543..761f6d1998 100644 --- a/cmake/targets/BuildCares.cmake +++ b/cmake/targets/BuildCares.cmake @@ -4,7 +4,7 @@ register_repository( REPOSITORY c-ares/c-ares COMMIT - 41ee334af3e3d0027dca5e477855d0244936bd49 + 4f4912bce7374f787b10576851b687935f018e17 ) register_cmake_command( From 80b0b883150a92a449751e2eab292d5bfcc4abed Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 15 Dec 2024 06:54:34 -0800 Subject: [PATCH 015/125] Deflake doesnt_crash.test.ts --- test/js/bun/css/doesnt_crash.test.ts | 75 ++++++++++++++-------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/test/js/bun/css/doesnt_crash.test.ts b/test/js/bun/css/doesnt_crash.test.ts index c418f74e22..8cca195bb6 100644 --- a/test/js/bun/css/doesnt_crash.test.ts +++ b/test/js/bun/css/doesnt_crash.test.ts @@ -15,47 +15,48 @@ describe("doesnt_crash", async () => { files = readdirSync(files_dir).map(file => path.join(files_dir, file)); console.log("Tempdir", temp_dir); - files.map(absolute => { + files.forEach(absolute => { absolute = absolute.replaceAll("\\", "/"); const file = path.basename(absolute); - const outfile1 = path.join(temp_dir, "file-1" + file).replaceAll("\\", "/"); - const outfile2 = path.join(temp_dir, "file-2" + file).replaceAll("\\", "/"); - const outfile3 = path.join(temp_dir, "file-3" + file).replaceAll("\\", "/"); - const outfile4 = path.join(temp_dir, "file-4" + file).replaceAll("\\", "/"); - test(file, async () => { - { - const { stdout, stderr, exitCode } = - await Bun.$`${bunExe()} build --experimental-css ${absolute} --outfile=${outfile1}`.quiet().env(bunEnv); - expect(exitCode).toBe(0); - expect(stdout.toString()).not.toContain("error"); - expect(stderr.toString()).toBeEmpty(); - } + for (let minify of [false, true]) { + test(`${file} - ${minify ? "minify" : "not minify"}`, async () => { + const timeLog = `Transpiled ${file} - ${minify ? "minify" : "not minify"}`; + console.time(timeLog); + const { logs, outputs } = await Bun.build({ + entrypoints: [absolute], + experimentalCss: true, + minify: minify, + }); + console.timeEnd(timeLog); - const { stdout, stderr, exitCode } = - await Bun.$`${bunExe()} build --experimental-css ${outfile1} --outfile=${outfile2}`.quiet().env(bunEnv); - expect(exitCode).toBe(0); - expect(stdout.toString()).not.toContain("error"); - expect(stderr.toString()).toBeEmpty(); - }); + if (logs?.length) { + throw new Error(logs.join("\n")); + } - test(`(minify) ${file}`, async () => { - { - const { stdout, stderr, exitCode } = - await Bun.$`${bunExe()} build --experimental-css ${absolute} --minify --outfile=${outfile3}` - .quiet() - .env(bunEnv); - expect(exitCode).toBe(0); - expect(stdout.toString()).not.toContain("error"); - expect(stderr.toString()).toBeEmpty(); - } - const { stdout, stderr, exitCode } = - await Bun.$`${bunExe()} build --experimental-css ${outfile3} --minify --outfile=${outfile4}` - .quiet() - .env(bunEnv); - expect(exitCode).toBe(0); - expect(stdout.toString()).not.toContain("error"); - expect(stderr.toString()).toBeEmpty(); - }); + expect(outputs.length).toBe(1); + const outfile1 = path.join(temp_dir, "file-1" + file).replaceAll("\\", "/"); + + await Bun.write(outfile1, outputs[0]); + + { + const timeLog = `Re-transpiled ${file} - ${minify ? "minify" : "not minify"}`; + console.time(timeLog); + const { logs, outputs } = await Bun.build({ + entrypoints: [outfile1], + experimentalCss: true, + minify: minify, + }); + + if (logs?.length) { + throw new Error(logs.join("\n")); + } + + expect(outputs.length).toBe(1); + expect(await outputs[0].text()).not.toBeEmpty(); + console.timeEnd(timeLog); + } + }); + } }); }); From 1fa0dee5e933190ffd2c5d49ede80fe769cabbf0 Mon Sep 17 00:00:00 2001 From: Michael H Date: Mon, 16 Dec 2024 02:19:34 +1100 Subject: [PATCH 016/125] document `npm:` in install docs (#15754) --- docs/cli/install.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/cli/install.md b/docs/cli/install.md index 88de3d1759..56212b5c47 100644 --- a/docs/cli/install.md +++ b/docs/cli/install.md @@ -149,7 +149,8 @@ Bun supports installing dependencies from Git, GitHub, and local or remotely-hos "lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21", "moment": "git@github.com:moment/moment.git", "zod": "github:colinhacks/zod", - "react": "https://registry.npmjs.org/react/-/react-18.2.0.tgz" + "react": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "bun-types": "npm:@types/bun" } } ``` From 7633f3cc35accfaca2f822cb47a52e06894bb996 Mon Sep 17 00:00:00 2001 From: Sam <100821827+01101sam@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:52:49 +0800 Subject: [PATCH 017/125] docs: `dns.prefetch` doesn't require port anymore (#15792) --- docs/api/fetch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/fetch.md b/docs/api/fetch.md index afbf53c5c1..5cb4068c9c 100644 --- a/docs/api/fetch.md +++ b/docs/api/fetch.md @@ -234,7 +234,7 @@ To prefetch a DNS entry, you can use the `dns.prefetch` API. This API is useful ```ts import { dns } from "bun"; -dns.prefetch("bun.sh", 443); +dns.prefetch("bun.sh"); ``` #### DNS caching From 9604733ee18666b8f39a2e6e0c89728ece1d029c Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 16 Dec 2024 13:51:45 -0800 Subject: [PATCH 018/125] =?UTF-8?q?=E2=9C=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../parallel/test-http-no-content-length.js | 44 ------------------- .../parallel/test-worker-fs-stat-watcher.js | 17 ------- .../test-worker-process-exit-async-module.js | 11 ----- 3 files changed, 72 deletions(-) delete mode 100644 test/js/node/test/parallel/test-http-no-content-length.js delete mode 100644 test/js/node/test/parallel/test-worker-fs-stat-watcher.js delete mode 100644 test/js/node/test/parallel/test-worker-process-exit-async-module.js diff --git a/test/js/node/test/parallel/test-http-no-content-length.js b/test/js/node/test/parallel/test-http-no-content-length.js deleted file mode 100644 index a3a51c015e..0000000000 --- a/test/js/node/test/parallel/test-http-no-content-length.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; -const common = require('../common'); -const assert = require('assert'); -const net = require('net'); -const http = require('http'); - -const server = net.createServer(function(socket) { - // Neither Content-Length nor Connection - socket.end('HTTP/1.1 200 ok\r\n\r\nHello'); -}).listen(0, common.mustCall(function() { - http.get({ port: this.address().port }, common.mustCall(function(res) { - let body = ''; - - res.setEncoding('utf8'); - res.on('data', function(chunk) { - body += chunk; - }); - res.on('end', common.mustCall(function() { - assert.strictEqual(body, 'Hello'); - server.close(); - })); - })); -})); diff --git a/test/js/node/test/parallel/test-worker-fs-stat-watcher.js b/test/js/node/test/parallel/test-worker-fs-stat-watcher.js deleted file mode 100644 index c648792af7..0000000000 --- a/test/js/node/test/parallel/test-worker-fs-stat-watcher.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; -const common = require('../common'); -const { Worker, parentPort } = require('worker_threads'); -const fs = require('fs'); - -// Checks that terminating Workers does not crash the process if fs.watchFile() -// has active handles. - -// Do not use isMainThread so that this test itself can be run inside a Worker. -if (!process.env.HAS_STARTED_WORKER) { - process.env.HAS_STARTED_WORKER = 1; - const worker = new Worker(__filename); - worker.on('message', common.mustCall(() => worker.terminate())); -} else { - fs.watchFile(__filename, () => {}); - parentPort.postMessage('running'); -} diff --git a/test/js/node/test/parallel/test-worker-process-exit-async-module.js b/test/js/node/test/parallel/test-worker-process-exit-async-module.js deleted file mode 100644 index 38d4ad74c7..0000000000 --- a/test/js/node/test/parallel/test-worker-process-exit-async-module.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -const common = require('../common'); -const assert = require('assert'); -const { Worker } = require('worker_threads'); - -// Regression for https://github.com/nodejs/node/issues/43182. -const w = new Worker(new URL('data:text/javascript,process.exit(1);await new Promise(()=>{ process.exit(2); })')); -w.on('exit', common.mustCall((code) => { - assert.strictEqual(code, 1); -})); From 4eae3a90e8e25833a2f09af43cdadeecda64d469 Mon Sep 17 00:00:00 2001 From: 190n Date: Mon, 16 Dec 2024 15:54:39 -0800 Subject: [PATCH 019/125] fix(napi): Make napi_wrap work on regular objects (#15622) Co-authored-by: Jarred Sumner --- src/bun.js/bindings/napi.cpp | 136 +++++----- src/js/builtins/BunBuiltinNames.h | 1 + test/bun.lockb | Bin 400730 -> 424434 bytes .../js/third_party/@napi-rs/canvas/.gitignore | 175 +++++++++++++ .../third_party/@napi-rs/canvas/expected.png | Bin 0 -> 5283 bytes .../@napi-rs/canvas/icon-small.png | Bin 0 -> 4965 bytes .../@napi-rs/canvas/napi-rs-canvas.test.ts | 25 ++ test/napi/napi-app/binding.gyp | 15 +- test/napi/napi-app/main.cpp | 52 +--- test/napi/napi-app/module.js | 220 +++++++++++++++++ test/napi/napi-app/napi_with_version.h | 8 + test/napi/napi-app/second_addon.c | 53 ++++ test/napi/napi-app/utils.h | 89 +++++++ test/napi/napi-app/wrap_tests.cpp | 232 ++++++++++++++++++ test/napi/napi-app/wrap_tests.h | 11 + test/napi/napi.test.ts | 30 +++ test/package.json | 5 +- 17 files changed, 942 insertions(+), 110 deletions(-) create mode 100644 test/js/third_party/@napi-rs/canvas/.gitignore create mode 100644 test/js/third_party/@napi-rs/canvas/expected.png create mode 100644 test/js/third_party/@napi-rs/canvas/icon-small.png create mode 100644 test/js/third_party/@napi-rs/canvas/napi-rs-canvas.test.ts create mode 100644 test/napi/napi-app/napi_with_version.h create mode 100644 test/napi/napi-app/second_addon.c create mode 100644 test/napi/napi-app/utils.h create mode 100644 test/napi/napi-app/wrap_tests.cpp create mode 100644 test/napi/napi-app/wrap_tests.h diff --git a/src/bun.js/bindings/napi.cpp b/src/bun.js/bindings/napi.cpp index 0c8bdec56d..c06ac65170 100644 --- a/src/bun.js/bindings/napi.cpp +++ b/src/bun.js/bindings/napi.cpp @@ -1025,6 +1025,21 @@ extern "C" void napi_module_register(napi_module* mod) globalObject->m_pendingNapiModuleAndExports[1].set(vm, globalObject, object); } +static inline NapiRef* getWrapContentsIfExists(VM& vm, JSGlobalObject* globalObject, JSObject* object) +{ + if (auto* napi_instance = jsDynamicCast(object)) { + return napi_instance->napiRef; + } else { + JSValue contents = object->getDirect(vm, WebCore::builtinNames(vm).napiWrappedContentsPrivateName()); + if (contents.isEmpty()) { + return nullptr; + } else { + // jsCast asserts: we should not have stored anything but a NapiExternal here + return static_cast(jsCast(contents)->value()); + } + } +} + extern "C" napi_status napi_wrap(napi_env env, napi_value js_object, void* native_object, @@ -1039,50 +1054,46 @@ extern "C" napi_status napi_wrap(napi_env env, { NAPI_PREMABLE - JSValue value = toJS(js_object); - if (!value || value.isUndefinedOrNull()) { - return napi_object_expected; - } - auto* globalObject = toJS(env); - - NapiRef** refPtr = nullptr; - if (auto* val = jsDynamicCast(value)) { - refPtr = &val->napiRef; - } else if (auto* val = jsDynamicCast(value)) { - refPtr = &val->napiRef; + auto& vm = globalObject->vm(); + JSValue jsc_value = toJS(js_object); + if (jsc_value.isEmpty()) { + return napi_invalid_arg; } - - if (!refPtr) { + JSObject* jsc_object = jsc_value.getObject(); + if (!jsc_object) { return napi_object_expected; } - if (*refPtr) { - // Calling napi_wrap() a second time on an object will return an error. - // To associate another native instance with the object, use - // napi_remove_wrap() first. + // NapiPrototype has an inline field to store a napi_ref, so we use that if we can + auto* napi_instance = jsDynamicCast(jsc_object); + + const JSC::Identifier& propertyName = WebCore::builtinNames(vm).napiWrappedContentsPrivateName(); + + if (getWrapContentsIfExists(vm, globalObject, jsc_object)) { + // already wrapped return napi_invalid_arg; } + // create a new weak reference (refcount 0) auto* ref = new NapiRef(globalObject, 0); + ref->weakValueRef.set(jsc_value, weakValueHandleOwner(), ref); - ref->weakValueRef.set(value, weakValueHandleOwner(), ref); + ref->finalizer.finalize_cb = finalize_cb; + ref->finalizer.finalize_hint = finalize_hint; + ref->data = native_object; - if (finalize_cb) { - ref->finalizer.finalize_cb = finalize_cb; - ref->finalizer.finalize_hint = finalize_hint; + if (napi_instance) { + napi_instance->napiRef = ref; + } else { + // wrap the ref in an external so that it can serve as a JSValue + auto* external = Bun::NapiExternal::create(globalObject->vm(), globalObject->NapiExternalStructure(), ref, nullptr, nullptr); + jsc_object->putDirect(vm, propertyName, JSValue(external)); } - if (native_object) { - ref->data = native_object; - } - - *refPtr = ref; - if (result) { *result = toNapi(ref); } - return napi_ok; } @@ -1091,35 +1102,41 @@ extern "C" napi_status napi_remove_wrap(napi_env env, napi_value js_object, { NAPI_PREMABLE - JSValue value = toJS(js_object); - if (!value || value.isUndefinedOrNull()) { + JSValue jsc_value = toJS(js_object); + if (jsc_value.isEmpty()) { + return napi_invalid_arg; + } + JSObject* jsc_object = jsc_value.getObject(); + if (!js_object) { return napi_object_expected; } + // may be null + auto* napi_instance = jsDynamicCast(jsc_object); - NapiRef** refPtr = nullptr; - if (auto* val = jsDynamicCast(value)) { - refPtr = &val->napiRef; - } else if (auto* val = jsDynamicCast(value)) { - refPtr = &val->napiRef; + auto* globalObject = toJS(env); + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + NapiRef* ref = getWrapContentsIfExists(vm, globalObject, jsc_object); + + if (!ref) { + return napi_invalid_arg; } - if (!refPtr) { - return napi_object_expected; + if (napi_instance) { + napi_instance->napiRef = nullptr; + } else { + const JSC::Identifier& propertyName = WebCore::builtinNames(vm).napiWrappedContentsPrivateName(); + jsc_object->deleteProperty(globalObject, propertyName); } - if (!(*refPtr)) { - // not sure if this should succeed or return an error - return napi_ok; - } - - auto* ref = *refPtr; - *refPtr = nullptr; - if (result) { *result = ref->data; } - delete ref; + ref->finalizer.finalize_cb = nullptr; + // don't delete the ref: if weak, it'll delete itself when the JS object is deleted; + // if strong, native addon needs to clean it up. + // the external is garbage collected. return napi_ok; } @@ -1128,23 +1145,24 @@ extern "C" napi_status napi_unwrap(napi_env env, napi_value js_object, { NAPI_PREMABLE - JSValue value = toJS(js_object); - - if (!value.isObject()) { - return NAPI_OBJECT_EXPECTED; + JSValue jsc_value = toJS(js_object); + if (jsc_value.isEmpty()) { + return napi_invalid_arg; + } + JSObject* jsc_object = jsc_value.getObject(); + if (!jsc_object) { + return napi_object_expected; } - NapiRef* ref = nullptr; - if (auto* val = jsDynamicCast(value)) { - ref = val->napiRef; - } else if (auto* val = jsDynamicCast(value)) { - ref = val->napiRef; - } else { - ASSERT(false); + auto* globalObject = toJS(env); + auto& vm = globalObject->vm(); + NapiRef* ref = getWrapContentsIfExists(vm, globalObject, jsc_object); + if (!ref) { + return napi_invalid_arg; } - if (ref && result) { - *result = ref ? ref->data : nullptr; + if (result) { + *result = ref->data; } return napi_ok; diff --git a/src/js/builtins/BunBuiltinNames.h b/src/js/builtins/BunBuiltinNames.h index 0c04b13631..b3cb19b816 100644 --- a/src/js/builtins/BunBuiltinNames.h +++ b/src/js/builtins/BunBuiltinNames.h @@ -255,6 +255,7 @@ using namespace JSC; macro(writing) \ macro(written) \ macro(napiDlopenHandle) \ + macro(napiWrappedContents) \ BUN_ADDITIONAL_BUILTIN_NAMES(macro) // --- END of BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME --- diff --git a/test/bun.lockb b/test/bun.lockb index 592e2bd028cbec1c45bc4a767a5aa41dd3122432..fbf0da7978c74fb43117143efa38953611026ec6 100755 GIT binary patch delta 52597 zcmeEvd0b6h-~KtL({Lh`sU#JWC@SSdLNd?EoGBzlq6~!`ndd2NQ-(}smLXHfJkM?! zLgw+l&2#*&Yo8V8d0y`Kx!>RW{%3z&UElAuhP~F>YpuQ3-r8N;W&P^4&5TMeezzYz zU*>7yvvOSaer8Z+D38=b1G-W)f*xGo|* zvOh)39EBpELNT&6*c@yk{Gm}j8LW75TcIchJppV94(S)?);%O9^aT9E@O$3Ur;EI+ zP-x)q0o#H%gPCv4J%yqWd0_Ows6JH`@8DY~6uOb!MTB;O8-WWT;!|X31x^Jc;>bY* z!+Uw6ApJx7M1d4Z(DOs@-!Cj82L22YFQR{Fm>ZN>5#BwrzuQ1W$iA&FXc;gounk;P zp;L?uj|>S5bsL~Cwb7S!IRbd%SC9342h5VkM)vjOndUuVLdD3l&{^{g5pO$A$c$%+ z6Z99{30wqvBQWE8ftlVCY^8&di-e4j1!jb!BBL>2)-WnEEG)d2LV+JcqC@&C`a$O< ziuy~>c`eXJsc)&;FZ8ShYY=b0hu$ynQqS$dENFCSNRPxC)+KdoU+GVj3}%8d$cQJ1 ze63Iv2bX|Pz1ADOJ{C;Bdvr*T&=`f{i_q)5)nB^VV1`GAMu&xZDimG_XCDZUaSQ7k z)m@=`r_ZM>bhK>6k-b7<1`bdt6w#rBV#0gHDb(-vEpZsk7O?!FP!t3gd9y`jQ%b3O zs8q^*AO}vZBKi!uYLKBym#7a=P<&`eX+MFDa!zFQ&Z6kbymVM@B`5h4fP>;*gA| z4YSwxmJHEg99IKj*K<(HJs{7Y1)uG4Q|J=~dxP1~BA!m+A|mD`+=$FrkELLC+kRz~ z3P*4tm{-ml%qv|K>;QgOT7RXpz`VlS!0Z9@z>Gfv%=YOf!lxl$&UhKltO%~`n)3P* zEf73O@DMN?t{0dyNE^XMU^cKHm{+g@nDMN^%y>OAW(^Z?BF^Q9E9$Ro-if0`0s6S1 zC+QHOH4Juse=sx3b=7C^TyQ3s8Rf;RjCeeeonQ+vPna#@Zv(UGqkD&j;9QC`@Y#~y z9(u-Iso$VTg<>7_#1*B=T7C4?*RXRHeP3u+CGlFRQo2|#eZFB}HUKIupJ$x6{!;r@ z)mN-Cm{)8_49})el!DLrpAnDcUai&FD>8f_dy3)_bk=jFk3L=ZLA`o~Msos-cI$;a zx>l3($K5g{I@B#HMjMPzabYNsiOdrJ(_>31C z(?1$FK814)eZfl!4htRVHYhs$`xp)P(}zDnzV_@I{iCD8I1Nk}Cp=bDe}cG>K|?u8 z8`skN{$Ngj{X_fpWDV=P=;wShv;+$$9Tarp7A<b?VqY%YbpT%oHRzUfBf)AN@LMQ_>uKFGOi@&2V9M{Fzf z*?dqx?|TP4d%rk!x4`j5?L3LdMOWH?%Z+0mbDY?POhr4;o5;^hdMP6 z7`nV(P?IKKw*}N%)X{xP_UvT|eS2A+t9#k^QN$eGnUed>W0PiF&uf7#4n7TyTVC4k zc=SkZCz}gXzFbRlcE9MgV(Ym2ZTeMxaAfQB^b-3c+cZdR9uR)EiKcvbBlWT!2cw5d z1J9f(QF_V)`_8G}4)dS;PCMvasK-moqJw*`9zLSymQ8*;lw11Onv#(?d}0mbk~s>6 zPh$K;U*j&YYRJ}tJk97rjzaR)D*cR=cNB`|a$pNsb!ll5VfmmdDiaf$YmHCBYbeJk zjHPQ;ImTdEzKBsMF=4D$a|K=(ct(l-&9xeDtbA+2Qzt6njfUq3Pm$$mLNyz_^pG`mp3G zYDU5G%*)ewD?E?H_&L7D_hD6+%WnTrAHy^;Gf-wA!Yg~ebn&e_!haa zyr3&tu*A&9a=DB>9_6)494xurj5A<0mCK`f%$CXs^wrdY#kMSzm^njhJOrLxVvQQB z?54~$G1Fh0za_ke;v9)1C%Q^6N+~sF5P4#pw5L{+1Fw~wKv_p?T;(Y*Tkcq2;{;eu zW$QF7{ROmq21|~cFv~|xM=sTTSdC@tE-d{ut@u2z%tK)5TQdWeKA!2HdGT7n61@Xf zb$#ZmeAIBfr3`zeuSWHkLZM}GC4Xs6ePR70>;qJMp@<}SP{ z@Qf3co3xr@uTT$oriuOmT1_{2>}@LcOXGBSwG(rj`D)(7Vtr6Nf33#jwZ5=&@yy1+ zYl|>_?{hz+F@wO!=;}CKqc{4<>O}ueTH|T(sweu@_thMO#Vco&n9xzHF?p+xg<{|Y zE#dLnpon#}nk0D4Pv04@!1GFsuji}D_fFsKjU{DarH>grc1^XM-$Zz9PZjesJ`Ar` zV*D0gO>yidSb21*1g&vncxeA1U(HBZ_2l>o+qA~#;nhyeXyB`H_<#$pkB@wM!K;<% z7vQT}`9b=mR@T(qfWqd(U__5A_mLeSBi2_H@lo1kjPSKkJP@u(Oi0xl-+-sjx8x`N zKt?%|w3=Xe8~`Y7pjMUmN%~}>tZ94#YI7;qMCog6{TV$_Z}$9QZu((<`C&Hvf+FeT z&Vt!cZ(jRhmd^dIM*J|-ewd$rn03B>k2~pyc>!j9QL=B}%`QL86+g@;Fzf2$R#GVQ z%;+EH_V1?V6HH!1eK&Jg>OEZ1dRn7iN~Pp$q4YCa31b)x&0BuW6)|r&V)~DWhRVN@+Lcb&x%A5|hM)_gdrk@M`F1A#4n5%NGH2o<;|c7alY8 zJaiyI_9UYaz zaHwdal*eMe#LNa-O;33GbF!nafX8ltk~Q}+gX0cIndl#`)#Nu->L)+>_R$(%4}_`M z*NxNR1tsS0uAwqR%?qOmf?*7UVLTQa%PvxUVRWIpFx%@*U-R!~BFwgW_3;n0Rz9Vo zwO&p9VLpV}O0QPSuT-?un-gI+l}*iMn6>o9s;AW?U=JGd-MjNIUO+*^uoduvzsLLr zuY>Gmw(v14q*R1`584N>>vyk|rJ)xOuk-h?Yw&(#>20M{wD}%33EuaZs#jLhP#cW4 zKx}F2NbxpGUsYmZ=@X?BkZQ=1rZe`hZIJ`UD{hEe;Gz16tMMqRlqUdOiiuj|Veo1v z#;5vfcGHqi>HomT3=U@(xie{27SneKdCt&Wh1V2eM)C~egne*>#Eg42%wV*X<;*Cp z<{Z3cvWHcG#szy==8d(-HmxQeUL$zC?`l;?tfgIc%9<*zjr0kuS&eUu z&@(HJT{uU){#LVTkVZ`*F}}I4W)mz<#F#?sYK=d^^GVET>8tU?#+>KEFzTSy41mX# zk{nC35grFE?sj#ws;BnSr!vYBs^$*T(6Y)An#B&^>lv&yeh9BR=LwagqcqeBE!@db z+U2AiVZ72&sqmLFoRq^f4`4Dw)Fe)8SsGhwo=ky*3nPCi;ial#QM%L1C>7m*9`q7H z9e*Cwq%6km&x4jDsN2tjjGQnB{5&WGLA=~7(!Z4u^-=Wtc~F^hzbs)qf?EGP)p-Q{ z*K?Wh)V-Xgp)TlINAZY&&1agZT%y(N!h-{P@(Nq??q57lm+xWdPyOK4`5toz6SehWh*=vR*Pa-_9em8-_{l-a zCR)u^cn$PH^Ry}lSE;%iI!BnRG?YBXP1*(4WZ_{%3&cX^0X}Ax^ht1DmL8tJKD#$s z&Bh-d7920&`6g!6_0?3Ytj_=wP?nDw9L^^gn3!ny{qT^1+FhR=x;QFaPk1OensgjI zR!YC-Is%V(82y&y9Xw9nC{&zQ(+Uqo^tV6Udo}am@fLI+fUm{`Pe^zx z)vxq?;4zk2qW@~GrZ2oE@QgWQs?t5BU7lzMb39AoO4TeeGgfQd2cDl?y%bn%1hfyP zw8tWrRbs*%t;*F)`cwte)C4?m!G@uwuWGNCG}H^Ni)HmLu%@23KD8+?oob!8RNWhD zARaRW%6Z~C87IT5FZp?6&VB^bO)dl$WvZfDsd`mJ55@BsUVrSu&;YyO@q(GN_!UNFR44%$Xi-**}4}V_HoU9RUc|dLw(T}Rs8hfScwE_jicc;P4vSo zyB8L#fC&yA;RC#mQoI+Mv{g<09FFUU)%+xQqWsAI61?jAyJZ195#sV2mF}QbwXG%X z^26CAsLWL!hsNjOxyy@hW$nD_lxrnFc+6BIUy+&r680B7u?!!MZIwS~|J=pCngOtw zM#24zYNNmOsTR6T(K=G~+BokpJU-G72i`M|(UVt#W&wHg3GWL*0aA5;Wpy1cGB32k z6hOz84?{MB(j4GKik>4M|Ad*o6+p&fMa~CH4w>7@J0LhP6e<76Dp0#LA4;?q|= zrPCi|6UncR(q6}MjTiFInAuJQc>XCO9@z|-4KREzpavEI#=sJQ2bubEfah5O@E~)F zU&9hH!UljDZ31}wj2WH=khcOn44DN?msLIUggXH8PN9<-Zx28{gS%xGAX5kjz&!pF zHjEIyKKS>7%nf_@yIQ|JU-B~%6%sTnR=Y&9JeJ%m4 z=oNs+-!TiGCCAb;PjF56hRpo3h5mz~8cFNxDvL{}>MG6T*0>`gk(v2jfQcUfJPeuP z4*@cs0m+9UvoKEphCh`<^-TX6z;HZBkq@vGP)})T!$3UFkPk!FNb&WQ#pPgZjOD|S zjiiiF)}x-Xyj%|@^TA=rlvMb^^J32@A7uI_!Y4bz$GSzPs(WAxnyw&g4U8DYuuH z0_qBx%(659Q)(!5vMKx)!Z&0}E%AdKD8k7!TL}&VbI5lPen$r40PFbFUlA$!^-|Q%zP{m&q9i9tgI#95=)9?{|R$k zlo9cN#`zIm8R0CByNE~TX}yF`rdd@b#y$)=ffme&z6=%2>s4F$KVyd1L%505tO>dS z&)Xa>ds`rwDTDaq7tEkGBK+@|QQF}LyFrME{}a}aub%`UnLZ)Y_P`GouosvG4ig#v zjM?j>M7;hY-p`m9W{3*sXFrTbM8?&L1Y|}SCwwwbJYM*J$1Lb1#ADPcBHdKM(}`^{-cn5fip!aGIKcqwgO)gI+^-qFiUq; z=wzDLh5tX`(sFa%L<0Em zwz3Z6zp_et-a=VCoasx8;D5p_e_4@^%zT^#mlL`nW1?+|g$K*wC8BwYXk=!m75>kd z+53oaGUHblTm#GrsXmzT8i09yn}B(c8NZp4*bTvu4?|{z7SI{g3O|@pkcjs)mRB|+ zyaSkKC&698Oy3R6e7iGHX8puyAm~flOGNA~B9eIlBZY6s%rFW%JHTKt{a7$tV3deY zW&uVE|2yj-FySN-VX}xo<_TvAeWuXK%xIS2M4=lp3or*dgXW3wU$GklnBja8k<2yT zM&TQ>Qd-|i879?;5u1#35yz03*AD39og$pfLhTluA;R~Ha5BwI;ggyEfbhu{@Xrb# z+#T+}2>YC?-!a$UFA$IUycF@lc!nng zX82kJkU9T+5k8p-bHT<^?m(rp^rf}3ki6Hz$djUUVt*ANkE3a%{@{*3cW%?2xrYnZGBqe+o)<#uf)QnwbV4Vlr~KxaD! zi+G(yJTk+(2)&!o$&B9%%xZ-T?kmC#SU+h|U_JYZ2tQ-4(gq`(CmbR;R>c1&%vHoB zk$$oo=VyjfL`H_p8q5+pnFX9J{GTzy=ZbJLhxu|aTVR#Y{|o0w028Kwm6Bbo*gvlo z@&A9Ab8(u;=O3_sm@)x})E+R)w^#6fks+D-0s2yQtg^WLl;E%kHe^OS3Z3n60?c*8 zeK7Thj4x%!DT_B^bN>mKXZ=7~Fq3_T&+4c!Sm+yrdD%?B%*Kp^NU%!E?Z7o+ye9Xzi0iN`G0aER_rM%!XEIasE{ESgr1w%w7DVznWhRIkO__15&w)R96b^U_8O9s*V}!&n;9^R8kW zJd`fvVSE}>x7>G=J9vT>?ewJlSF(n^PenyGV`Bmg4SRGXNd@jf@g!7(IPMp zGFx(q@X5?@sqo44mx1MBFZ7jQo@ll3$&8l*W*18{5u-6pMEKue7GOK_<7hk}^8F>V zX?ZXLOL|E7{|Phx5fPuv6Q2NcjdTOd7Q6>$jqeM70A{*JV7934sR(!`__^Re!JIMQ z3jZCLO-7Lkjlj%U4Q7TW!Z!u;_!%?4nTV&+vrb_SgBe%%~o)yAT zMuoMAN2Xs2%mO+Hoy?XhEBmzu-n9 zyeXIkXb$E09Wz~Lk**7vC+a5Bk(pnJ@X7SMgE{KL zz&d8oM?@eqLSNyNS<)!slX-#x!Y4C+wD4idufOYpDK(*h!;qO@bAaja>RUhl{ukeY zBin!S3Y@!L94yA~ci_L@fy?j4*)@N^14kqLeg}^E484JK*6(-V|9dal^|L=8Uh(ep z`yDtM0f*r`akk6P-hDG3_22Knf4>9gN(=|ziF4Wc`yKf2ci`*~cxV3m9XNL%Hn?qb zDfjywxV&-y{SN&1J8;eqzu$qg74SritNLH??|0y?Sb=i#{QVAG-u?Z42mW8)eRGR~ zW7Y3>;J@F2vm+S33+L4O`yKf2ci`+7KYORHf9n7H9r*W`;y-&A{`(y`I}hK9^YMn^ zyKn0Bxj^B&Zysd&zu$qQA$V`*yKf%9-+}*r2mbpV_}{$)ug~G~|Njnr{DK5!`ho=2 zYgO%#Q!0Clo|Bf9DzhkXMYR?+EGK6Lq^gr&_)eLimWsEJxqI*9{s&KvtZjJxMB!=` zMu(r6UA@gNtL4T03TD0<@$q(J>GT+twQkh1AnV4iE?ZV~>-tAAzg<%@&y-0Ve@#36 z((zH>s-AdcIkfeRuCLNm56=!C`2ND_nYIlr+#|QerL}#yEwt0USCjDp8qA1a3w{N^ z77vR#A*egOOPJYHGx+HH6=@UOU5ib*b>ZX3?bT~396os)dpnL^;4$lC#z&{RHrDMz zjy?OlP20NJ=a-%iu6Irh&3({3t7*;EQv6tzb+hLU&Zm`5xz{U5p?Ew#@G^6S_iZORiF8_3FLSw#8$}8Sm zm9*fJs;%TRPGzC1vZUAj8z+~>%;|8^=h9zQ-nynW(Hbq8`m)r~Y4-lt_WIh_IrQ;S z$f$f{ssy#YwrE~bWaFDPOFpu^wBuS%-52eWUmN7h-_yxE)R}$nU#R;y|2*q9+dD^i z-TFM*zv0>kWd@%wb7EH^U7a>}Ojn(4(;>Ks&7P(U|J)TEW89>}Px0?rR;IIDm#vqSzcpSlOsu?b4%5nJ9o=b57S%shEz-Kx?-u*l1)*5jqg7wd*8^~ zqE*M9DFcorTpApAeCC^BjoMpnSAMSKKl_A1@jeN*d9}$u^Yg@yfTOLe)Kl5IP z=ark>ih7__ZhdX+-pjG{y^g`{>g=&GIzH%3{Vj@d-QSFgsnq(~&cdzl29e1SDAf06nl$qH+z)-5b@J^WZ8@aRs0xRCx)hC%oSfsl zFRQat|2y4w4W8=NL$YqM-L|Y@>wPvX-Z#ev73+_i66lbB-l6ijF6}FXZhF~beEubw zPj7vlGhjlt+q~xa-t63D6I^t|%nPmTuBql$Dw?3WInFaOQxUeNk9mybHvz?qeLv~( zQE$rwldY`krN1cEcmL$dIZGR+^gCgG^-K3_E_2m!2OJz~FUhGtd*{;V34LOsn_A|i ztbW_+()gP}m!Gw_HE2El?o{5Pe)7=&`WW9^+l+D@o|RV~d((1etxXXz=e~Iu7roeH zW}O1v(;7Z^o!`Nx?3HGB>Z~7dy}#!Eg#8HzZC1KA-#<#Z(Y2`boW-mD;qd30gDMZL zeD2xEpa%WU9I3SDxp$2bFYnwO?QFkvXG*u`{Ts}(>TJ8ay#KumMYc`Ne)!P7{KBwt z!=;c)!K!9A42s8J>B>9Q@e6~;T|f3_T8%?qX_>d4CHII(@V}pxu_*1TWLAF3g^JB} zH1;B8t~@>d7U>l^?{6i_CxU z?djzF{njTJ-_W^Si~CQlN?Jc!b@*sbmiN08l}3DOZEf*qvh~i00g*NtE5{gjw)gnd z;ALh0ns45aQ;Nr5ETTH5*SX8p?Ifel&E#%WwVnP?QFVC zU7OzXfls@wGgmo8>vY*i?KT`+Hy}A9e*65?c0DaOdnV63?ml+;gN)Gr6Zx<7c2X{j=e%H#W6RVTwjPc#HSf+j)4BSy z zKfYvkXql*UpSP`B+pS8*no&1OT{|CjQd&P5#rrhT+4Ovab&DSbZ>rj1Ziy)mE8lKs z)L`V2rQHS&eBJf%jvdy|tJSkPyx?ZoPD`a8obeoT`E~MwO>Muuvd(IA$!55BwNY!ke7Z4Y()Ap7n>M~*=j1G| z-1*>QyG`-CQZj?Cn2p|gc5=raQs*fso^q>cqf_Z)+;4jn?rPhl#gu(DlwH=8SLL%Q zKA}(l!Yli=Eau*LRmIAI%h!ze99HkqqCduMIy$iXiQKqrCeuf(Rkk%Kp2o0vt}EBH zpB<8RW8U&>_4k@r{95te^@6c+wEK$9-RvfZ1LEu z#gi?S^2b$6pXQk46}?=tn2O>(`CwdN^@hzmyWaa$_L1G_R%ME>3j9*v%3QT)`4yM1 z7n@&jPbNfCcj_eG9Pf>oVZl-p7j;<|ahcE+jQ=ZBV>?hQ;f!=w|*Lx2Crn z-#*$mBEu}DUbRgp-e))suAizXklUv8Q*tP zndwcugS8_DOBpO)(dIMmz1TNw_?F5J0bQO1X1kocY1{g_+X<^PrJn3KSS!V%(Eanp z4zGJW^8MIh(vYMwLr$(*Sb5FWo||@rSA1=@*KppmFf85x57WfnC)a&R{@i&=c2>CM z&WAOgmgx0lcfM)SbGDx=?X)z1+lZWc?QLq*uePA$^1a8tJyAuyTlsPG#>IVWob2qk zr=1iz4aIXxv72J`FmUE9+bKQFcABj;njaQZreDDl)(*+H`(>osPn&YBd2DxIZAhUx zulBWXp)3?L_rd!fP0Bk}U2PqyXsiFvG5V!OLBrxzSk=?Y_Sxsi){Sn=($qfoA*AE2 z?3?+gT%R0V&Lp*npGVD=C9T@;x3{_2@}rO2)%NzAdmRkzlbvZ%xx0CtqeiDnESBu1 zqj*+*uYNt-YTFq1elvHi_fIgdSTg(TjzF*QT1Cp%xjzbnF=?a&pNhnr@yU} z%DTniS5Hmd>P(+GxcxAjxUZ%5EN-T`(f+pcseUheF3WW9*F{qgf< zTBWVe3aRH@Fz&F$bkn~~-Bd-&0f~ zHoDZSZ>-w;hx5}v4T@LTuz07}Ty&VXXGC=qkJ7cO49a;}&acIW@QZ_v&-+}-`{|%J z8_)gO*D`2XQJZVh-Oo`qKliwtbz#J~bB7;1T%_u7+iNEds&;jyL&MvfYhQoR-6>^LysMMD5miC6suef3HtkTW*&p!Nc^31bUns!+)JveA~@@$oI?@wn{OInui)w37I&QDv^Yo2B^ zsL!(YdyWP`G;=hGQ*bk4qCUPU4Gxx%<8`D2h~nUK2~CE1B=-itG~93tgyJfLGk!T zI`2>ijp@_&u(5f&2|l)FHlwFhsFv%u_L=qlm;K(EY&|$;M6}&`r)FuU%XD4r0uDE5 zQ)8FMkogfrE%xohY47!t5?ZL|D6CT)&bKCS$?F?Uao?UR36!sB$QYRs|bR^4i5Sik9O ze0%$CM!%Ss*!3r-lE zWbRaFY1q(qDNe^K-mALv;eI#g`^j;ShV`6&wqWxyNyX2)dAF@=X;9$2U%;1JIA`j> zuGcngoH@c|TGPTKhIV#P71DKyyL+a`g8@mCOUI9$a<}%kuoC&3IjxFqXtZYKtrZV4 zJ38L}+{mK9fYZBnOuWtSpyVx491IIwdWzThb!!^B?Rq;_^P+!xz-t$Cw>b|N=AW~( zY_l4%r#@%D3Y|aO&2!e4fY|&Q4${)~1^&9%B7WVXa&>gicS_~WT@5mJG|YJEt%o1m zMdX_K^)2P;Q+V^X=?!b-t2?~z9_J3Z7B@z8u}lc@)A@VXa++w;TVqyY^uyzmAGp?j zQpImpiSiM17cAk2V)6=H+A!ZE+4Wc7c|P#KNL}X_k8i|uw2im&o3l$|L!! z5lx1}*DY};?>o;w@7f~TeuvY6vWb0PmW!zsP&TYx;@)TGZ|5bM-z~4ZduPazrUxco z>L1cSE}!Fke(NZ&#CcyikguKg-256bYn^-*t;VkCu+Yu*Q~wq-+?|^`4Exjflk1Sr z_mUd!J9;($E6;Vo{i|9O{WJg4X-!KPDjc6tYjD>W^W(SwVUVwrL4kE@*8@S@Ka~7B zY-tz2qS3paJw520<=5w;_S3C;&9<)%FB4eTH+`?~`4)G~*S#@yHeNAiXu`3Yk$ZNp zS?Xt3{#fJsO$;(FXOOY_`rfTk!H>(v^r~D{w{z?BsslXkcXQFc&T7B#%3k%}tr=Ys zyq=F;ryJXCOrff7Lmss{WN}be#?d;ffys(dg$u5p7i5sJvth=cofHA{D%Y(Pa5*IF zh@ZzPv`sDM%?v0*X7NVnyp{W z+S_%j^|C+hUpU$3jJ&ty$k$3C>mQdr+(5e}A)tApF!6}L+c+4kCvN6 z6*?O3=_?pXqsFM(swx^u*T}9$lIK{kn~^k$T**kfL#}KjRUd~(9_1IPETp7yswOHA zBk2j1EGo^$L#bjUEf^1F!a^vyRJ@I(#uNCUWD%706QF2~q)${HQRzHU)kIlMN}Z@` zC(TQOU@-}Tuhd}@gocYDWKi&vG?O8Gpb$A3LM>@0g_I=_?505Qm%^t&XulM~X$k?7 z%~S|x%OJ#0g-}mAPGJWHw`mX>NO993^iGD5O`(zGG97~TatKqWLuevhg`jLIdCUMc zlO~dyOF5(#Qni_&meNd8p!As3O7fot3XRJ4xLnO9>Prg_F8VnWP?)%{)*~X#goyI!@{( zInD=#NpYm!(s@$2Ko$E)S1BB$;I|M$q%?6MgxHM`o>PdDsx5+0eiMYG zMGyu^k11qPXqE&aMw*`lVZvqzxfBLTjTS@jNrSL{F@zz~M+%Q9bY21>PD)(@Vcr%9 z7E2)vlR7Mg&~Ph+3<~j*W*LMJ6e5>F&`CQfq-=v=mkc363Qva6emjKI6h=!n%ORMh zLx^7vVXSlG9Ifac#|Nb|Qqm~a$AE`@DUqpc8pjzL(z6+*i7k-{Siowq^QDWz_MFz+}7i|r70 zOC7dDXm|ob289eslMdkng~)UW`=p%|Qcgm!+W{d{3f}>t{V52iDIAn+c0w>a4IzFf zgu~Kt3Ogvc?SgQW-_=HYoPm%{;kaI~J_}*$ZU`r(tGf~77zMvQ5Kc=InI!g{D!=q> zkE*HitW+%nLizJ~!g=X2g{<><`WuoN(%IDIV@A@gQ-^&LgIAY1x@gqr^2)MfX4edS zIH}Amm%`_Un@iuStmt0yP4UKu)+CL4I=s`$q<(%w$`4+4Z{Zwyj+g)1lH#J_96xAh zTZ^UD-p;Af_uakWXV*@2DfMS&u=nCOt_?N@UZ}RgY^-I|tUyg`-K_~$rrK3a70VxN znw#FT{m|zoBkEk3a#5+jjq3kb)Fs1=L#I?InqWSlW`~W(gC{08D_86B((Q{Y_IwyU zvHkll6+bE7HBIbNYkS0==KHTYeY;e-scC}NLg~J6uw&&xV{}c2@bisIys+ath|B-7 z+^%U6KB9EpW1g;E?+^4(Zc(q#m8b$S^ShPJ-m$Sr#pmA^^bgJW{PobM!fzsK49u-M zG__#qxsNN{$($a&s#=c|hZUDa#)XjaABF|?ozhh4vc25SHQgtSK3TNwT$41QSX`k%7M^$V_`}%%w%f1M_e!h9ypVE8JuLTwLh8Sdg#V})+ z^%u6T`&?kdy{R5U7G0>bcIqYV+fc=&-6_I=UDcrSi~4=nU-mXWHQ{{f zp~D_Vf&EM>yq>-@yLRn!%on$NGnP2ZFym#Hzb?8pVY&B~v03jgjqYUcckJY?G0_42 zKXzOfdSv$D#KhhE-WLmZt9zk(Z?}kH^OKVjqyC7j*6rT5qU}D9__%zwTwoRd0+-^d zVZJw(e;qV>q5Y;gGZSrsHQpU`J?iT`zZP2Ea%)Yk{lNld9<7}7E$Kk={kWqob8ZFu zTX_^poA~m^^bXVPt1me{>fzJDa>n`sUo*`3z=;tN*ViBHe8y?O>>KX)2FJRotE)#h zYq(>>0FUSS9tXB)cYHyKhJ&6ty&l&5i%-p#Wgk|b(P`5S_hY5Jkojxq`bQl zqI~my+KbdB>)R)!3@-d=O0gLt-;v1ohGD+-W*5I1Ja=(W+kk|N&aQ{N$2*@}zk1}7 zt6_&j=a>zfU1f6Z_VtFh)OLwV&wrqM+vm^Lzp7n6t@q7R**8wK&R_Cb{bF*)`UgPS z(&kKz<`0)K0Texe3E-9#asWcg9}o^x$dN1$LTG;l!k~i??n;>y%(5Uj9fELQ8gK~0 z4hokkJd_*{L+E`K!q~$Q9!uvbSYLzSeFVZ&Dd7l&V-)UFcrJMyg%Eok!knWJ{*rPi zl)nL?-Z2O-rJ2VdWKnoa;kD#{9KwWb2rG|6cq_f6;Byl~n-dV;OUq6`ctpYYB!rJr z;7JJcZb8^a;j^SX1)2%)DSv*P$|`t)fuee+TVdP z=nNDiwR8ZAO0AYkoCO=JrD(E=S~@{CRZFGMfz8y?P_jlXT_BsQr3&Z4`P9-Va(=aR zjclQoJTHI?sHI8df@mixhFn4|sjh%+)lx@tNwt(lwo^;yS>RG?sXN(TE$t#ZpypS> zj%q1_TpINzmqER+fy<)aWGB>{Tuv>Oz7BRqy~*WKZ?X&OeFIzp^(I$Dy~(bqcQ)7! z^(I$By~&kP@0(zE)SK*qdXqg-?_1z1YH0!43-u>^qyD$SRZ)Mk7WF6lp#C|kwp?@P zU_DV?Qr-dirgylb3aGhyMnxlK;{MvM_8uu4|r#*dU5u=ML>9(m+PX?wh zbuc<+ta@mb9#PI{u930)Cm^Mnk5vyDWs02M4POw(mr6zkfXgtwt&+O=4?TUct5Hp* zab4U}3ZyS{HL9Yt$oqqX)A4m+J86K*Xu6zN_vol0F`>~h)$ozv!pzH5DY=(LH@xj` zwA5Jsn|d!+af&H3yqn{U-SlV5E?)6 zz)u_T*eH2?Fe){wKS#LQ4}GKkZjhXj_EF|CZ<>w5>wp?@M?I zZJW?oMEq49`Pi=4bn>^D@W&S9gCA?;|54)y3~T8n1wY7$fBf5|irPZkuTLy5-~5G^ zDKyqOKxq6pBb$w%KRGA<^V>n86^3>(?_)2AgjfXPB@ywk(DFUFtH=>k$nXRHXw4u(y;Fc zjZ1vSD+4?b8dvAk*k8s9jVo(vPQXlPl({J8iOT`_)EE}`IJod+L}#EcVzE5gLMsoO zUzy`^Q)n)*`DJN#+FL@a06XuqfwzUmjyg!B%@LX_G!voS;j=`Z*bOifBEO7DtrEcB zWZ-d6Xq92}i=gcB{B0q|a|g!5=J5bblcS+O432`wV8-Kj_+l7{;|Z8%71n>C5TAn? zk;7(?(Ebz}hfNRI972Bytt#xEB3|C-IknJ&gvL*GGCv=nwa{J(tr|36*mC>77GiaX zl|{riLi2?-9l7w6X>Xyi=J@+c3cf()@lC|TpEgp=7aDi2G&!sn2u&%pTF@2>O~ub} z@_e-cz6;`EjEL+Y{y>t@Ohw{4&=w1gmy7WNfF(jR7g}9tONGWuNV6W0EHn$D)o1-z z2r=(tqYV&owb1y%QJM{b6rmM@#zHp&)(EYz&>BNC6IwB7EMODB92zGzYmr}5*o7F6 z?a!~2(ryOuJrECmn3N{Ji-Yg=%ZY7;#!ur|i+Cl4))JbH(Cma32(6^hN>{eUZ2|{JKIbEfVwZ%djOl#g-LXTiE>05|461YX`fS(8>#~JtIKl zR9pcX%hiGPSBi)gh1d}Rx5b2%_bX>CTn;o&vHbNjChi1G7x5|ytur)E9*!V>l9lng z07{|p4oj^o;0wDP+uuWo-5`c?io)S3v=G=`gjPjp-Jy91%}Z!Kpz+g@JiLY06ZUG@ zoS5+6e&iE}!p{5DD8CIWzsu+akzZuxQC&m~gWV1`XDgPJrS1)M6!G|-SZd(_`vng_ zFt2e0z-!B+meBgZE+aI5Fw^!0bi9r{>Ig9sHhVLV0HO7RT|{Vgg%$;ED24%NwR%Eh z#|ndnztyDR|Dfeb1_1o>G$*wNLW_nS4h<8SPSH?^F%Y{#eat|qjmLK_0@8A`wjtQj=6Of10vT0xDU%;g^!QN+RdAjFm;@la^_MTUVw z8^(CZr8c+~G_Hh(19|^tGg!onhxSFp>jaG_9s!)EfrB5{Wy^5rU*`C$1EZ@DN5bY) zuK;j2p(ViPhYae1L!hyrjRKa4410-qqoEx^S`N`LXq>9Y0BfP~7$D+}g}nh9Coo;K z5XZsc8&b|-G0=*E#{(fE@kD4m-vogFAArYXk#-{Nw$M1MO%d88*j1r%vYHBwjX4>p z2#pid41GME{70ksE}7y?5pgQ)(*O?+7X&M&0lNUsU~_~v9rkX32fxtEcr$>N6mUpF zn+f}ktYDQTv{~?5@FH-gn=iyf*qlnKEfCsl*eo26h0xdva{x})oDq{myt%NQ#ALQu z#FL;o3vH>;=0S52S~5Sj#!}A*dI*u<7^b!W;5YR!O)6FhZ6R!qY0i=>g|-Mb$9^z) zmC%x4tJzU-a1vsEivd=EM~cvNOW-Vn6ADfh;!@bjLR%xWWzg7jdGI5~Y=vZiGbJaS z^&;MK*qkYOY!KQC*qrluY!n(V5r(Hu!C|!tA~ReCa41qs6A@R#X7Axp+altn!2XH^ z9BSJ{yj0lP%ml}Fp{;?vTxjVc?OJFOjv<=WWsc@+6 z5gBfT%}IsYUJ-8-Y*vKYKA~-fy$4{Y-7mB>P6CGj_S#G#Zh@T(u-6_C+E&;>06XJB zp>2cBj!Ny2(6+;_Df-c2Xe@s^&|7FnMZ6u**r#+$VH^|UPS~7umVu88jYE!;4v!OH zX1E*ZA+%E>9&6SUHq)LKS_bS;5$_C`Y4-x`tjXYWT>qh!6#D?)HkX6XgQ@KY?lT3B z3qs3;ohY=6LOTF09vUy#C1^(AgFszT<15gZEPuM6FxLF z-OW^Ouhaz~+!E>dWy^v$09*vPZ{oSH955Upmw`V34vZ|dG|gOHOm`DD`!M@#4sZv!3)}Y zPicW=oV735S0)c?9^cMNLc)~0TOu(!*1(*i#t=mjs7QlCr zd`CT33basHv0Dj~+fQycQvq%54E~6<7vnWtZI&Go0bt(n3Hzts9fVX0< z^|@q^0{R17ZpTO#7>kx%hjKZ==(&_^BfciiKpb^j*;3lsy zPy{FnaD!JI;KzFN14j^te=#Zz;GWJHxQ$W29Y_au06T$Qz;0jLZO8 zcpsYV08j#UApZhbD;UEOIUX1ca3k0Y_>4~V75D}y;Bzxr5@-js2dsgjfF)2JumIj8 zZe_4L-~o67+#K@W%Udn)-&{Oo09wGu2S2!Qn+?nXrUP6G4*}W$ZGrYc2cRQR0I%C-}qg0k{R@e^k7SmURT%0}g;4PzvCV>MFwcJ5k&< z@o#_~1P%d5fTO^1-~@0II0c*mxO2JyTm-o3i3VbTa3Dfe5c498egJnmo28e9&?wDd zb^^G6;eMq7Pz|UK_yRS6nm}y;e{)*?W1Qu|=g>~)feXMz;52Xs;M$1mp78+pKu3X< zz-nMBz*QX=aa^<|@_Efj7^8sEz!+(crMisnBg{v@W8e;O4Y&^600IH-pSXi42XNO= z9^g*F5hx9CgAfYv!`l4bIlm?`2|NrO0`3m<0D1ypKySbt$Ojm6n3=#Z1 z1$=;NKy_dwG8+N#??Z$GD!>TfZo&%i0uG@U?FYDG zxQQ!>uiYtb0Nf1lugP5jxCxlcKlvyD^CY*z=pkI&^9zYvk!CxP4uk^SG$epW0d)X> zAOPUXbt1rBESJ>d0IpO&gT4SyfhWLS;2v-v$Odi#w}4<=wN3z+=bomx8dYHM``P^H zHrMA7KrC8!B(4m^H`L%6@Ephi_+{~~fIq;c zb^|~Q@RR8L2sl3!9*4s9K}Grk^^i{^pfM1R0=ClOM-b2)cm;7LFbd$3x*HPnljlu= zW91mM1|EG|bypaftCFdsfW zsf8Bu1Nes|7`HjVFkNpnX;;7-Z~;;fX(_M_NCqN-&Ok6w4`={X20Q_0pd3&fC<-t` zLxiA(=yQv{1t^4?7X^5UD*^?1+steBziV;@GRj4QuRs=%gG`BSuy+ExfIYxIU@4H7 z=YMx8GnB}9r{rR-Zl{Y!err)kJ_O-aVZq&iN#Y9Ixe z155VhWf5y!&yXrU3X-kZ%jK zfeQdPEk}Sw00;XRAPVRUaA6h!aFBCoaFNy+;M%MzPzB&_WG^nL2e<<85>;rVRHTnC zp-#2ZeS+rUUWB{=7RIn3JUKJWi^u7Q8PI1M?u_%oRIu6AKSSrV z^bO4M#Odk_eBR_awm8nd@}8KN5ld)TI%ddu&lJduqcO1a8Q4r~A$+!uVPW$sl~+Le zmWV^P(uqWQwPlktq7B#@C<+t-7@4<`VnAUO-U=|xkT&BOG7FWb8OCL0@(QWTOF)q) z|M!v`hBL#wmMDj~T=}ymWW#jj;ky8?Kt+K6tA(q2+HOEH3hxeHgxN25fHUu%^)|;$U#* z8UcjPx%TN=k57SH^GC@Y?A9lWVgZIqU*<0?c_Ocp0!1;2G+n zEx5W_0sks^IXKxMd#HQ*|c z1zZ9C04@WUfQ!ImU^n951fv}Cf17y(`yucExCh(??f^N!ZQvGAA90!PK5T|P1D*oR zPiL4R?QamB!3j9SNZ>2{kHBl-Gw=a;1-t~_1Mh&hzzg6F@F&3ZjGq^eJD*tq5#I1xJ zj`rg|+yy8J}J7_>8B?h1MP?11z!U_Oim#9XtXVuPwd}=y)R^{8C^cmjjLP}Lt@ATxVYI9Zbi15h%jCW0w zy(l3$%1Wj5s8qF*yHqP$T{%6=N9`G>>v;>=pid7x8P<39id{!V6eQ{=LeAB_?E5HU zj_yZDEJE@l&5(%Z;X6{buYQD#5h0zL2Mk?aF9^S8AfFJq%|M6+(!7lDd0;$g$21Y5 zLr{`PR4{k!saNBy|M-z8RV3Pb_gGy;Y_EtPA=?pRiR?aF486MVz#*F-AxA~X$yGHr zTsyGr(2tNTgkUi<@^a^n6Sl0KV8;+0ngd06iXg0UMwUCA)p+#qgV8?{PmUMm{u@VI-|A0b`{DT)y9dj~vwzc_VQ zrTgAMjS$4rIgZ#?=(G8tem@d*LI{hn{e6&g*W&$4{|MG{irqPP4ANf06B ze3MsITj%KbBV?8cxfJ$tg|4zLeAADh9YouZ4&YJ6Q`!05JW0kUt=#N9AdMbG6 z+^XJv+Mup36G2rfc~+_9qxkiR_;oM&b#wo^aB_uoDBXXpQC{i(N#TAyD1R~ZQ2V4? zI6p`7KN)(zZiQd>g1-!SVX*OZ3YVDSqCj zI$rTccjd+G$nfJ^%cafB{qmo5tzQ?r9dgTuHr;hUs;0^9YsPZVa%Zu-i;%|4Jc~J| z)gFit2lq-Il{`EZkqFWtQGU~uFuJ8BN5`otg#A4h%K@nl2C7sOX6&vwF+~_x;h*; zYJ{A8Zrt9#+`g)Eh&&;NhlYk~y}cA;+6?;I%D%3YI!v8U7jqByZ$xkXa7mkxw3KIv z?p_I5VYP!0PVSeRjC`ZGc^~tTd~$^RI?X@6hUlt)(^>xeq5e+>)6cq*xK#`q7~abh zMQQc?!Qx0WyPzL+?H|%7ir49^i|zGC4HrB>2zqNJ50C#*f9>BdEFuQErF<|gKHhp_ zIov9`X!Y0aA2%JciRd31=7tP+H?y*4bN7ZkxWHZR?KJ4#&Xsu%$X;i6!A|M905wkh2HN5~z7a1Lo7J-yYH023@1 zFh+1s#;!=@cC_pw2klUwYjTKZB@8vgcB%cZ_v(3gAI5db^nEinbR3!CFHVGsCpNOL zC&$m0x}n}j=FfFThe|s;lb$tyTt=`k(ZjU*~36bc2%rzgDh4E~+YvGsAnM zk|N5W1I{3z{IDE>ff*Dg#YW>8QQb649nD=X`uu9>x#ZuY}O z@v~-uZlYC}d(S=hynEl9Dr`Ex znCZXr{4%wxq)4Z06}qPUvWB{dsFbMprdIwyx>ljsVV_lI^@J=rv24u~PJ17|lG3rSg}7%FgNVb* z>zl{s{`p}%FGw3+T1eMUj`LJ?%JlyoZvVH>4f?vUid9RGK{>M&t$1899kx~$MR6CL zb%}buC+O69mni8yVIoU??+Nqu;g_WVXH~@<`;^D$PJ%Gg2s}z>giN_i5u1Q~^?Q1B zlc2M_`Mu<0wXU9~j5YtV@i8&6AZf-G9Cg4~E&O%al?u(?SWx6ROxr>mz^fnJB00wo zhps$2GG8Y>u9(nBNM;M2+9a6NxhF6K2oyp)bc*H3DL}zP+iF&Q9 z&r?OqHokv!&q=ik9T{duH1W|-G;uRz_4!w=eY3D5Ec8p2if*eD(nBvGGqq0WpS1&b zs5&U}P}Kc@Ze21jl8c8wPcy-_v(FLd*S>ardg68MXL7^v^et)?y#?mbexWM*xK6Nz z-il0Wy|5`X6Pa`MLb{<5M?@@WeQnF{j}6dWm;i2sF>Ie`1|(w#m@)(vt=u8(4=oo} zG<~PA-0&Q}nbLx3{fHMm_eFodTEJs>#;}axIJE7qqWHf<-)(@f>G|s7A8F9@>-H;< z&p=^4dHJnI=hcGzwF>1TnB9z7-9r_EJ$k+&X7x93Zi|amAOmDde$Q_f+8&yHmqN+x zp`z_zHcSG9jYrMO55GKq{Ozfqi+>gNQkeQdfx;eXa6fN3Cs0qxb9%{dTL?RxaRp=aol7Y1}_8S&yA$UT`>N%$lAUi3rj-P8ZEuD z7i+GsmcH8yD@@YT`=27s)zUNj1RZ66B1}?;Mv)7Z^y()sx`_b7;YpstsmBl;(~&0J<03*JMcrPhAxwr6I+<_-QxD+?#2 z(X?Sd8=Po*w?T*!u|O6?)2aP}U0oeb;~OA8F^1+gU{rSC7K+)>wu+0BkKEaoD~pH9 z60?qRTnCa)H()U3f~D(G>Us>Mp6RIQfRL%rgnwaA$}cb4Hg;WGIHIt5W(*ZH-D#kj z1JLkO1ATn}o~ToQ2m8QvPAuJf5PkU6fM1}1tht&;R^}{Oi{mrDcU{;*e>ezhDISR5 zD}gT`5+@Dj?_T)L{EJf`IignK5gL&p22(N_y%~rI$Qrq2q4CTm4|Y61LbfB>;!Ns0 z;^@++n94tagZbn8&b&T-*|c|lgVxhn>|+XfK8{9z21KKb_* z2;G0t3$2EK4jFgIGUn(;UUfYAfIUJrItR}KuwDr5<}? zAgtNCQ>NUHhJFNz`IP*-)=wJiIPfclDQb}94bJbXdA2sDZiYfJgQ5pd=3i_bRHQ|RqOSfx6=aM>3e zi9^Ppu5f+9j$+tagn``(3R~d=b}ycjb~Rx;C~R-Tipoi$R`BZcfncuUY|Ds0E}GR` zA@jma>?xG?1ygk2SaB$j%r)rV z`CG(2qe`-6B&?W=GU-3UJ4nnU*v~vZC28?+~)E3?I)aJVfYar0*E7!6=Pz`rC89X&wB^+lus5nNt0a z&yP2?q#lBm{zHX#x{*9bFpqK{)XhWb18}I@hSGKP zjV>L5_ZS0qHietBqe`EyyJNk~j?sL;NO@nu&q=9?u^s;k>{9tI$~h{G=uGy8qX5a; z$zYutx?DXf)TrfgwbWxw*jZOX&BW?ct7EqDX1PsuI*wV)+GM@`GAZr2ut052r<&u? z^4})XpFqR+WRT?qI{ionJ;u`FOnRBsS7g#wR$gSLZ&B8NZI=3-+im;R9Zl~%$Tmvu zzCx~ei+)4^M@PBc%8?78GXGy(jE0=ykkqomv$sV^b~UV!Syh zGZP$GeyTb~Lyf>5Ac$ati6%;kCazC8$;EsUxVM2^C0}u{1oJb~j;iUd*O>rv+Vm z^hxiY#zu89oA#X+R;YW7q>?kjeD&&)bny(hVnnki+>RXjj+L=7cRvT* z?$NaP9B^ZD>4S5qzdM(XoWo4b$)mjUsDCn#d@S9cN9)dGXKBo%A5qp{8KVkGz}TI? zcXsGK`O9lDc9?$iun{4RaWw7%IJVtR6)e4bEN!?T=x(W&FY6T=anWNbHUE=N+E_ZjljWUzpd+Ox=Db;s=HlDqmh`%q`E3J4RVf8mc z>B%bG8>Sjl+4Z53UziN@70=FN#neJ~nN7+SIqY^R_n6m+Q@{2+o(bFY?AWorfFsTJ zJWf$%l*d_K>~I;UIUPQU>Ty=dHRWag8eUQ8C@XZzt;<}6Zl}8g$nEl39j;(T_e@&{ zRGC{=SQb>|@OqrqLP>g6YJ07(qywkj;VrRM25Vt=I)bH@SiL1d8qBbIrw3Jd${eot z{_@_HmRnsue6a`EBn-5yL79zx#TUd{=Jr{A!BxHz;7Z)iA_?fL^w_*o7RS|2TC-d< zB=PBEMK7k7r^?*=9Ii?}lqPCw76#C}siF`mRRA17t-oDNj0|XmQCVZe2y`$4q51i< zqCSN;CU>D-IealU~;-D6{?AX$ln`ueYfK$Ei+uht~T2R0>*mcq@;RCl|WG)`)R znJ>sJQF<*{R==ON6v#buE(dWi#xvj!sH+rmP_}wy2rDy*p4jj$1tk)3Ko;M;8 zGvk>I3k5ecHkXkPOPS4DWSs`Nvux9tNSC{atoMt9DD`o%N19S;Gva2)W}N|vov`?+ z)Ko7fW(0@_JfLL6Q!t_%wp4j7?50ejQ++Rup+8egscYw@(&OUbB>83uwQ|mg(+zlK zNb}fi(~Xi^R60OoFa%UM*&qa!$+}5QHnfi$$N{5hij~(`aaKsMu3r*A&$BZy}*7aCvg4rwHXmWf}5?hMmL? z4{o%23muN2nrRM~wX8Cz3Wxk&Y)V*P$Vp4q?JDv4Jl^b7ETm$G*GH+XLO8`eCu#-< zV4%a#8KH@ZCTENB=8lapm6;dtE5{_U7~jH{2P-ftEy)&BDF2esmv$@?6Sztem%YqA zgDr3ew;(^>W(=sOr4}(!ay9-&r2cknTB_wn(C3gCe_N1Ve9$^_@Jc^JLTuoCusxT- zl^vKHL$JlLtxEy1QYRp`11ca^;-JAnW+iW(0XV*wa-$j)ge-EfeOCcWPFhKq6i6#{sa0`=)GCU)>|7P97xgKB&45$`r>EM_K_ny-n&X#Nc` zj4H2*5p?nza{I1{(NxeX_M!ufiaHJDwc=lLtC+#S-Dv4GariA|4sYR1OQx~dRZh>f ziMMg&(12QKRA_b0w0ezBhpW887(n9thy_3HF2<4P23l^oE)G#C75!NgB4yqX2L#k| z1-UX|6y7Ed?3ART$J)gBj-+r(x-J?z)@r1FzS$}!bR>n*yz4O&4dg|NsA5$GiwL*1_0Db_Qb^n(X_Uecv;fA{k@}gHqNkLl;V=QdF`xWRHZR zNQEdnS+cbe`Q0Dqb&Z+#`|aK5{r-GEzyF+@$Ln!DAJ_9*&ULPHo$ESh&T;)lo+BSe z%#1F1``yzoZ|LctIC$+F>k?i%v-IaYTL&$Aeo%>m=OUW7@P4y-Ph^Non|D@+g5Kf3 zdsmK}k-Jnox675;gKUl`-^x=g>B0$@>mi~~z;Y`>@{I5Y zCta@Ga9(WbV^0P39kA@)iM<|=AL4Swoet{b;VkH1!-^jmpV%)x#^oAAA+#cp$I^`5*1 z+;xjx3l@|MCWCRml2!!_xgN}TWUqk(kX%E1^&Supm$?zt6JhOW{u{33(vkTyt@$OW zCtPg{Dw{u9h5uv7XXLLJz(g9n2tPZS#s=%tyYzk7BNwR#TZE#QPdy`ui zD3&cOb1<35@(-DlrxYmA`kgFpr>AeS?UG2*LkT~h)$JVURC_N_i zC$-=~wgSZ?gWVwv)`)N?UofBbu+lHJJO<9}YU>)8>Ua@B1s%4$+d9s-JQ!BPCiai- zMOm&X*gDg%6%6u_p@~lo8|ZTN&zGE7s93hOg@fHCPgL-52BMPRD^wt<5+jzXQ3O_R zWtSbh&cngObraTZU4+$nh7VC$F4qxk`KQ3z{l|+1cWYq6Q1t@Ws6l;1uD6L-v&}3X zOy7H0-@fsQ8ebC2_8r1`)1*YOpx(U_o^(wq74(ZA@^oUtz+SFwrGxnfEcc5aT6S1s!oAb2Z5hRL-hM+y>S0eO z4(g{fdXz12b=hD6BYO=SHGn;-938aFz#7S(j(^J8#ResVBjFDAR25Au7wmDnVYN_v zVxmsW5tH5xjL%|U5EuB8P#k*x& zC`O1X6}la(J(d}K%2PghT)ogh9xi@z_BzE)!jd<;&?DBrS8>UE8^;AQa4D_ic!hV5 z4b;by7uBd28<>Gr4~r_+j}08fQhvnI2)Ve#R!YuH4owKvaJ<4B#s(%~Rl)KlE5BV> z%FmU<;x8j(_<2SbrE-2qdJE}Ayq`C#*r-)mKU81<5ykB;*!J#VJuCi((O1(Lgx z!M4J^Q_>J+}eZLH_OPi9YqyM{k-!R2aU_C~nl{2d533kKgx z3tmYJ#$CMU@FKw`LErrZ8wG=TF5L_EN((Mc3tmeLR=a%9cYIoKcUmy~XBx%UEG@V& zEqE#|Sn>*O67(II7F?MY{PkWiQ0;2)5c-`?FvwaQ(8jUe#aCS>Q$cri?`Z-}2?Q!# z3w9EBa(L@l?}%$I^SR=;5y(`C_%YWx4`|hl$@?3|dOyDIGE*gAM2T<}m36IeP8GbOib8XI^Es}>fg8h!i}mbw77Y8@NM z_nXUA9?PA)e?V-YDORJP)v9VJ#^X*hb@Sh_+Q>4ka=5E{erMN<(gq6%G$r8Q@rTRR z-83&sABwu^a&-&_N2LW15Nsb*OWe8_980imP(6?qEcU0%)jFt-AlNb(+(odN6Aa|I z9qiQ}9kIaHJ1$qRU`??K|CQdF@DJ80tS0Ujbk;_! zZujEyxZUaU9E#QMUfgc1d!C*O9@C^W=i5wXigir$((X9V0gu@uDZpItQAY~AO0YdS za7gGV*Rj}td;?GW+|B^XPEU{Ze~eWtIrFl(z%7NGB6YMMVe+Q&#pzFh(^!?9%yjG{ zm{B&v@;W`C4^~4bPCa1@R!b+Y)sWagR_2(^9ZPZju~Y&l!1~z0My$qIuH;rNVmnL}bwJ zhE$t!bLQRNc z>~9$Buf{~UYI5_oae={vR2YY_YiwWzmaZO-SKw!?;Prwd;whEY?5XS?>zSU_G^yeq z8#tEr-i~t86=SNb>ydL&_Vf%hO=4;3SHjGcSoc`}X<}=e>9Ou-14WtaDpPi6bZmGp zEEVWtbAxipwd)nv1v7jZljgqnjme(f?dth2FUYKQTIXl<-f*l+E$) zVkQ&Q`MzmR-7m(BYv~Sz<#f9`-Z#x$V%pv>#uJsxOo^j6KF8!-4U-{x)|*vBnbFJO zu)LqnP!Iq4UX(gZsR&L`$5C+uu+*Gfd3#n3y=N%uJeJehO?Z^MYG|I|>4oD_$50-e ztsUsgL@~kH@TiYKqvX8};{x?qC+Mm{XKxW3n2V*8(K&5BNAsE{H96Ep@|h{(T9IZC z9GJt};jv(*RPz*;J%Lr}{B(z4e!s^Co=mftmVAH}m)yKjT;Lob<=|Y)0#yp!JK-9| z2A)l`$YCp%@}t{wBD+~k$fAC4#s=zO)xzQwp_@*?(nW-67@n)JYGP5snAkv;Lctbt zuC0N#Si#|lIiPS{R1q@; z#j~-9*#igMOx=|_gAQ7tKbHDSZnHl#V@BqpZdWTzuA>~V?pQkXHu7!EvY4Toe|h#7 zHBB0kUttzQ>I5#Gmw{)n)b`9180?*5-KvISI0ZP4pJORYe{!qSRYOY$qv$Bi zW0ztvi)kI_IaS&;X-<D1I4GKFhg%137_z zVL7Y>;?+*Nx7qSt+Yq$<9V??9Km~mYw54b1 zI~_I1s`xHzi)HVzwpjKT!Tl#-BmNUs!hP0Xtb)I^wpe@kHBg1W1={`{w^M{N_)cDI zVij;$23vYohDROsA6fd3K=~X8E;F#bJGZlIC$J=+1adnAw54aop9SJ`KwElNbyyEO z@fQ@yCYC?zS*N;}VQpgRKdWmgaK#E&VQuL-fPK?Z|B;pMmetd}lkZq{_22a5k}Q=K9ViE=-6EjH5IDJ6n2|#AxqqV%32$*I`CHXG_nL81bA9 zuH*EEN;W~PjSwqX)!Jg6;I*usp510(M|W;Bx}!Vv-cN*C)6pH4q`EX9iBdJRNyQo) zTUa|iOL~kSaZ4L7R)GIw>?OwySWW&Q5Q z4-p@2^DAfl#45LsZdR zwpi)rSUWu{{amYy4L042bKkD}pnhGd` zJW~IORd4~T-;Y&LAse5bm0w}2|4-a5y@N6=ViSs$(ZiODT0K2$@Q$&%SpF4do1(p0 zAt}2mHu`=n_gEV*mVY(Naj-_T`mp>Oz&hehU~OXgH?#JAILUEnfrETn@uQ4d+XVMx zXZmF0JHiTfvD_V2`W~VY!m#!tpe%4W}BRas^=~;eHp{q*_gJlng)dJ(K zzgQKRVD0p*bdzoT6dON9T}uVdun{wDgjgBPvOL@B=~)$+gRUrJa$JrsUZHq1u#dZ+a~6JN-NlMdvAoXeV%6(o%NuR{CL1qSaI3Y&%4eIk#p<#9 zteuX7qd+!jt=R{uNJ zW#I~b%IB)}PtVHly4B$(&e;5?6~sz-8&)rJ)2U^9)VcpBHWT|YS5)uKY?EcN$;3L% za#%g5`=^n9mdRD=4Hom&AbkMP;b-W*|=1qy`mQp`=Ze1W;EgUm{f7TExrj1RV zo>fd+bhTq=SbkltpIGtTtlq=wV)@6z+O7VUpS1D!;o$f=&^p|YH3J+*yb65A@^I__ z->~K&lWqDbmZ$pcrFp8&P^>+eWo@zcJlWd!W5v(4@nW6+Z^CMU#a6!`E8V-1IB3t7 zSYB!qIBYg0*n5EQS@}ObJ?~igE&5Y=&Y*Y_qo5ZKgkAZz%1s zvRH0AVYS0<%U{@dv4US&{cBjwa8TmEVdeKN@!~_)FC9POWN_FyCB zuzb?;DI1@j<#*b~pRw^`k2%Kv7FInj*yxKkIz1OO)t{tU6qALjs9WTNb$Fs+XYmLt zJ_gp+tP!m3|B!w_)xU)m z{ND0$SbirgpHw89So$ezpGvaAY0GC|Wqi)s=dFDK*7kR-9k_1O-LU>*75Iy_#mfIT zSW?oT{L10B#NvVPV zCsx4)$WWcGR50WJh@Hi88JplgVeL`0^%pzC7p%)`Jy=rTvvxWTo_`Y5baP-OeA)6mSP5T+Rp3Hc zn^=4BhSe9rO25?dN*lihR(>DB+Qdq?-rDO!C|?C^LQnylt;06!@OP|qpW1XgVHLE? zrV}f_-PRV%-UI8j`w~|Auam69*Vf^nwZ*FGch(lGfWy`nE5jq!Cg`ebp+3|^0$X}k ze$9c>wE)_ZQUm`9D}%pz{_AAeo?lfo{bOH6$kytsFNgqR0b4F7pq+T$v4i~J`L7=L z2G5PZeeSC^+Xi%Gb^smPPl2}dEPbb=K6w87;Q8-e*MsN3IvE~3|NU|Uxvw^{<~0?qEmrWs^WUDfB_2HgeenF36XL=1-}KLewIq7*{5Sn` zUmCK8!Si2k;WM9q@cdUN(1Yi{51#)%c>ep~ z`R~7d{#)BVzy04o|9$b+%kGq0FMDoy%*17$rl#rwPiAwBkd#s%dfJ=wQl@{1@~g)j zkuvWUlK9FW`4n!^(2y@OEwV}#sh^2Z2`-bJ`9A&;rH!PCK=*US>- zGe3zUP3?_PeluTGz+4j*G>tbwh0G#RVRKUyWm;{9ikPLMhmCs+RMd156*DVE#Z6!< zRKoNUl{D)`rA+uXsI*BCl`-2yWlf$>plCB#RL<;%%%tU1wd{7PTEUFmj!<<4!Z8UI zP01Yy=Os+vfl%2TmN0K6LiJA(V$I}F5gM&RxGbTXskRg04+#r*BE*@WBrI8t(EKxm z>Sq3D2p!iT+>ubzG~R^}x)x#CE`-|Vri678y6r}&YnJXt=>HKy<~<1YO{YBw5h)0p zBs4UE&k=S>82C9tW3yhuh;<10zd&ee624%ko0)B*<|fZxsD&9Udd%z=wKRqIL9NV4 zQERhb)W($j5^8J4i`tpPqV}f3S5OBtS=7;-5Op%u_CuY`EKwKplc=kyeE{la=8L+U zYoZ>e@z+pKvq;p-+!XaTtqwwuo28;Y#{CTxZ#s$knw6q{Ch#rP-}DkCnDvkuv0c0P z9lQ9XN%#(-#14eL5(b()hY$`)7;^|=kl8I^(x(Vz4c6yXmE3y&f^YkrcjWH&5mBgzd*=*9ATpAbex@j!K@U$XaXmo zNv4-*vRN;hV!}^CQ%!m` zc+uRT%gd(1Su7K@=9v>%N%QSpRZZ}HAL>l01cGjk(rncgF3$vyLwE6`%1~>-~R4osGG;>$@Y{ZXMX) z+QT20xOr5k8o!!8<9R1v{V{ysz(M8C^_;bG&fL(}1>0=QGU1t9&3|q1a;=&_&K>yC ztry!5o4_Akp>eJ1 z7pnH2o%wKVw-wiua?hA>eC=m9o7bs#tkM^6mwI>Iv)hh*USWUN8Z*nq4E$zujv~*R zmPey1eD+-Ox6=bnmoIW!!WF6tzm`5@mpfOJs4~4St*Cst?v6cK|5&~JX7*~WHthT4 zEAzG-LtZPSmniiotAwz;Op_PO*qxAL~`S- zf4>?B9P>>1!co7@n|8X3d&x^RM;r|4oj3E{W$$k38GWHz^s}~4 z=sD}6^cgQ-xFconx`fe9wlzH%AH9C)+b7-%Pxm~Uoi5y zQV(ZNs{47xt;0_K5Odz&@YAswD!kGw>ss5y%J|Ln8BdvHiZ!qQ@Wr)di)86r>dnE! zr|#I^Z^#b^`w#!{@m1f<{^82m5eI4)x{-fC^QhA+KAH9W#1adRF1b1hGr}@6_-BMe626hJ+!VfoFzI`QiB}L-n*9>09!02p6=Ag* ze-+`pgfkM>nhMtt<{d+rdkrDQoRHAy2ZZ|95!Rbo*Af1Z@T-IkruGelB|jo8zJajG zT$9l8I6}K$5Vn{_zaWI3K=A*Hu+6mk6=9u(wGy@)_iqUOPa?$shVZFbDIww%LeAfr zVSVN`y?JO^NExaXHbgXMA_>#i8oOWo$)+m4&L-M z^L*(wQMXVgoke;6778y%9gtG>9H}b*Nvf~CX2PGI_MU@Yb42`&*Tme0zxA3a;_tlX zr1+56JaPv<>@~B+N4%!aEAaPTb3yh|?7!e+Ub6r;9WPSCoxdpIN3Use7bWx(%CfsC zC%opClyxX`yLp>>PI>3P=WTELU&bS|8{v%Cbatae{EV_m$~mve=t0>fWuOP;C$ITf z%7`l{`MoF?z2*roN{Oo|d!=0Vn!G-gLsG{0P_FQLn3PG^P|EsIu6fNUKT6f>D95DS z@S0K~DCeb24?+2r){!#r21@k|D8JJ_8BiMif^u2PO3vIiW$c|eX!wx$#32tCPpQ$(`=Q%2 zs(8xJ-Mw3vn{hq8z4h~}6G|a8I!DH>zXwnMungwga=sc-3^cs(dpEc#{0#Ao63(AN zJGQA%-j}`la4RddZY*gVVKt3b;f~^RjkKDcC+m$8ZKKS1vPgQ?M(K}Z3pf$HDsMIY z>2MLNjj@{kM!l5P##&AHhRa(m$!dB7kWWTA+c>MKihNbe*~SO8BuKZZ-WGdR4oke93Cr(c<)X&e~F6 zRLw#7QR_I8jx>id@<2vX3MX%l*&^FilfY zS6)Q7O{}+Fm0>>MwVK{+l@%$~m?WO^{TXf?%%IGzXEE zREQsAMP25VxG?B#HC>|R7zLVIO&3A=6#rRQmd6DocfmEdsb7Y9BK=G-)g)E>GE6c1FMxm z%V4!-dQ)1pE(RZZH z(H^myc1UUU0f%V9PWx}RBAJxs;YKN@WK>PoW6%SjnA&&1_?FbtG^x$tkw)IOq$wXFH$S4cM$lbrjz)L)motO`Ala!YqiI)BCK}KYAwRR!VO|0+OsUZSJ_60F~^R_mnwZ)C;atf<;GM$>TmyVdxtuos%LuqSv2QG?4JtMwwB`gZSM zX#8{a26_itn;TZz$3c6-8gTTQy0ku^6Jc#$tHl$}Yc(IN<)-uMM?ouwNJQ%gqO2AQ zE5rVvh}8mCOF+wJwTxDK0xi4MG^i=Wiq6DfMmnfrRxP2wl6g zSjVRb_eawpl+|kLSl!Vy2!&bgX~NafG~k3=Z7|_jG;OM=Dw7DR2DK!orV@vMiv%S;)~osfcm()E8MCQ%^*u7zNQ^(N zqncOoqrg|zv8c`PS+s)`TpKQCwb6vXM5_bqb$^1cF+iW@sSB4tQ@yB;dUI*x4*RMeSZbVgJlFX2vxJ%1j3!sGzh78=YpRDJ(Ym1C7Q~69<;Gq zYnyf=T01liOi695_yR^{L=8CV-D=Gj0iPe$r>k8ZtluQUe0S8*I$FQUXkP$rU98^} z!s~$sq0}z}OeOp=(59~hkWG?n8phj>M2E78r(@r+S`VwegssYHuP2vx!TBub0>av!vf2W|ZxHSU53<@Tgcn)u zX{)`8rsmW(7}g#y1QiJPg@;(b*9ga0Kh2a>Zqn=gl(gb7E53oIQ&FdoKCYk)7Xh7i z(neUnHwoV*Qm55O>-QGnJ7_wqp0$2&6F#a;*hX7zG2u5;Kf*M|CVmHTlyyvPnRn5i zwc0qFcnO*+s8eXXO}mt^#tLcAS-wj5^fFD$tGECIbn4`X_KwCg77=Ge@sDB{a1potTxU1ty0b2!q9P@ZpGDv z)$4U!U$WX7!s_+fX28mDEl>~FHp}{bMEG&SN;}(XDTLMQwdrD}wCjL6VUjwEzE7c6 z(D_=4usX`iR@3=<+BUzjnwoF6)#h1kBid**9j^Ik8b3CH59}Vlil!u+flfv3&}*q* zO4)*;W>rmJw;66FtY(#_vp^Nx24;|pDxkAKg?s`o18r|xKOM>xTkv8u6;1Li9 zv~biyu?EoMuolpB%sM~|!?GYRh%}k&_=+cKUHBJp)`G}d{%N_V<=t$M477yPlI>-n zRhs^SWFmM0ya*3 zDuPO&GN=M#K~+!VkTpK4<_Mg3BD?pTQMy4O|B|z%Sr8 z@H_ZJD1 zYkL8$TU!IIOWT5Wpgm{-9s@0b)~7{H*#^FfC5sSzk+Xd&m=0!unP3)326KQ`r1Q*V z-1BSsrsdiape33gga9qgGMd8;d_@}bzaO}A0xhJpaN@rSaPeOPI18poI6vseke~^6 z0?-6{Ab1LBo~t>m=Bz_a{f55c;kv-VpPA(>6`h zv~qeDj0R(XR!w@%U7sBo3O>b0pJZGKv{D)f8kwJJGgK5O_!)g~7tjYNLV(soH-Wx< zaS>bwKZ7gaD#%SUZh$ufUCN$;hl51W7xV-D!MDWeW577@1ZV}~z@wm+ZcM}y&?@C&pwG}2f(w9xAQI#UT67#D?t7qx#WwH>*bY7g zJHaln8|(p}gS|j&i~ZmL(7IqSNCf>s0vMo$;Xndf3#Pn)-?)og;W2oB)Tx5%4`|3AE;zPVapQXret6XmYJTg_;be z08Om-0)59L6ddOW>w7Jy;XUx@;0v%9dPn!g^X43?6BDf1~ zfj_|o@Dn%*PJz?lC^!aw0NXi8JAh`q3&1NO90YxtL!a}|l=lEQ!T$fm!8ibFQn}hd z&w?KX)j`JUI+Tniasr(&ySp>G6&g-Z-73# z+z2!V{n1;2)}Xm&7uOJHg7H8z)LkUjhg8;pwctB4I0O!ZBS2qa(X4eHIE(!~I0mke z_9T1)lp)RsbicnPxJ5bNfcBIz7CubtYywGx_~{K^U@s?u$zU4L{oUCh6zEQ+ZaDU( zfUck+=uhVTKx^SFS&Y(J| z2+r&KL0TYcL3joH3bYW^qjndCdVn9~!}&CtAJ#X_zXM0W@5KEH_JOalb>BzdJlDM* z-P;)i`hvD#JDUC;WhZza=vK{#y04?p-|HTYYS|9xbNS^!WuQ;!>()wXpky3l#gyO)S!hP1-EHQ`8EfN+mH4xcpW6Y!HV!jTGwUY7ZJ-+i-+|*~ zDy$*A4y*?oz-I6|I8WSva`-mlw+{3(`&;=sB)vx+wY(pTq70R;it8z zmXh1SZIIfStqE)CsfOJ~gMR|v1dG8Oa0sMtrzNx03pByw0v`e z)I+7wAru5aW}sQ$Lx8looRc6c#wDtClk^Y6In6f-zH+rS1=rf*7i2x0sS4|)F9|eW zY7LSD*19A+{5$bE32Qvf4(BxWpYT2FjxgJv@D=G)4mBE-1!X{KPzsa;B|vdd3={>L zvlaoG=oSWrfaa~5ziQs9`K!jhyx@{)-qlyGS7m~lX;y-Djcp7Xfrg*~s0-?V+Moug zPG#Q()d*{v+>NlN%o>9=ht`Tt9fm>5d7>3(_CD#$UB4!BMvAEgYrxZzqn?FqEe^Fv zYy(;YP0L$?$3P3v95gdGpYTp0_n$taX`flfct}fK*iRlI&ON{lh~SvJOL-9#V6g>m24~+40O3x!ski!6g&_- z4HCgnFa-QTA!Fdt;8~z6pstFV?`t)qx&AY76?g=!tEGIT$w#a*RaT;&d`~8zzMcWR z2-L@4029GB3e!0-$!ZF#dlx37X@qsPn+j|F{5W`-u=aEg(4ML#)Cx1;mq0R@1!jWT z3achcBj`KKvnA20j4qfu&#x zco)0_7J~-(CMls3C~_583H~`l`Fx6A9M-IP9N2-q1*`|#z-F)xq<~FeBiH~w0w04l zKX)oL-0N;Xx;A@boXQl$urF{d`C$t^W z@jna>0XfL=8hjO;0zZJG0NLf`=NRFA@N+;@_fAxJ2z&zlM{wNoFtn3|hr$~0l`qZh zTt>nPpC+ynNYek?afLvt(Gj%Nv2p!_+==R&G49`$uI( znK6tRHfBqiSB}KBi)dn#R^*_bGA-`HZt9CzxOGR9w$aZ1xz_?nM zRyKBA%F~{%cDPi2$RF=bAh7Tu|7!0L0&Oz;E9B3AgSjAy-umdd@AE~RQ=&@ImDF@) zZn(^%%p^)A5Xj=+>s`bDVtqJ^e}4Y2m_pGwp*MQQ}Pd&IY#3AwQjj7PFzkX|1-E0B$sj@HLo!0wbRjQETVv65!nR4MIu8T{4 zxioH^C;OETmZZ7#B&HBC{d4SIo#Tghj-p#d*2{n!u|6-gFI$jHh+X?tj9FV z=8wTn!Jg*z)c2Y!x#)|nyryd|I%7Pep4z(7R}J4QP?7%!leVbf^qR3=Gc%XJucwaB z9F6oxn6TXbyq*?56J3C0J$!Ec(ayMKi=OQ8dAl0doX%D$x~k?HN){8D#4Ymdctk(_ z(csJN`X0lB(@AITY`^(1H+d|^BLa`BF{jrJi>=OxaiA|V<0D4<*YSg{*9#A5ebB~mUTh0BE%MMT z--Viw^7vz_^x^(SCOk78{$*~*k1`ET%frnKRGn$VhzqR_HMmpL7EcSrhnfP~Kk^s= zo0fTLT5J4G!=*M$a6co=fxP}okwX}`RQ_u(Y^b~BPL_8(?y;3=XKKn{FGuC0Il?lV z_WAtH?mxtFw7CjqHkn5Tqh6DJ6TMvNdLIV z{#k=f+cmlUxC=eH9rC!VM8_~3(zLeJzA9<~p8;`y8I{M7IH ztfo60xr-DUf?J<@=gB#}m$#>M2JwpQ%Koh819|2TGspAOZb3WZZ)y=NBPQ~Bo9D9; zakmm)Y}+@?U88!1D(a`!!+co4pEvS#uGu>SUtc?lJ z`Ana8N00537Sog%jUVkAE^Sda;mfAPRJYZ6f+&pvXLqidk&<`oz_dhDh|$oJILZv& zw=Zv0T1-MNv#%hnH!_#;6r!ECa5pX|o)ODG4r~5s|3_?(rNEyf}-8&fR>w zraW8zR@5dubV23Bxk-%9*#&(^emy_y)}=Nr$2~l^c};1fSZC_YxqIX6lu5tVz3g~6 z7vqY=DA)53>^tnWqZV z11jb=lM1s>O0fT}d0c+j`td zShV2ixJb)ce!$aHJktD8 zgdGc3FY>;HI|(Vg=fkuJ8GQI~FoW_%{V`@mQGZU8wWzoN)3U68P5yD* zEz&%2^OQy-yMNR*6MGX&7v|X7DQE@HHziHmXb!|LCC$}n|2WT-QYNt+RSa-}2hn;G;(VJ2h56zr8*j&?RmM5>(WlgpU zg(l3$R{mLgw8~v# zUV{T$_1uuHYGjBgrFdok;2%>u6%A<|6H+NQdT75<=6IKoyykd^kT7$#OGpMYr(;M} z^IM0I{H99BkO;G`Lr4KrzDr2JBy|o6G2J?bl$V*^?5zJpO26zm*Q>>mV@KAcVnQ?6M|>#iaB)2X@4kTt2Y|+`LI3~& diff --git a/test/js/third_party/@napi-rs/canvas/.gitignore b/test/js/third_party/@napi-rs/canvas/.gitignore new file mode 100644 index 0000000000..9b1ee42e84 --- /dev/null +++ b/test/js/third_party/@napi-rs/canvas/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/test/js/third_party/@napi-rs/canvas/expected.png b/test/js/third_party/@napi-rs/canvas/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..3a98dd5ee0d538a7f6e72b722971ea6974b8b188 GIT binary patch literal 5283 zcmd5=RZyHwl>J}^w**UY5=d~@9}f~B2^t21ySo!$U0BJ_B{Z5%B$+&-;Y3it0(}VR8v)aq2rgezxdvZ?r#Vlx`LZaw`^vZ zK@y&v2;OuNeWHmE?$ZI{@h!L`Yh23VW{XteKfxWBJLj1fL)SgHC7e+| zHC0=QX70p&6Ri#2XY!5g!j23VN z5Bvf>F5n4(k`5?$_uK5pcc=nqHuZ7USY=|RQeKUfb|h7r-*7BCwY0QCY8_=G5Gswq z0p|xVA&{c>A3L?q(qEF3-nv)5BN+$Gnpd-^xR$!qh^WJsz99%_eF+l-1qNE%E-8!x zPMqD(RzWMm$S$1)ZpsIltCK^SVip^*G^+#%!qO9dAn)5Z3SK=NU}gP?x?Uq2)zxU9 zuOxfx#lYKkKpl#l!&0#c1~}!Z?JS0bh=1-H_tm>U4LQ4E@? zvy}wQ(4!9QF&~hbJC%BwXK@#sPe!Mr26(?P)q3mCZwA|3b!vqSSdw@=MwNUn^=V?z zMpa}!_ZAK}Ib3Lc*ojcKKqs05uzPncp+L$A-2?!jmz|3(P!1i?$QHo!X_BrdQI%hA zry%Y(#~ZbbTPCc^l7e#K(nfUd%ajsDPL9P6<=*gJFD|ayhX4z3^{}OLp2Nrj<%~Rb zLBPyz2!E28%q5_Aip0)QngC$u;Ze#%K5P;#kDL2e7H;)*J2#2YG#+%UfV7`LWM2Mc zAya^`5^pUt0eP7DS_6fUuPW@GJ7fr`iN@C7Fx6x%V7|@?UyaT{8auRxcEfBfsHQ<9 zBAv7dNYmDowXKb=$=8Xrh3SF& z0<-EWtxeukq2Tz243&^`N8#35EGA2xt(oo2e68`EWJ9I^r|8-CzLvQV2lGkIH@m;R zG+esZjEJY^$LlL!o_8-3lok*m_7Y}0j?!%QW*eTJ23<~X>}(v)wF;az)=WOEWBmjV z3rKCc3^zH?Ayv1!oRk31(N^w-!$~%#fO_`QeNFQLe&!(L)H`^l|GBX&453nQ-(H6W zAlAu5;n&U)hO-U(MD)_+2gF$dyH5A@vE;3qB;Wg}Q#t!Gx=7>9L3;bkeZW~h%jc_E1?8ItYj(lV?nxP+qeNVmWyndBB zzE;?Bx7gqK#J;Dj+A?jvVgKXk?h^&aup&+_AsLbRfbRz<{uEGtg|>i;^ev}Z5WJe( zK^+ICH!=5I-!ucO0UKr9$e|%~By@^_Zmr>q2CtW|B}xrNIEslepr+LR+C`U$yo@aq zAy!@w@m`$NCwMK&JbVq+R@b4r}F(`#UL4k&BB&LCF1>oK+Nw`YT-%lp$@~&U! zx8##48yjcy(rfpcn~Q5d84&bwS_DuL_Ch1C9+S4oVsNtkHoR6nK1uJ|Y}?Joxz`r3 z6#D`7U`Nd-s)EdyJ~xA3geo03&ql9S!oxR=McO>)U%rv@q_r8$$ea{V82I#jX1~Zy zqI+81+T;4k@t?Fdv+=Hr^p^qzg0rU9LHZXpLF6x;smb=uk9%chxMqRl zAIdZyJW$#N6LWHKgmC`_FZ0vO$KP6#6dSBh1;2{U({h<^AqoeXiIZ>1)GnJjWbp=7 z)re#17X?f&&>xI`Y?jT6o!$4@Tf#)Q(;q4>9pNrDyg-#Pb~%&lKR;%D7fh3(@hA; z%usHHo3cTHZS6YodD`q>9TFwI3;a)~7@Z8Pd+MoIx8lQ@5x4}AYuOMkEWja2?6Fqh z-PunvlHz{g_H*R8Cg)R!L^8mLF{6F1)2OEwe@52A{h`RuU-^2QSrpAq3aJ6HQvyo9 zbxhOCfs#8m#!XnE6#rj0z~Rs{=2vOZ2P`OUkT zJfEAB81+Si!Pw-~Jc75sg7*401$_Fa)t1F-hC4CuKE6w(PPCP$C{`mO{lwx+v#gv` z&NJ`xyIXGwm9G%Fa^#0TXgZXKK#1wZ`E6$B4-II~^<<0{9Bj?TzA9-#s47}7Idvf2 z{i$4*X_5Mk8q<<`!`@UZW z%G^-oUk3#*T!~{l#})5gUB7lkU5^JFQr9(G9#@vA>$>wr896nwhZ|I!~OpAZJiGO#T<^@pD^TkNXgL;+& z|D=?Q=nn@6X!iI}T#}C0d@W$$U5mf>!W;-V+lxbP3#P4X48?Ucq>vT03wT#M&ZVI7 zcavDn`%^enk$Sq+!BJyYN@S-$toq2g^{ZG{{ZBTnSE-l4Snmnt_Uu9ZaB^k`_F-N&oInmLT}V6Q3|<#st(YW7wde*QJ*KDWk)pUj95*l5BHe>$##;&KZJo# zI0;B!Q@ju<#npoRyVc4km2p{;|4UP5;lr1;xJ|dhL^cTFVt#;)PVl;btOz+t<9M{|0 zAdS3A5#&rqJRPMC6n%A3ugEg_$Ru%+RoRInCSG1&U{wLb?Vp^AD27txBKy+2w0rzJ zUxdRI&zXQWOcBAOoj&TDqMz&aJz*nWo1F=^%_RLi$mm+I-1o@$et-Gt7bvdY9O-=d z)kO#vl(b)Q+mfX7Ts%#dkk+gn;rE(*kM?@z-;t^mYy^&Jh%UleXNJvz0>GfMFm2pYLpVLdYPVL5XpleN>yd5eRg zN^#nyytRku5v25OpKmDV%t>#Ho?~nF$3+>sa4Afu#4`vH2Gj+mWlNv2wZZCxs(;2pUI@2Ba|nj3ae zyukMt+#w~jEDak}_lJ$fG+g5?#(r}dyn~K2-5jX_DEEJ66q|;i?3D56ybY8ghL03X zyy*O0jAJ)#@FX$i;R}PG=`p_DMjE1j7Nb3XdEU}ImB0yjW*V@Et(l%`VLf55 z9SWd8jlSuozOP+gTcQq0m+B`GoPL`fuK1l;0NKcA0=Vdhs4H}QR*HbOm$<`bp+{-( zYIwm64gDt>D*wMn@Ldbr&5$Mz3~JOBdGmOYpge{rV83oF&ARN$jf(T~&zXJoST6(M zcCAxYcVQDWl{lD=zF@Y7UZOm&2Nu%$!9Xuf6;m`JFDCDSsSS06AhUP7NLz zxL^UYoEig_W1i6|QufOLB`f`x-C;VJufor}qjd(cR7ai5WLYL`~Wl zIDRj*I5m1OJr5TPc8+CKn&}}i&5HOc=OENNBTyT9JW4IZ`?fW^M+6@Tq=4NLsM;7? z8``b&R`jj%2fN`5>XD16RGeU4L&UnvDm{5d@_d{1{Cnxy5o3NDC$xprw!rW&wSVit zc8}@HsXVDTED-K~NQr!TboGR-p67?pa5smM zJo&y7aD=zVtLS9WjiH8hH*%2RkrfCZ|YP9fz}Syfb}Lc1pZbfYVV zB2&iD`L@7Jdi&)RWKcvU0_(*>B7h33EI8`M<631WS-LdQHX#kr&mD|d?n@-cms9t6 ztf`+SV0|khKAE*W@uLSj3hJj>X(mT*K)mv+-m^EJHsn$kIcgf@Qr*5Zf@5f3y1j;e zsr`&5X`0ScAYUbY`lITmF@bNEOv2>g#4te3hs(<0idFy5sy3ahADuTvPj9xVwl1!r zey*9F)3fiXQFoi)5VY6$G1!nK=BvhuTNOG{*Ipd4g^a1jo*>edAc{I$HDZQp+ zO=bUmc!(TeVk)NF(uPZRvv)!N7sH2xenWa@$wRF2G7A_Ccn~M@PwmE^?b6Snq);xB zCd&gZ4&IyziTjdKPXDcIe=hAbFm&Ky@$u}7holGLA6?RncQ50C$DghiGb~tOUI#bq zCQcS#TE7moywfkr#06Eer9VuSB9$*kJnrBi{F(Lg!%+I!siKG4f_mQDB-Ghx|c{#ce3% zSBu+#cO}tER?`1dG5T);(*I8=XWvScsK)7Z!HZ2LKJ}kc*Z;y)R1R`tjQ{kT1<8LA i$Nm?O|HFGh-GMfoki9YIaJze<5l~f9S1gw|`|uwmp~L(D literal 0 HcmV?d00001 diff --git a/test/js/third_party/@napi-rs/canvas/icon-small.png b/test/js/third_party/@napi-rs/canvas/icon-small.png new file mode 100644 index 0000000000000000000000000000000000000000..69bc385e8ca9947e54df56921d113487a205841d GIT binary patch literal 4965 zcmV-r6PoOaP)Px|A4x<(RCr$PT?=>=<<)*S_hd;zNVwz%Nw_8ih(JIT5q|uoR&AxCV681}A1|$7 zeeecaTJ^Vbv1*I7NWFmNB30wB)CQ;Fe-vO{tW0`(u z4|PC}0vH#dmB?#m1t_D>iiav7uLD>jXNCCqcE_y0cq9N)R= z4mq(d01-jAu8s;q0g%rC%$Dl@&_fSm{kpZij~NG?mUF1CEJehuwl!q(1@40B}ayvheV5I30G; zV`qCWTjk+{7(OBcDMN>|JY|RWAvG-%!$zdDe>XPNqoKjWpFgD#B#+4HbRsrotdh4x z0bqh=WetM+3y>B7Nm4yqS}q`I@L>M2v%MaNOZQ{kgnUHD#P9&b#tmYh5gn_pfX!;b zq=G_(g?WtMc&;7|XFZ^d${vHkNh!R{yg2`mU!nUh2WpO0 zdKsQ(RW@rUqN1Xan|~Q!pu4*pRTYP1J)xtm6(?$|*>^NMi%&>YG*rQ?1*oh#Cinhh zANyyz46jru7=Zi%z^|kgCM3k8@%%YNM@M^J3Dy%r-tKNYswzs@MNy!+M zEuP+5J1sbVv_jT{l#E+mQH5!)&wqeX>sRPXPa=MurxiKmnot z$13%T<;(8Hh7G+7V7Jo_m$gw*FZ%My1LQn|o(a7pEn^gh4xsi1lfkDqXW7EHt#sH2-uFIlwj_z(8sW^oA#3ba59X0>|3F!gL2igsMQU7#od zax;LpIEnT3XONca@wx#p)O{N@wI`7~&1 z?z`?B@Qwh!pS8c=h}BO$tJd~jgSsfoob!%>aU%dk04R8gZ1$woLwN6ayXY+}TzC`Q zj0-M{Xt5KRcHhF%|FiB7cyf(wg5>uA{9R}gAs`C??BQMxc!#lHj)IqXEj@&Q(5jD( zEX|sAIllbjbGTjIaCHV}Ag3VDZAtdGT_$V)gtD2Tvklu>sTjIras2UcU#E89VF zl=<`LWB2aevJH57<9ht$N4?1rMp&q|wVe&W5-nZ26kE4$l@*(jo{E!|Um8)Rmkb}> z7Vjk-AVmOvKoTb9=cBy56wZzYz%84bq)XY-@=6rWxdC-`b;!)@O)^MMPDV=$AuxQaDueyWfDd}UUqp_)HbJp96EEXIfe0Q~d+cw;O z`)!7IS7Z!1X0SwLLYCb*r(C4O(+{wD5R_AslP)F_)bZ^k|M z+#}o8##5z88myd)tJXjqAkEFq7&1hhW~%ftTy@0^eDcBH)K;O2&(Ye3xU2$SynJdP z-(``97(KgM^ZSkXP0#j0L_`G2%F5W((iJOK;Q8mDS5)w9%|Q%J5gSld%LPm{y^bF- zfq$}T(B%x)CL-m>s|?A#*C0}Mn3wydM&BI0tU`jS&b zfY9-zy*wZ;2Y<>nU=0KU^ccmcfmKi4hrZl{NqPD*9F^>*0uXkVbrpbrb3z!0H7Kj| zl#!Fs)=uM=I!a3&j?-11<7FfmOXn=G4eD>SGYrr4|tKAEZhfqQ-pZn>u zwSW#?8b+-SgdeB8G2l$&IgGkploBjkO)$Prsz?nepFHyt<`xvPdNCto;2z#{z$ie2 z(11>dl>Ce#-U~yT@-p29WY@dh2tOcy@5t197NfMbC$~$`(0NzQLh;{s2H14p#qV17 z2)1meps1LJCMMyVUB!r$90X!}jmzSJh`=%)skUJk)761bH}y7L3JA^40wId)2+1hD)avByu)y8ZhGCOt!_w)Q;3yFX$S44( zI3}ZJIa(Vp1w+lONR44m9odWYwBFNMn)RA!2IBOE0oh$F+i$#db#eoP5AYb>+xX<-D#$uuDfsoqcYP`bNF+y5Icjg@($m* zwB|4{dAiTuKORIw$v!E#KU!2LNDoZGg#Qn_pV+=g}jfpHK4>{Lw~eI z*j15|{?;E{LlpC}C^$nwn*OAJeYO|Z-1tMhmXwKM;gR@xOC8SkWZ}Q}-`8S6S_Z;Q zCb-;g{IT*d9y;JTlbB)(!?xrsP{xi4srrkkO#Cfk~z?Ty!&ddg^qnnxY)!SzA_$Rf6MoeeNBCMIhHEwcY_B z&u4D${JFES=N&qg)xX4bU2o5ukA+#Xhhant#{P8+x?C=_d{cq=LF&#a8r4E+SCv(G z4H}!hlQ?J%R#6A*MyRnbaYtQ8+wRrcPvFrgz^+L`n6Zl%`o`<<08x~^cf5? z3Ikq_6bvn62LRezN%DI>BswYzmPYT5K*L+(M__li1Lk3#?fV%iL-Ey(-xrlwzV{1k ztgd38RUY^R+BqQ74pbMN`{0Tr-w1%#VZ5Dv9l>ni8@AyOL58wX_{O)m2l0tve z-OE?v)ot?02eRvpK2X>}fj7y)oI933jH37dp`~_FUY1-zI#9wNlIZSx(%bmE8?{&=P+muSJKz+12HoX2d@==MRTE`;tRQZGCqqRCKSK=^ z)y)kOBc=6#5nuO9IlS>>JpnEa#N*%(5DHH4H;&Otm_n-q zfDj+ubN9Zm@^7=Jxakfs@(dZ$0ftvEr3MfxsebkWMftS5>rW zs1^{alM0GPDx-35L%s`?S$%Ul>l`zvIGf8WZMzmgs4VSaUnvyQdiDs+ar#1=ArAyy zlpqK&N%g(Z(u$GOb>D+2YkRGLkWMd1558}I@mVZh!X7XAe?v?cUEHZ0-Ftb*o49W^ zzoDVE-SkrqvL|Wv078|M_34lgPdTG9Q2E&hh)B>M(9zneVDQrzL1Tq4(zrh*6-7U8 z_M(z}y?~IsR{(frLlp0N3A1MwA|f%Ky>jnTA(zz#MtoJDm+Hlzeu0~Q7SI{Q|K(1q z1p^S0Nr&;gegSQeISwcG6@&gC78i%`7-O>kj0RU4w@{K#i3w?!%@y4(tV0*NFh=$l zWrVT<@eodqEGYDHZ1zYT_~O?_jie76DAYF2bp1th%hv%TB?KF>4K96XYX5i z6z$n*wPO72>(QdH0Mq~kvC=i{bJUhG3J|J~e)4pezlslj^d@r0j#gv~i;jjVI?4l* zDGa7C-zu_46173P^c_2?$pgov#kfd2b+=6PKkn z8nS=X7l4rJqPU82b_fYc^h*NzQvGGr?<+vKsws7(JS5B*xDu2cRu;Gzv4p+`gsYu? z(M$Q4UW{&~vGOS8mcQ-WSkeAt>PFWml}ED?x)y43uqz5sJ|z>Acl*zl4zQyB@(?+- zMK?+W*e)ZA(|U@!CE4p-ji^9QMkoOy)Q^4{lrku3rQ4UZ8Nd_5W8!^TIn@=afJp5? zt6u6derw<_ZqgppV?7Ch^1tQR*JxZqfb@fD`lrfE#Y6hXI{i@V03iKfbYE2t05Skb jh*==S)EV%Q5Ch~tjJkVYq?wEt00000NkvXXu0mjf!vl8B literal 0 HcmV?d00001 diff --git a/test/js/third_party/@napi-rs/canvas/napi-rs-canvas.test.ts b/test/js/third_party/@napi-rs/canvas/napi-rs-canvas.test.ts new file mode 100644 index 0000000000..b03b58df0e --- /dev/null +++ b/test/js/third_party/@napi-rs/canvas/napi-rs-canvas.test.ts @@ -0,0 +1,25 @@ +// Create an image, then print it as binary to stdout +import { createCanvas, loadImage } from "@napi-rs/canvas"; +import { Jimp } from "jimp"; +import { join } from "path"; + +describe("@napi-rs/canvas", () => { + it("produces correct output", async () => { + const canvas = createCanvas(200, 200); + const ctx = canvas.getContext("2d"); + + ctx.lineWidth = 10; + ctx.strokeStyle = "red"; + ctx.fillStyle = "blue"; + + ctx.fillRect(0, 0, 200, 200); + ctx.strokeRect(50, 50, 100, 100); + + const image = await loadImage(join(__dirname, "icon-small.png")); + ctx.drawImage(image, 0, 0); + + const expected = await Jimp.read(join(__dirname, "expected.png")); + const actual = await Jimp.read(await canvas.encode("png")); + expect(Array.from(actual.bitmap.data)).toEqual(Array.from(expected.bitmap.data)); + }); +}); diff --git a/test/napi/napi-app/binding.gyp b/test/napi/napi-app/binding.gyp index aebdebb7ef..39b61162a2 100644 --- a/test/napi/napi-app/binding.gyp +++ b/test/napi/napi-app/binding.gyp @@ -10,7 +10,7 @@ "AdditionalOptions": ["/std:c++20"], }, }, - "sources": ["main.cpp"], + "sources": ["main.cpp", "wrap_tests.cpp"], "include_dirs": [" - -#include +#include "napi_with_version.h" +#include "utils.h" +#include "wrap_tests.h" #include #include @@ -30,23 +30,6 @@ napi_value fail_fmt(napi_env env, const char *fmt, ...) { return fail(env, buf); } -napi_value ok(napi_env env) { - napi_value result; - napi_get_undefined(env, &result); - return result; -} - -static void run_gc(const Napi::CallbackInfo &info) { - info[0].As().Call(0, nullptr); -} - -// calls napi_typeof and asserts it returns napi_ok -static napi_valuetype get_typeof(napi_env env, napi_value value) { - napi_valuetype result; - assert(napi_typeof(env, value, &result) == napi_ok); - return result; -} - napi_value test_issue_7685(const Napi::CallbackInfo &info) { Napi::Env env(info.Env()); Napi::HandleScope scope(env); @@ -595,33 +578,6 @@ napi_value was_finalize_called(const Napi::CallbackInfo &info) { return ret; } -static const char *napi_valuetype_to_string(napi_valuetype type) { - switch (type) { - case napi_undefined: - return "undefined"; - case napi_null: - return "null"; - case napi_boolean: - return "boolean"; - case napi_number: - return "number"; - case napi_string: - return "string"; - case napi_symbol: - return "symbol"; - case napi_object: - return "object"; - case napi_function: - return "function"; - case napi_external: - return "external"; - case napi_bigint: - return "bigint"; - default: - return "unknown"; - } -} - // calls a function (the sole argument) which must throw. catches and returns // the thrown error napi_value call_and_get_exception(const Napi::CallbackInfo &info) { @@ -1080,6 +1036,8 @@ Napi::Object InitAll(Napi::Env env, Napi::Object exports1) { exports.Set("try_add_tag", Napi::Function::New(env, try_add_tag)); exports.Set("check_tag", Napi::Function::New(env, check_tag)); + napitests::register_wrap_tests(env, exports); + return exports; } diff --git a/test/napi/napi-app/module.js b/test/napi/napi-app/module.js index 6cb1280cf2..307e9ee9f6 100644 --- a/test/napi/napi-app/module.js +++ b/test/napi/napi-app/module.js @@ -1,4 +1,30 @@ const nativeTests = require("./build/Release/napitests.node"); +const secondAddon = require("./build/Release/second_addon.node"); + +function assert(ok) { + if (!ok) { + throw new Error("assertion failed"); + } +} + +async function gcUntil(fn) { + const MAX = 100; + for (let i = 0; i < MAX; i++) { + await new Promise(resolve => { + setTimeout(resolve, 1); + }); + if (typeof Bun == "object") { + Bun.gc(true); + } else { + // if this fails, you need to pass --expose-gc to node + global.gc(); + } + if (fn()) { + return; + } + } + throw new Error(`Condition was not met after ${MAX} GC attempts`); +} nativeTests.test_napi_class_constructor_handle_scope = () => { const NapiClass = nativeTests.get_class_with_constructor(); @@ -270,4 +296,198 @@ nativeTests.test_type_tag = () => { console.log("o2 matches o2:", nativeTests.check_tag(o2, 3, 4)); }; +nativeTests.test_napi_wrap = () => { + const values = [ + {}, + {}, // should be able to be wrapped differently than the distinct empty object above + 5, + new Number(5), + "abc", + new String("abc"), + null, + Symbol("abc"), + Symbol.for("abc"), + new (nativeTests.get_class_with_constructor())(), + new Proxy( + {}, + Object.fromEntries( + [ + "apply", + "construct", + "defineProperty", + "deleteProperty", + "get", + "getOwnPropertyDescriptor", + "getPrototypeOf", + "has", + "isExtensible", + "ownKeys", + "preventExtensions", + "set", + "setPrototypeOf", + ].map(name => [ + name, + () => { + throw new Error("oops"); + }, + ]), + ), + ), + ]; + const wrapSuccess = Array(values.length).fill(false); + for (const [i, v] of values.entries()) { + wrapSuccess[i] = nativeTests.try_wrap(v, i + 1); + console.log(`${typeof v} did wrap: `, wrapSuccess[i]); + } + + for (const [i, v] of values.entries()) { + if (wrapSuccess[i]) { + if (nativeTests.try_unwrap(v) !== i + 1) { + throw new Error("could not unwrap same value"); + } + } else { + if (nativeTests.try_unwrap(v) !== undefined) { + throw new Error("value unwraps without being successfully wrapped"); + } + } + } +}; + +nativeTests.test_napi_wrap_proxy = () => { + const target = {}; + const proxy = new Proxy(target, {}); + assert(nativeTests.try_wrap(target, 5)); + assert(nativeTests.try_wrap(proxy, 6)); + console.log(nativeTests.try_unwrap(target), nativeTests.try_unwrap(proxy)); +}; + +nativeTests.test_napi_wrap_cross_addon = () => { + const wrapped = {}; + console.log("wrap succeeds:", nativeTests.try_wrap(wrapped, 42)); + console.log("unwrapped from other addon", secondAddon.try_unwrap(wrapped)); +}; + +nativeTests.test_napi_wrap_prototype = () => { + class Foo {} + console.log("wrap prototype succeeds:", nativeTests.try_wrap(Foo.prototype, 42)); + // wrapping should not look at prototype chain + console.log("unwrap instance:", nativeTests.try_unwrap(new Foo())); +}; + +nativeTests.test_napi_remove_wrap = () => { + const targets = [{}, new (nativeTests.get_class_with_constructor())()]; + for (const t of targets) { + const target = {}; + // fails + assert(nativeTests.try_remove_wrap(target) === undefined); + // wrap it + assert(nativeTests.try_wrap(target, 5)); + // remove yields the wrapped value + assert(nativeTests.try_remove_wrap(target) === 5); + // neither remove nor unwrap work anymore + assert(nativeTests.try_unwrap(target) === undefined); + assert(nativeTests.try_remove_wrap(target) === undefined); + // can re-wrap + assert(nativeTests.try_wrap(target, 6)); + assert(nativeTests.try_unwrap(target) === 6); + } +}; + +// parameters to create_wrap are: object, ask_for_ref, strong +const createWrapWithoutRef = o => nativeTests.create_wrap(o, false, false); +const createWrapWithWeakRef = o => nativeTests.create_wrap(o, true, false); +const createWrapWithStrongRef = o => nativeTests.create_wrap(o, true, true); + +nativeTests.test_wrap_lifetime_without_ref = async () => { + let object = { foo: "bar" }; + assert(createWrapWithoutRef(object) === object); + assert(nativeTests.get_wrap_data(object) === 42); + object = undefined; + await gcUntil(() => nativeTests.was_wrap_finalize_called()); +}; + +nativeTests.test_wrap_lifetime_with_weak_ref = async () => { + // this looks the same as test_wrap_lifetime_without_ref because it is -- these cases should behave the same + let object = { foo: "bar" }; + assert(createWrapWithWeakRef(object) === object); + assert(nativeTests.get_wrap_data(object) === 42); + object = undefined; + await gcUntil(() => nativeTests.was_wrap_finalize_called()); +}; + +nativeTests.test_wrap_lifetime_with_strong_ref = async () => { + let object = { foo: "bar" }; + assert(createWrapWithStrongRef(object) === object); + assert(nativeTests.get_wrap_data(object) === 42); + + object = undefined; + // still referenced by native module so this should fail + try { + await gcUntil(() => nativeTests.was_wrap_finalize_called()); + throw new Error("object was garbage collected while still referenced by native code"); + } catch (e) { + if (!e.toString().includes("Condition was not met")) { + throw e; + } + } + + // can still get the value using the ref + assert(nativeTests.get_wrap_data_from_ref() === 42); + + // now we free it + nativeTests.unref_wrapped_value(); + await gcUntil(() => nativeTests.was_wrap_finalize_called()); +}; + +nativeTests.test_remove_wrap_lifetime_with_weak_ref = async () => { + let object = { foo: "bar" }; + assert(createWrapWithWeakRef(object) === object); + + assert(nativeTests.get_wrap_data(object) === 42); + + nativeTests.remove_wrap(object); + assert(nativeTests.get_wrap_data(object) === undefined); + assert(nativeTests.get_wrap_data_from_ref() === undefined); + assert(nativeTests.get_object_from_ref() === object); + + object = undefined; + + // ref will stop working once the object is collected + await gcUntil(() => nativeTests.get_object_from_ref() === undefined); + + // finalizer shouldn't have been called + assert(nativeTests.was_wrap_finalize_called() === false); +}; + +nativeTests.test_remove_wrap_lifetime_with_strong_ref = async () => { + let object = { foo: "bar" }; + assert(createWrapWithStrongRef(object) === object); + + assert(nativeTests.get_wrap_data(object) === 42); + + nativeTests.remove_wrap(object); + assert(nativeTests.get_wrap_data(object) === undefined); + assert(nativeTests.get_wrap_data_from_ref() === undefined); + assert(nativeTests.get_object_from_ref() === object); + + object = undefined; + + // finalizer should not be called and object should not be freed + try { + await gcUntil(() => nativeTests.was_wrap_finalize_called() || nativeTests.get_object_from_ref() === undefined); + throw new Error("finalizer ran"); + } catch (e) { + if (!e.toString().includes("Condition was not met")) { + throw e; + } + } + + // native code can still get the object + assert(JSON.stringify(nativeTests.get_object_from_ref()) === `{"foo":"bar"}`); + + // now it gets deleted + nativeTests.unref_wrapped_value(); + await gcUntil(() => nativeTests.get_object_from_ref() === undefined); +}; + module.exports = nativeTests; diff --git a/test/napi/napi-app/napi_with_version.h b/test/napi/napi-app/napi_with_version.h new file mode 100644 index 0000000000..f852184087 --- /dev/null +++ b/test/napi/napi-app/napi_with_version.h @@ -0,0 +1,8 @@ +#pragma once +#define NAPI_EXPERIMENTAL +#include +#include + +// TODO(@190n): remove this when CI has Node 22.6 +typedef struct napi_env__ *napi_env; +typedef napi_env node_api_basic_env; diff --git a/test/napi/napi-app/second_addon.c b/test/napi/napi-app/second_addon.c new file mode 100644 index 0000000000..85232861dd --- /dev/null +++ b/test/napi/napi-app/second_addon.c @@ -0,0 +1,53 @@ +#include +#include +#include + +#define NODE_API_CALL(env, call) \ + do { \ + napi_status status = (call); \ + if (status != napi_ok) { \ + const napi_extended_error_info *error_info = NULL; \ + napi_get_last_error_info((env), &error_info); \ + const char *err_message = error_info->error_message; \ + bool is_pending; \ + napi_is_exception_pending((env), &is_pending); \ + /* If an exception is already pending, don't rethrow it */ \ + if (!is_pending) { \ + const char *message = \ + (err_message == NULL) ? "empty error message" : err_message; \ + napi_throw_error((env), NULL, message); \ + } \ + return NULL; \ + } \ + } while (0) + +static napi_value try_unwrap(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + if (argc != 1) { + napi_throw_error(env, NULL, "Wrong number of arguments to try_unwrap"); + return NULL; + } + + double *pointer; + if (napi_unwrap(env, argv[0], (void **)(&pointer)) != napi_ok) { + napi_value undefined; + NODE_API_CALL(env, napi_get_undefined(env, &undefined)); + return undefined; + } else { + napi_value number; + NODE_API_CALL(env, napi_create_double(env, *pointer, &number)); + return number; + } +} + +/* napi_value */ NAPI_MODULE_INIT(/* napi_env env, napi_value exports */) { + napi_value try_unwrap_function; + NODE_API_CALL(env, + napi_create_function(env, "try_unwrap", NAPI_AUTO_LENGTH, + try_unwrap, NULL, &try_unwrap_function)); + NODE_API_CALL(env, napi_set_named_property(env, exports, "try_unwrap", + try_unwrap_function)); + return exports; +} diff --git a/test/napi/napi-app/utils.h b/test/napi/napi-app/utils.h new file mode 100644 index 0000000000..92e158e6b7 --- /dev/null +++ b/test/napi/napi-app/utils.h @@ -0,0 +1,89 @@ +#pragma once +#include "napi_with_version.h" +#include + +// e.g NODE_API_CALL(env, napi_create_int32(env, 5, &my_napi_integer)) +#define NODE_API_CALL(env, call) NODE_API_CALL_CUSTOM_RETURN(env, NULL, call) + +// Version of NODE_API_CALL for functions not returning napi_value +#define NODE_API_CALL_CUSTOM_RETURN(env, value_to_return_if_threw, call) \ + NODE_API_ASSERT_CUSTOM_RETURN(env, value_to_return_if_threw, \ + (call) == napi_ok) + +// Throw an error in the given napi_env and return if expr is false +#define NODE_API_ASSERT(env, expr) \ + NODE_API_ASSERT_CUSTOM_RETURN(env, NULL, expr) + +#ifdef _MSC_VER +#define CURRENT_FUNCTION_NAME __FUNCSIG__ +#else +#define CURRENT_FUNCTION_NAME __PRETTY_FUNCTION__ +#endif + +// Version of NODE_API_ASSERT for functions not returning napi_value +#define NODE_API_ASSERT_CUSTOM_RETURN(ENV, VALUE_TO_RETURN_IF_THREW, EXPR) \ + do { \ + if (!(EXPR)) { \ + bool is_pending; \ + napi_is_exception_pending((ENV), &is_pending); \ + /* If an exception is already pending, don't rethrow it */ \ + if (!is_pending) { \ + char buf[4096] = {0}; \ + snprintf(buf, sizeof(buf) - 1, "%s (%s:%d): Assertion failed: %s", \ + CURRENT_FUNCTION_NAME, __FILE__, __LINE__, #EXPR); \ + napi_throw_error((ENV), NULL, buf); \ + } \ + return (VALUE_TO_RETURN_IF_THREW); \ + } \ + } while (0) + +#define REGISTER_FUNCTION(ENV, EXPORTS, FUNCTION) \ + EXPORTS.Set(#FUNCTION, Napi::Function::New(ENV, FUNCTION)) + +static inline napi_value ok(napi_env env) { + napi_value result; + napi_get_undefined(env, &result); + return result; +} + +// For functions that take a garbage collection callback as the first argument +// (functions not called directly by module.js), use this to trigger GC +static inline void run_gc(const Napi::CallbackInfo &info) { + info[0].As().Call(0, nullptr); +} + +// calls napi_typeof and asserts it returns napi_ok +static inline napi_valuetype get_typeof(napi_env env, napi_value value) { + napi_valuetype result; + // return an invalid napi_valuetype if the call to napi_typeof fails + NODE_API_CALL_CUSTOM_RETURN(env, static_cast(INT_MAX), + napi_typeof(env, value, &result)); + return result; +} + +static inline const char *napi_valuetype_to_string(napi_valuetype type) { + switch (type) { + case napi_undefined: + return "undefined"; + case napi_null: + return "null"; + case napi_boolean: + return "boolean"; + case napi_number: + return "number"; + case napi_string: + return "string"; + case napi_symbol: + return "symbol"; + case napi_object: + return "object"; + case napi_function: + return "function"; + case napi_external: + return "external"; + case napi_bigint: + return "bigint"; + default: + return "unknown"; + } +} diff --git a/test/napi/napi-app/wrap_tests.cpp b/test/napi/napi-app/wrap_tests.cpp new file mode 100644 index 0000000000..5365a29e89 --- /dev/null +++ b/test/napi/napi-app/wrap_tests.cpp @@ -0,0 +1,232 @@ +#include "wrap_tests.h" + +#include "utils.h" +#include + +namespace napitests { + +static napi_ref ref_to_wrapped_object = nullptr; +static bool wrap_finalize_called = false; + +// static void delete_the_ref(napi_env env, void *_data, void *_hint) { +// printf("delete_the_ref\n"); +// // not using NODE_API_ASSERT as this runs in a finalizer where allocating +// an +// // error might cause a harder-to-debug crash +// assert(ref_to_wrapped_object); +// napi_delete_reference(env, ref_to_wrapped_object); +// ref_to_wrapped_object = nullptr; +// } + +static void finalize_for_create_wrap(napi_env env, void *opaque_data, + void *opaque_hint) { + int *data = reinterpret_cast(opaque_data); + int *hint = reinterpret_cast(opaque_hint); + printf("finalize_for_create_wrap, data = %d, hint = %d\n", *data, *hint); + delete data; + delete hint; + // TODO: this needs https://github.com/oven-sh/bun/pulls/14501 to work + // if (ref_to_wrapped_object) { + // node_api_post_finalizer(env, delete_the_ref, nullptr, nullptr); + // } + wrap_finalize_called = true; +} + +// create_wrap(js_object: object, ask_for_ref: boolean, strong: boolean): object +static napi_value create_wrap(const Napi::CallbackInfo &info) { + wrap_finalize_called = false; + napi_env env = info.Env(); + napi_value js_object = info[0]; + + napi_value js_ask_for_ref = info[1]; + bool ask_for_ref; + NODE_API_CALL(env, napi_get_value_bool(env, js_ask_for_ref, &ask_for_ref)); + napi_value js_strong = info[2]; + bool strong; + NODE_API_CALL(env, napi_get_value_bool(env, js_strong, &strong)); + + // wrap it + int *wrap_data = new int(42); + int *wrap_hint = new int(123); + + NODE_API_CALL(env, napi_wrap(env, js_object, wrap_data, + finalize_for_create_wrap, wrap_hint, + ask_for_ref ? &ref_to_wrapped_object : nullptr)); + if (ask_for_ref && strong) { + uint32_t new_refcount; + NODE_API_CALL( + env, napi_reference_ref(env, ref_to_wrapped_object, &new_refcount)); + NODE_API_ASSERT(env, new_refcount == 1); + } + + if (!ask_for_ref) { + ref_to_wrapped_object = nullptr; + } + + return js_object; +} + +// get_wrap_data(js_object: object): number +static napi_value get_wrap_data(const Napi::CallbackInfo &info) { + napi_env env = info.Env(); + napi_value js_object = info[0]; + + void *wrapped_data; + napi_status status = napi_unwrap(env, js_object, &wrapped_data); + if (status != napi_ok) { + napi_value undefined; + NODE_API_CALL(env, napi_get_undefined(env, &undefined)); + return undefined; + } + + napi_value js_number; + NODE_API_CALL(env, + napi_create_int32(env, *reinterpret_cast(wrapped_data), + &js_number)); + return js_number; +} + +// get_object_from_ref(): object +static napi_value get_object_from_ref(const Napi::CallbackInfo &info) { + napi_env env = info.Env(); + + napi_value wrapped_object; + NODE_API_CALL(env, napi_get_reference_value(env, ref_to_wrapped_object, + &wrapped_object)); + + if (!wrapped_object) { + NODE_API_CALL(env, napi_get_undefined(env, &wrapped_object)); + } + return wrapped_object; +} + +// get_wrap_data_from_ref(): number|undefined +static napi_value get_wrap_data_from_ref(const Napi::CallbackInfo &info) { + napi_env env = info.Env(); + + napi_value wrapped_object; + NODE_API_CALL(env, napi_get_reference_value(env, ref_to_wrapped_object, + &wrapped_object)); + + void *wrapped_data; + napi_status status = napi_unwrap(env, wrapped_object, &wrapped_data); + if (status == napi_ok) { + napi_value js_number; + NODE_API_CALL(env, + napi_create_int32(env, *reinterpret_cast(wrapped_data), + &js_number)); + return js_number; + } else if (status == napi_invalid_arg) { + // no longer wrapped + napi_value undefined; + NODE_API_CALL(env, napi_get_undefined(env, &undefined)); + return undefined; + } else { + NODE_API_ASSERT(env, false && "this should not be reached"); + return nullptr; + } +} + +// remove_wrap_data(js_object: object): undefined +static napi_value remove_wrap(const Napi::CallbackInfo &info) { + napi_env env = info.Env(); + napi_value js_object = info[0]; + + void *wrap_data; + NODE_API_CALL(env, napi_remove_wrap(env, js_object, &wrap_data)); + + napi_value undefined; + NODE_API_CALL(env, napi_get_undefined(env, &undefined)); + return undefined; +} + +// unref_wrapped_value(): undefined +static napi_value unref_wrapped_value(const Napi::CallbackInfo &info) { + napi_env env = info.Env(); + uint32_t new_refcount; + NODE_API_CALL( + env, napi_reference_unref(env, ref_to_wrapped_object, &new_refcount)); + // should never have been set higher than 1 + NODE_API_ASSERT(env, new_refcount == 0); + + napi_value undefined; + NODE_API_CALL(env, napi_get_undefined(env, &undefined)); + return undefined; +} + +static napi_value was_wrap_finalize_called(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + return Napi::Boolean::New(env, wrap_finalize_called); +} + +// try_wrap(value: any, num: number): bool +// wraps value in a C++ object corresponding to the number num +// true if success +static napi_value try_wrap(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + napi_value value = info[0]; + napi_value js_num = info[1]; + double c_num; + NODE_API_CALL(env, napi_get_value_double(env, js_num, &c_num)); + + napi_status status = napi_wrap( + env, value, reinterpret_cast(new double{c_num}), + [](napi_env env, void *data, void *hint) { + (void)env; + (void)hint; + delete reinterpret_cast(data); + }, + nullptr, nullptr); + + napi_value js_result; + assert(napi_get_boolean(env, status == napi_ok, &js_result) == napi_ok); + return js_result; +} + +// try_unwrap(any): number|undefined +static napi_value try_unwrap(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + napi_value value = info[0]; + + double *wrapped; + napi_status status = + napi_unwrap(env, value, reinterpret_cast(&wrapped)); + napi_value result; + if (status == napi_ok) { + NODE_API_CALL(env, napi_create_double(env, *wrapped, &result)); + } else { + NODE_API_CALL(env, napi_get_undefined(env, &result)); + } + return result; +} + +static napi_value try_remove_wrap(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + napi_value value = info[0]; + + double *wrapped; + napi_status status = + napi_remove_wrap(env, value, reinterpret_cast(&wrapped)); + napi_value result; + if (status == napi_ok) { + NODE_API_CALL(env, napi_create_double(env, *wrapped, &result)); + } else { + NODE_API_CALL(env, napi_get_undefined(env, &result)); + } + return result; +} + +void register_wrap_tests(Napi::Env env, Napi::Object exports) { + REGISTER_FUNCTION(env, exports, create_wrap); + REGISTER_FUNCTION(env, exports, get_wrap_data); + REGISTER_FUNCTION(env, exports, get_object_from_ref); + REGISTER_FUNCTION(env, exports, get_wrap_data_from_ref); + REGISTER_FUNCTION(env, exports, remove_wrap); + REGISTER_FUNCTION(env, exports, unref_wrapped_value); + REGISTER_FUNCTION(env, exports, was_wrap_finalize_called); + REGISTER_FUNCTION(env, exports, try_wrap); + REGISTER_FUNCTION(env, exports, try_unwrap); + REGISTER_FUNCTION(env, exports, try_remove_wrap); +} + +} // namespace napitests diff --git a/test/napi/napi-app/wrap_tests.h b/test/napi/napi-app/wrap_tests.h new file mode 100644 index 0000000000..a70a44240e --- /dev/null +++ b/test/napi/napi-app/wrap_tests.h @@ -0,0 +1,11 @@ +#pragma once + +// Helper functions used by JS to test napi_wrap + +#include "napi_with_version.h" + +namespace napitests { + +void register_wrap_tests(Napi::Env env, Napi::Object exports); + +} // namespace napitests diff --git a/test/napi/napi.test.ts b/test/napi/napi.test.ts index 25144c80f7..18a53af2a7 100644 --- a/test/napi/napi.test.ts +++ b/test/napi/napi.test.ts @@ -319,6 +319,36 @@ describe("napi", () => { checkSameOutput("test_type_tag", []); }); }); + + describe("napi_wrap", () => { + it("accepts the right kinds of values", () => { + checkSameOutput("test_napi_wrap", []); + }); + + it("is shared between addons", () => { + checkSameOutput("test_napi_wrap_cross_addon", []); + }); + + it("does not follow prototypes", () => { + checkSameOutput("test_napi_wrap_prototype", []); + }); + + it("does not consider proxies", () => { + checkSameOutput("test_napi_wrap_proxy", []); + }); + + it("can remove a wrap", () => { + checkSameOutput("test_napi_remove_wrap", []); + }); + + it("has the right lifetime", () => { + checkSameOutput("test_wrap_lifetime_without_ref", []); + checkSameOutput("test_wrap_lifetime_with_weak_ref", []); + checkSameOutput("test_wrap_lifetime_with_strong_ref", []); + checkSameOutput("test_remove_wrap_lifetime_with_weak_ref", []); + checkSameOutput("test_remove_wrap_lifetime_with_strong_ref", []); + }); + }); }); function checkSameOutput(test: string, args: any[] | string) { diff --git a/test/package.json b/test/package.json index 5fc461dc32..56bcb98c72 100644 --- a/test/package.json +++ b/test/package.json @@ -12,7 +12,7 @@ "@azure/service-bus": "7.9.4", "@grpc/grpc-js": "1.12.0", "@grpc/proto-loader": "0.7.10", - "@napi-rs/canvas": "0.1.47", + "@napi-rs/canvas": "0.1.65", "@prisma/client": "5.8.0", "@remix-run/react": "2.10.3", "@remix-run/serve": "2.10.3", @@ -69,7 +69,8 @@ "webpack": "5.88.0", "webpack-cli": "4.7.2", "xml2js": "0.6.2", - "yargs": "17.7.2" + "yargs": "17.7.2", + "jimp": "1.6.0" }, "private": true, "scripts": { From 540a0a89abadc885f9baa7e6039271945101e6af Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 16 Dec 2024 16:33:15 -0800 Subject: [PATCH 020/125] Fix text input with ink (#15800) --- src/js/builtins/ProcessObjectInternals.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/builtins/ProcessObjectInternals.ts b/src/js/builtins/ProcessObjectInternals.ts index 506596a53f..0cf98e9e37 100644 --- a/src/js/builtins/ProcessObjectInternals.ts +++ b/src/js/builtins/ProcessObjectInternals.ts @@ -126,7 +126,7 @@ export function getStdinStream(fd) { let stream_destroyed = false; let stream_endEmitted = false; - stream.on = function (event, listener) { + stream.addListener = stream.on = function (event, listener) { // Streams don't generally required to present any data when only // `readable` events are present, i.e. `readableFlowing === false` // From 67e4aec990f075342a603289224482fe2ec428a0 Mon Sep 17 00:00:00 2001 From: Michael H Date: Tue, 17 Dec 2024 11:34:55 +1100 Subject: [PATCH 021/125] attempt to fix debugger (#15788) Co-authored-by: RiskyMH --- src/bun.js/bindings/BunDebugger.cpp | 14 ++++---------- src/bun.js/javascript.zig | 18 +++--------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/bun.js/bindings/BunDebugger.cpp b/src/bun.js/bindings/BunDebugger.cpp index 73ac12f028..9b97595917 100644 --- a/src/bun.js/bindings/BunDebugger.cpp +++ b/src/bun.js/bindings/BunDebugger.cpp @@ -54,6 +54,10 @@ public: } void unpauseForInitializedInspector() override { + if (waitingForConnection) { + waitingForConnection = false; + Debugger__didConnect(); + } } }; @@ -120,11 +124,6 @@ public: }; } - if (waitingForConnection) { - waitingForConnection = false; - Debugger__didConnect(); - } - this->receiveMessagesOnInspectorThread(context, reinterpret_cast(globalObject), false); } @@ -153,11 +152,6 @@ public: break; } } - - if (waitingForConnection) { - waitingForConnection = false; - Debugger__didConnect(); - } }); } diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 9fb2fefe70..283739d987 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -2073,16 +2073,12 @@ pub const VirtualMachine = struct { } const unix = bun.getenvZ("BUN_INSPECT") orelse ""; - const notify = bun.getenvZ("BUN_INSPECT_NOTIFY") orelse ""; const connect_to = bun.getenvZ("BUN_INSPECT_CONNECT_TO") orelse ""; const set_breakpoint_on_first_line = unix.len > 0 and strings.endsWith(unix, "?break=1"); // If we should set a breakpoint on the first line const wait_for_debugger = unix.len > 0 and strings.endsWith(unix, "?wait=1"); // If we should wait for the debugger to connect before starting the event loop - const wait_for_connection: Debugger.Wait = switch (set_breakpoint_on_first_line or wait_for_debugger) { - true => if (notify.len > 0 or connect_to.len > 0) .shortly else .forever, - false => .off, - }; + const wait_for_connection: Debugger.Wait = if (set_breakpoint_on_first_line or wait_for_debugger) .forever else .off; switch (cli_flag) { .unspecified => { @@ -2093,22 +2089,14 @@ pub const VirtualMachine = struct { .wait_for_connection = wait_for_connection, .set_breakpoint_on_first_line = set_breakpoint_on_first_line, }; - } else if (notify.len > 0) { - this.debugger = Debugger{ - .path_or_port = null, - .from_environment_variable = notify, - .wait_for_connection = wait_for_connection, - .set_breakpoint_on_first_line = set_breakpoint_on_first_line, - .mode = .connect, - }; } else if (connect_to.len > 0) { // This works in the vscode debug terminal because that relies on unix or notify being set, which they // are in the debug terminal. This branch doesn't reach this.debugger = Debugger{ .path_or_port = null, .from_environment_variable = connect_to, - .wait_for_connection = wait_for_connection, - .set_breakpoint_on_first_line = set_breakpoint_on_first_line, + .wait_for_connection = .off, + .set_breakpoint_on_first_line = false, .mode = .connect, }; } From d5f1f2f8adcf7c345ae0bf1f435893f232fb81ae Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:37:46 -0800 Subject: [PATCH 022/125] Use the same hoisting logic for text lockfile (#15778) --- src/install/bun.lock.zig | 314 +++--------------- src/install/lockfile.zig | 87 ++--- src/install/migration.zig | 11 +- .../bun-install-registry.test.ts.snap | 27 ++ .../registry/bun-install-registry.test.ts | 58 ++++ .../hoist-lockfile-1-1.0.0.tgz | Bin 0 -> 176 bytes .../packages/hoist-lockfile-1/package.json | 44 +++ .../hoist-lockfile-2-1.0.0.tgz | Bin 0 -> 179 bytes .../packages/hoist-lockfile-2/package.json | 44 +++ .../hoist-lockfile-3-1.0.0.tgz | Bin 0 -> 180 bytes .../packages/hoist-lockfile-3/package.json | 44 +++ .../hoist-lockfile-shared-1.0.1.tgz | Bin 0 -> 152 bytes .../hoist-lockfile-shared-1.0.2.tgz | Bin 0 -> 152 bytes .../hoist-lockfile-shared-2.0.1.tgz | Bin 0 -> 152 bytes .../hoist-lockfile-shared-2.0.2.tgz | Bin 0 -> 153 bytes .../hoist-lockfile-shared/package.json | 104 ++++++ .../dev-server-ssr-100.test.ts.snap | 74 +++-- .../__snapshots__/dev-server.test.ts.snap | 74 +++-- .../__snapshots__/next-build.test.ts.snap | 148 ++++++--- 19 files changed, 600 insertions(+), 429 deletions(-) create mode 100644 test/cli/install/registry/packages/hoist-lockfile-1/hoist-lockfile-1-1.0.0.tgz create mode 100644 test/cli/install/registry/packages/hoist-lockfile-1/package.json create mode 100644 test/cli/install/registry/packages/hoist-lockfile-2/hoist-lockfile-2-1.0.0.tgz create mode 100644 test/cli/install/registry/packages/hoist-lockfile-2/package.json create mode 100644 test/cli/install/registry/packages/hoist-lockfile-3/hoist-lockfile-3-1.0.0.tgz create mode 100644 test/cli/install/registry/packages/hoist-lockfile-3/package.json create mode 100644 test/cli/install/registry/packages/hoist-lockfile-shared/hoist-lockfile-shared-1.0.1.tgz create mode 100644 test/cli/install/registry/packages/hoist-lockfile-shared/hoist-lockfile-shared-1.0.2.tgz create mode 100644 test/cli/install/registry/packages/hoist-lockfile-shared/hoist-lockfile-shared-2.0.1.tgz create mode 100644 test/cli/install/registry/packages/hoist-lockfile-shared/hoist-lockfile-shared-2.0.2.tgz create mode 100644 test/cli/install/registry/packages/hoist-lockfile-shared/package.json diff --git a/src/install/bun.lock.zig b/src/install/bun.lock.zig index 8f236189d2..3d24d716f6 100644 --- a/src/install/bun.lock.zig +++ b/src/install/bun.lock.zig @@ -215,182 +215,6 @@ pub const PkgPath = struct { .depth = 0, }; } - - // TODO(dylan-conway): The structure of this map can change - // now that a path buffer is used. Parent isn't needed, and - // keys don't need to be iterated. - pub const Map = struct { - root: Node, - - const Nodes = bun.StringArrayHashMapUnmanaged(Node); - - pub const Node = struct { - pkg_id: PackageID, - dep_id: DependencyID, - parent: ?*Node, - nodes: Nodes, - - pub fn deinit(this: *Node, allocator: std.mem.Allocator) void { - for (this.nodes.values()) |*node| { - node.deinit(allocator); - } - - this.nodes.deinit(allocator); - } - }; - - pub fn init() Map { - return .{ - .root = .{ - .pkg_id = 0, - .dep_id = invalid_dependency_id, - .parent = null, - .nodes = .{}, - }, - }; - } - - pub fn deinit(this: *Map, allocator: std.mem.Allocator) void { - for (this.root.nodes.values()) |*node| { - node.deinit(allocator); - } - } - - const InsertError = OOM || error{ - InvalidPackageKey, - DuplicatePackagePath, - }; - - pub fn insert(this: *Map, allocator: std.mem.Allocator, pkg_path: string, id: PackageID) InsertError!void { - var iter = PkgPath.iterator(pkg_path); - - var parent: ?*Node = null; - var curr: *Node = &this.root; - while (try iter.next()) |name| { - const entry = try curr.nodes.getOrPut(allocator, name); - if (!entry.found_existing) { - // probably should use String.Buf for small strings and - // deduplication. - entry.key_ptr.* = try allocator.dupe(u8, name); - entry.value_ptr.* = .{ - .pkg_id = invalid_package_id, - .dep_id = invalid_dependency_id, - .parent = parent, - .nodes = .{}, - }; - } - - parent = curr; - curr = entry.value_ptr; - } - - if (parent == null) { - return error.InvalidPackageKey; - } - - if (curr.pkg_id != invalid_package_id) { - return error.DuplicatePackagePath; - } - - curr.pkg_id = id; - } - - pub fn get(this: *Map, pkg_path: string) error{InvalidPackageKey}!?*Node { - var iter = iterator(pkg_path); - var curr: *Node = &this.root; - while (try iter.next()) |name| { - curr = curr.nodes.getPtr(name) orelse return null; - } - - return curr; - } - - pub fn iterate(this: *const Map, allocator: std.mem.Allocator) OOM!Map.Iterator { - var tree_buf: std.ArrayListUnmanaged(Map.Iterator.TreeInfo) = .{}; - try tree_buf.append(allocator, .{ - .nodes = this.root.nodes, - .pkg_id = 0, - .dep_id = BinaryLockfile.Tree.root_dep_id, - .id = 0, - .parent_id = BinaryLockfile.Tree.invalid_id, - }); - return .{ - .tree_buf = tree_buf, - .deps_buf = .{}, - }; - } - - /// Breadth-first iterator - pub const Iterator = struct { - tree_buf: std.ArrayListUnmanaged(TreeInfo), - - deps_buf: std.ArrayListUnmanaged(DependencyID), - - pub const TreeInfo = struct { - // name: String, - nodes: Nodes, - pkg_id: PackageID, - dep_id: DependencyID, - id: BinaryLockfile.Tree.Id, - parent_id: BinaryLockfile.Tree.Id, - }; - - pub const Next = struct { - id: BinaryLockfile.Tree.Id, - parent_id: BinaryLockfile.Tree.Id, - tree_dep_id: DependencyID, - dep_ids: []const DependencyID, - }; - - pub fn deinit(this: *Map.Iterator, allocator: std.mem.Allocator) void { - this.tree_buf.deinit(allocator); - this.deps_buf.deinit(allocator); - } - - pub fn next(this: *Map.Iterator, allocator: std.mem.Allocator) OOM!?Next { - if (this.tree_buf.items.len == 0) { - return null; - } - - this.deps_buf.clearRetainingCapacity(); - - var next_id = this.tree_buf.getLast().id + 1; - - // TODO(dylan-conway): try doubly linked list - const tree = this.tree_buf.orderedRemove(0); - - for (tree.nodes.values()) |node| { - if (node.nodes.count() > 0) { - try this.tree_buf.append(allocator, .{ - .nodes = node.nodes, - .id = next_id, - .parent_id = tree.id, - .pkg_id = node.pkg_id, - .dep_id = node.dep_id, - }); - next_id += 1; - } - - try this.deps_buf.append(allocator, node.dep_id); - } - - return .{ - .id = tree.id, - .parent_id = tree.parent_id, - .tree_dep_id = tree.dep_id, - .dep_ids = this.deps_buf.items, - }; - - // return tree; - // .dep_id = tree.dep_id, - // .pkg_id = tree.pkg_id, - // .id = tree.tree_id, - // .parent_id = tree.parent_id, - // .nodes = tree.nodes, - // }; - } - }; - }; }; pub const Version = enum(u32) { @@ -402,6 +226,19 @@ pub const Version = enum(u32) { pub const current: Version = .v0; }; +// For sorting dependencies belonging to a node_modules folder. No duplicate names, so +// only string compare +const TreeDepsSortCtx = struct { + string_buf: string, + deps_buf: []const Dependency, + + pub fn isLessThan(this: @This(), lhs: DependencyID, rhs: DependencyID) bool { + const l = this.deps_buf[lhs]; + const r = this.deps_buf[rhs]; + return strings.cmpStringsAsc({}, l.name.slice(this.string_buf), r.name.slice(this.string_buf)); + } +}; + pub const Stringifier = struct { const indent_scalar = 2; @@ -678,19 +515,8 @@ pub const Stringifier = struct { ); } - const DepSortCtx = struct { - string_buf: string, - deps_buf: []const Dependency, - - pub fn isLessThan(this: @This(), lhs: DependencyID, rhs: DependencyID) bool { - const l = this.deps_buf[lhs]; - const r = this.deps_buf[rhs]; - return strings.cmpStringsAsc({}, l.name.slice(this.string_buf), r.name.slice(this.string_buf)); - } - }; - - var deps_sort_buf: std.ArrayListUnmanaged(DependencyID) = .{}; - defer deps_sort_buf.deinit(allocator); + var tree_deps_sort_buf: std.ArrayListUnmanaged(DependencyID) = .{}; + defer tree_deps_sort_buf.deinit(allocator); var pkg_deps_sort_buf: std.ArrayListUnmanaged(DependencyID) = .{}; defer pkg_deps_sort_buf.deinit(allocator); @@ -700,17 +526,17 @@ pub const Stringifier = struct { var first = true; for (tree_sort_buf.items) |item| { const dependencies, const relative_path, const depth = item; - deps_sort_buf.clearRetainingCapacity(); - try deps_sort_buf.appendSlice(allocator, dependencies); + tree_deps_sort_buf.clearRetainingCapacity(); + try tree_deps_sort_buf.appendSlice(allocator, dependencies); std.sort.pdq( DependencyID, - deps_sort_buf.items, - DepSortCtx{ .string_buf = buf, .deps_buf = deps_buf }, - DepSortCtx.isLessThan, + tree_deps_sort_buf.items, + TreeDepsSortCtx{ .string_buf = buf, .deps_buf = deps_buf }, + TreeDepsSortCtx.isLessThan, ); - for (deps_sort_buf.items) |dep_id| { + for (tree_deps_sort_buf.items) |dep_id| { const pkg_id = resolution_buf[dep_id]; if (pkg_id == invalid_package_id) continue; @@ -758,11 +584,14 @@ pub const Stringifier = struct { pkg_deps_sort_buf.appendAssumeCapacity(@intCast(pkg_dep_id)); } + // there might be duplicate names due to dependency behaviors, + // but we print behaviors in different groups so it won't affect + // the result std.sort.pdq( DependencyID, pkg_deps_sort_buf.items, - DepSortCtx{ .string_buf = buf, .deps_buf = deps_buf }, - DepSortCtx.isLessThan, + TreeDepsSortCtx{ .string_buf = buf, .deps_buf = deps_buf }, + TreeDepsSortCtx.isLessThan, ); // first index is resolution for all dependency types @@ -1444,8 +1273,8 @@ pub fn parseIntoBinaryLockfile( return error.InvalidWorkspaceObject; } - var pkg_map = PkgPath.Map.init(); - defer pkg_map.deinit(allocator); + var pkg_map = bun.StringArrayHashMap(PackageID).init(allocator); + defer pkg_map.deinit(); if (root.get("packages")) |pkgs_expr| { if (!pkgs_expr.isObject()) { @@ -1635,34 +1464,25 @@ pub fn parseIntoBinaryLockfile( const pkg_id = try lockfile.appendPackageDedupe(&pkg, string_buf.bytes.items); - pkg_map.insert(allocator, pkg_path, pkg_id) catch |err| { - switch (err) { - error.OutOfMemory => |oom| return oom, - error.DuplicatePackagePath => { - try log.addError(source, key.loc, "Duplicate package path"); - }, - error.InvalidPackageKey => { - try log.addError(source, key.loc, "Invalid package path"); - }, - } + const entry = try pkg_map.getOrPut(pkg_path); + if (entry.found_existing) { + try log.addError(source, key.loc, "Duplicate package path"); return error.InvalidPackageKey; - }; + } + + entry.value_ptr.* = pkg_id; } try lockfile.buffers.resolutions.ensureTotalCapacityPrecise(allocator, lockfile.buffers.dependencies.items.len); lockfile.buffers.resolutions.expandToCapacity(); @memset(lockfile.buffers.resolutions.items, invalid_package_id); + string_buf.apply(lockfile); + const pkgs = lockfile.packages.slice(); - const pkg_names = pkgs.items(.name); - _ = pkg_names; - const pkg_name_hashes = pkgs.items(.name_hash); - _ = pkg_name_hashes; const pkg_deps = pkgs.items(.dependencies); var pkg_metas = pkgs.items(.meta); var pkg_resolutions = pkgs.items(.resolution); - const pkg_resolution_lists = pkgs.items(.resolutions); - _ = pkg_resolution_lists; { // first the root dependencies are resolved @@ -1673,11 +1493,8 @@ pub fn parseIntoBinaryLockfile( const dep_id: DependencyID = @intCast(_dep_id); const dep = lockfile.buffers.dependencies.items[dep_id]; - if (pkg_map.root.nodes.getPtr(dep.name.slice(string_buf.bytes.items))) |dep_node| { - if (dep_node.dep_id == invalid_dependency_id) { - dep_node.dep_id = dep_id; - } - lockfile.buffers.resolutions.items[dep_id] = dep_node.pkg_id; + if (pkg_map.get(dep.name.slice(lockfile.buffers.string_bytes.items))) |res_pkg_id| { + lockfile.buffers.resolutions.items[dep_id] = res_pkg_id; } } @@ -1690,25 +1507,18 @@ pub fn parseIntoBinaryLockfile( // then each package dependency for (pkgs_expr.data.e_object.properties.slice()) |prop| { const key = prop.key.?; - const value = prop.value.?; const pkg_path = key.asString(allocator).?; - const i: usize = 0; - _ = i; - const pkg_info = value.data.e_array.items; - _ = pkg_info; - const pkg_map_entry = try pkg_map.get(pkg_path) orelse { + const pkg_id = pkg_map.get(pkg_path) orelse { return error.InvalidPackagesObject; }; - const pkg_id = pkg_map_entry.pkg_id; - // find resolutions. iterate up to root through the pkg path. deps: for (pkg_deps[pkg_id].begin()..pkg_deps[pkg_id].end()) |_dep_id| { const dep_id: DependencyID = @intCast(_dep_id); const dep = lockfile.buffers.dependencies.items[dep_id]; - const dep_name = dep.name.slice(string_buf.bytes.items); + const dep_name = dep.name.slice(lockfile.buffers.string_bytes.items); @memcpy(path_buf[0..pkg_path.len], pkg_path); path_buf[pkg_path.len] = '/'; @@ -1719,11 +1529,8 @@ pub fn parseIntoBinaryLockfile( @memcpy(path_buf[offset..][0..dep_name.len], dep_name); const res_path = path_buf[0 .. offset + dep_name.len]; - if (try pkg_map.get(res_path)) |entry| { - if (entry.dep_id == invalid_dependency_id) { - entry.dep_id = dep_id; - } - lockfile.buffers.resolutions.items[dep_id] = entry.pkg_id; + if (pkg_map.get(res_path)) |res_pkg_id| { + lockfile.buffers.resolutions.items[dep_id] = res_pkg_id; continue :deps; } @@ -1779,38 +1586,19 @@ pub fn parseIntoBinaryLockfile( } } - { - // ids are assigned, now flatten into `lockfile.buffers.trees` and `lockfile.buffers.hoisted_dependencies` - var tree_iter = try pkg_map.iterate(allocator); - defer tree_iter.deinit(allocator); - var tree_id: BinaryLockfile.Tree.Id = 0; - while (try tree_iter.next(allocator)) |tree| { - bun.debugAssert(tree_id == tree.id); - const deps_off: u32 = @intCast(lockfile.buffers.hoisted_dependencies.items.len); - const deps_len: u32 = @intCast(tree.dep_ids.len); - try lockfile.buffers.hoisted_dependencies.appendSlice(allocator, tree.dep_ids); - try lockfile.buffers.trees.append( - allocator, - .{ - .dependency_id = tree.tree_dep_id, - .id = tree_id, - .parent = tree.parent_id, - .dependencies = .{ - .off = deps_off, - .len = deps_len, - }, - }, - ); - - tree_id += 1; + lockfile.hoist(log, if (manager) |pm| pm.options.local_package_features.dev_dependencies else true) catch |err| { + switch (err) { + error.OutOfMemory => |oom| return oom, + else => { + return error.InvalidPackagesObject; + }, } - } - } else { - lockfile.initEmpty(allocator); + }; + return; } - string_buf.apply(lockfile); + lockfile.initEmpty(allocator); } fn parseAppendDependencies( diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index c2da337247..311411eadf 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -495,7 +495,7 @@ pub const Tree = struct { }, }; - const SubtreeError = OOM || error{DependencyLoop}; + pub const SubtreeError = OOM || error{DependencyLoop}; // max number of node_modules folders pub const max_depth = (bun.MAX_PATH_BYTES / "node_modules".len) + 1; @@ -841,7 +841,7 @@ pub const Tree = struct { trees: []Tree, builder: *Builder, ) !HoistResult { - const this_dependencies = this.dependencies.mut(dependency_lists[this.id].items); + const this_dependencies = this.dependencies.get(dependency_lists[this.id].items); for (0..this_dependencies.len) |i| { const dep_id = this_dependencies[i]; const dep = builder.dependencies[dep_id]; @@ -896,21 +896,6 @@ pub const Tree = struct { return error.DependencyLoop; } - if (dependency.version.tag == .npm and dep.version.tag == .npm) { - - // if the dependency is wildcard, use the existing dependency - // in the parent - if (dependency.version.value.npm.version.@"is *"()) { - return .hoisted; - } - - // if the parent dependency is wildcard, replace with the - // current dependency - if (dep.version.value.npm.version.@"is *"()) { - return .{ .replace = .{ .dest_id = this.id, .dep_id = dep_id } }; // 4 - } - } - return .dependency_loop; // 3 } @@ -1371,9 +1356,7 @@ const Cloner = struct { pub fn flush(this: *Cloner) anyerror!void { const max_package_id = this.old.packages.len; - while (this.clone_queue.popOrNull()) |to_clone_| { - const to_clone: PendingResolution = to_clone_; - + while (this.clone_queue.popOrNull()) |to_clone| { const mapping = this.mapping[to_clone.old_resolution]; if (mapping < max_package_id) { this.lockfile.buffers.resolutions.items[to_clone.resolve_id] = mapping; @@ -1396,7 +1379,7 @@ const Cloner = struct { this.manager.clearCachedItemsDependingOnLockfileBuffer(); if (this.lockfile.packages.len != 0) { - try this.hoist(this.lockfile); + try this.lockfile.hoist(this.log, this.manager.options.local_package_features.dev_dependencies); } // capacity is used for calculating byte size @@ -1404,39 +1387,39 @@ const Cloner = struct { if (this.lockfile.packages.capacity != this.lockfile.packages.len and this.lockfile.packages.len > 0) this.lockfile.packages.shrinkAndFree(this.lockfile.allocator, this.lockfile.packages.len); } - - fn hoist(this: *Cloner, lockfile: *Lockfile) anyerror!void { - const allocator = lockfile.allocator; - var slice = lockfile.packages.slice(); - var builder = Tree.Builder{ - .name_hashes = slice.items(.name_hash), - .queue = TreeFiller.init(allocator), - .resolution_lists = slice.items(.resolutions), - .resolutions = lockfile.buffers.resolutions.items, - .allocator = allocator, - .dependencies = lockfile.buffers.dependencies.items, - .log = this.log, - .lockfile = lockfile, - .prefer_dev_dependencies = this.manager.options.local_package_features.dev_dependencies, - }; - - try (Tree{}).processSubtree(Tree.root_dep_id, &builder); - // This goes breadth-first - while (builder.queue.readItem()) |item| { - try builder.list.items(.tree)[item.tree_id].processSubtree(item.dependency_id, &builder); - } - - lockfile.buffers.hoisted_dependencies = try builder.clean(); - { - const final = builder.list.items(.tree); - lockfile.buffers.trees = .{ - .items = final, - .capacity = final.len, - }; - } - } }; +pub fn hoist(lockfile: *Lockfile, log: *logger.Log, prefer_dev_dependencies: bool) Tree.SubtreeError!void { + const allocator = lockfile.allocator; + var slice = lockfile.packages.slice(); + var builder = Tree.Builder{ + .name_hashes = slice.items(.name_hash), + .queue = TreeFiller.init(allocator), + .resolution_lists = slice.items(.resolutions), + .resolutions = lockfile.buffers.resolutions.items, + .allocator = allocator, + .dependencies = lockfile.buffers.dependencies.items, + .log = log, + .lockfile = lockfile, + .prefer_dev_dependencies = prefer_dev_dependencies, + }; + + try (Tree{}).processSubtree(Tree.root_dep_id, &builder); + // This goes breadth-first + while (builder.queue.readItem()) |item| { + try builder.list.items(.tree)[item.tree_id].processSubtree(item.dependency_id, &builder); + } + + lockfile.buffers.hoisted_dependencies = try builder.clean(); + { + const final = builder.list.items(.tree); + lockfile.buffers.trees = .{ + .items = final, + .capacity = final.len, + }; + } +} + const PendingResolution = struct { old_resolution: PackageID, resolve_id: PackageID, diff --git a/src/install/migration.zig b/src/install/migration.zig index 664df225a2..41c8f606dd 100644 --- a/src/install/migration.zig +++ b/src/install/migration.zig @@ -1056,16 +1056,7 @@ pub fn migrateNPMLockfile( return error.NotAllPackagesGotResolved; } - // if (Environment.isDebug) { - // const dump_file = try std.fs.cwd().createFileZ("before-clean.json", .{}); - // defer dump_file.close(); - // try std.json.stringify(this, .{ .whitespace = .indent_2 }, dump_file.writer()); - // } - - // This is definitely a memory leak, but it's fine because there is no install api, so this can only be leaked once per process. - // This operation is neccecary because callers of `loadFromCwd` assume the data is written into the passed `this`. - // You'll find that not cleaning the lockfile will cause `bun install` to not actually install anything since it doesnt have any hoisted trees. - this.* = (try this.cleanWithLogger(manager, &.{}, log, false, .silent)).*; + try this.hoist(log, manager.options.local_package_features.dev_dependencies); // if (Environment.isDebug) { // const dump_file = try std.fs.cwd().createFileZ("after-clean.json", .{}); diff --git a/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap b/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap index 6b04de3ea8..a58e5d1e73 100644 --- a/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap +++ b/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap @@ -284,3 +284,30 @@ exports[`binaries root resolution bins 1`] = ` } " `; + +exports[`hoisting text lockfile is hoisted 1`] = ` +"{ + "lockfileVersion": 0, + "workspaces": { + "": { + "dependencies": { + "hoist-lockfile-1": "1.0.0", + "hoist-lockfile-2": "1.0.0", + "hoist-lockfile-3": "1.0.0", + }, + }, + }, + "packages": { + "hoist-lockfile-1": ["hoist-lockfile-1@1.0.0", "http://localhost:1234/hoist-lockfile-1/-/hoist-lockfile-1-1.0.0.tgz", { "dependencies": { "hoist-lockfile-shared": "*" } }, "sha512-E2nwR7egMFDoYjeRno7CAa59kiwkLGfhTFy2Q335JWp2r2bDkwoAt1LdChd5PdGYkbo7SfViHkW44ga+WXA+eA=="], + + "hoist-lockfile-2": ["hoist-lockfile-2@1.0.0", "http://localhost:1234/hoist-lockfile-2/-/hoist-lockfile-2-1.0.0.tgz", { "dependencies": { "hoist-lockfile-shared": "^1.0.1" } }, "sha512-7iNRBJF/U078n9oZW7aDvVLkA7+076a2ONEFvITpjKdhT07KWaBei0SzHkFYW4f3foGZPNlHsv0aAgk949TPJg=="], + + "hoist-lockfile-3": ["hoist-lockfile-3@1.0.0", "http://localhost:1234/hoist-lockfile-3/-/hoist-lockfile-3-1.0.0.tgz", { "dependencies": { "hoist-lockfile-shared": ">=1.0.1" } }, "sha512-iGz7jH7jxz/zq4OZM8hhT7kUX2Ye1m+45SoyMVcWTM7ZB+cY306Ff1mQePKTjkn84/pJMITMdRgDv/qF8PuQUw=="], + + "hoist-lockfile-shared": ["hoist-lockfile-shared@2.0.2", "http://localhost:1234/hoist-lockfile-shared/-/hoist-lockfile-shared-2.0.2.tgz", {}, "sha512-xPWoyP8lv+/JrbClRzhJx1eUsHqDflSTmWOxx82xvMIEs6mbiIuvIp3/L+Ojc6mqex6y426h7L5j0hjLZE3V9w=="], + + "hoist-lockfile-2/hoist-lockfile-shared": ["hoist-lockfile-shared@1.0.2", "http://localhost:1234/hoist-lockfile-shared/-/hoist-lockfile-shared-1.0.2.tgz", {}, "sha512-p7IQ/BbkTRLG/GUx6j2cDQ+vTUc/v9OW9Ss9igh/GFysbr0Qjriz/DiETnISkxYaTFitqOkUSOUkEKyeLNJsfQ=="], + } +} +" +`; diff --git a/test/cli/install/registry/bun-install-registry.test.ts b/test/cli/install/registry/bun-install-registry.test.ts index 203397a828..18474bcb0c 100644 --- a/test/cli/install/registry/bun-install-registry.test.ts +++ b/test/cli/install/registry/bun-install-registry.test.ts @@ -4780,6 +4780,64 @@ describe("hoisting", async () => { }); }); }); + + test("text lockfile is hoisted", async () => { + // Each dependency depends on 'hoist-lockfile-shared'. + // 1 - "*" + // 2 - "^1.0.1" + // 3 - ">=1.0.1" + await write( + packageJson, + JSON.stringify({ + name: "foo", + dependencies: { + "hoist-lockfile-1": "1.0.0", + "hoist-lockfile-2": "1.0.0", + "hoist-lockfile-3": "1.0.0", + }, + }), + ); + + let { exited, stderr } = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile"], + cwd: packageDir, + stderr: "pipe", + stdout: "ignore", + env, + }); + + let err = await Bun.readableStreamToText(stderr); + expect(err).toContain("Saved lockfile"); + expect(err).not.toContain("error:"); + + expect(await exited).toBe(0); + + const lockfile = (await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + expect(lockfile).toMatchSnapshot(); + + // second install should not save the lockfile + // with a different set of resolutions + ({ exited, stderr } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stderr: "pipe", + stdout: "ignore", + env, + })); + + err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("Saved lockfile"); + expect(err).not.toContain("error:"); + + expect(await exited).toBe(0); + + expect((await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll(/localhost:\d+/g, "localhost:1234")).toBe( + lockfile, + ); + }); }); describe("workspaces", async () => { diff --git a/test/cli/install/registry/packages/hoist-lockfile-1/hoist-lockfile-1-1.0.0.tgz b/test/cli/install/registry/packages/hoist-lockfile-1/hoist-lockfile-1-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..d44c7526c8e4a42d38b5c4fe809cc5818f3400ee GIT binary patch literal 176 zcmV;h08jrPiwFP!00002|LxCB4uUWc1>mkZ#iUCk_!_VaZqvXh6>JGbH-@{LhLyS{ zMw5PqiK3`=EJyVaS7gujRDYAMKJ-qC!jP4CBa7O|tVg%=zG({$vNvmE6bfou^>Eivy}afwkK5$gXAASPrtLc!xeN egw9Od#?76~h?Z;-Ns=VVPj~{o)i;O$2mk=1j8SX= literal 0 HcmV?d00001 diff --git a/test/cli/install/registry/packages/hoist-lockfile-1/package.json b/test/cli/install/registry/packages/hoist-lockfile-1/package.json new file mode 100644 index 0000000000..54b1a2b812 --- /dev/null +++ b/test/cli/install/registry/packages/hoist-lockfile-1/package.json @@ -0,0 +1,44 @@ +{ + "name": "hoist-lockfile-1", + "versions": { + "1.0.0": { + "name": "hoist-lockfile-1", + "version": "1.0.0", + "dependencies": { + "hoist-lockfile-shared": "*" + }, + "_id": "hoist-lockfile-1@1.0.0", + "_integrity": "sha512-E2nwR7egMFDoYjeRno7CAa59kiwkLGfhTFy2Q335JWp2r2bDkwoAt1LdChd5PdGYkbo7SfViHkW44ga+WXA+eA==", + "_nodeVersion": "22.6.0", + "_npmVersion": "10.8.3", + "integrity": "sha512-E2nwR7egMFDoYjeRno7CAa59kiwkLGfhTFy2Q335JWp2r2bDkwoAt1LdChd5PdGYkbo7SfViHkW44ga+WXA+eA==", + "shasum": "5765633927473de7697d72d0c0d6bfe04b6a7c71", + "dist": { + "integrity": "sha512-E2nwR7egMFDoYjeRno7CAa59kiwkLGfhTFy2Q335JWp2r2bDkwoAt1LdChd5PdGYkbo7SfViHkW44ga+WXA+eA==", + "shasum": "5765633927473de7697d72d0c0d6bfe04b6a7c71", + "tarball": "http://http://localhost:4873/hoist-lockfile-1/-/hoist-lockfile-1-1.0.0.tgz" + }, + "contributors": [] + } + }, + "time": { + "modified": "2024-12-15T10:01:42.154Z", + "created": "2024-12-15T10:01:42.154Z", + "1.0.0": "2024-12-15T10:01:42.154Z" + }, + "users": {}, + "dist-tags": { + "latest": "1.0.0" + }, + "_uplinks": {}, + "_distfiles": {}, + "_attachments": { + "hoist-lockfile-1-1.0.0.tgz": { + "shasum": "5765633927473de7697d72d0c0d6bfe04b6a7c71", + "version": "1.0.0" + } + }, + "_rev": "", + "_id": "hoist-lockfile-1", + "readme": "" +} \ No newline at end of file diff --git a/test/cli/install/registry/packages/hoist-lockfile-2/hoist-lockfile-2-1.0.0.tgz b/test/cli/install/registry/packages/hoist-lockfile-2/hoist-lockfile-2-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..e2fe749decd735c630f63daf61e93d42f0d818b6 GIT binary patch literal 179 zcmV;k08IZMiwFP!00002|LxCB4uUWc1>mkZ#iVP&SAi}#j7bBdRIm_=ZVY!f4J&m^ zG$#EvFPXn&MpJj@%=>Z8?BWL}HU>Z!1%(9go`BLNAulzQ(i#Opk hF8J0=+=R_zSXDA1T9QRXQ4~eL_5>?qp349T002sTPRRfO literal 0 HcmV?d00001 diff --git a/test/cli/install/registry/packages/hoist-lockfile-2/package.json b/test/cli/install/registry/packages/hoist-lockfile-2/package.json new file mode 100644 index 0000000000..ae6a8286eb --- /dev/null +++ b/test/cli/install/registry/packages/hoist-lockfile-2/package.json @@ -0,0 +1,44 @@ +{ + "name": "hoist-lockfile-2", + "versions": { + "1.0.0": { + "name": "hoist-lockfile-2", + "version": "1.0.0", + "dependencies": { + "hoist-lockfile-shared": "^1.0.1" + }, + "_id": "hoist-lockfile-2@1.0.0", + "_integrity": "sha512-7iNRBJF/U078n9oZW7aDvVLkA7+076a2ONEFvITpjKdhT07KWaBei0SzHkFYW4f3foGZPNlHsv0aAgk949TPJg==", + "_nodeVersion": "22.6.0", + "_npmVersion": "10.8.3", + "integrity": "sha512-7iNRBJF/U078n9oZW7aDvVLkA7+076a2ONEFvITpjKdhT07KWaBei0SzHkFYW4f3foGZPNlHsv0aAgk949TPJg==", + "shasum": "9d4e79abefd802c410cb2710daeccfda9ecf8995", + "dist": { + "integrity": "sha512-7iNRBJF/U078n9oZW7aDvVLkA7+076a2ONEFvITpjKdhT07KWaBei0SzHkFYW4f3foGZPNlHsv0aAgk949TPJg==", + "shasum": "9d4e79abefd802c410cb2710daeccfda9ecf8995", + "tarball": "http://http://localhost:4873/hoist-lockfile-2/-/hoist-lockfile-2-1.0.0.tgz" + }, + "contributors": [] + } + }, + "time": { + "modified": "2024-12-15T10:02:22.248Z", + "created": "2024-12-15T10:02:22.248Z", + "1.0.0": "2024-12-15T10:02:22.248Z" + }, + "users": {}, + "dist-tags": { + "latest": "1.0.0" + }, + "_uplinks": {}, + "_distfiles": {}, + "_attachments": { + "hoist-lockfile-2-1.0.0.tgz": { + "shasum": "9d4e79abefd802c410cb2710daeccfda9ecf8995", + "version": "1.0.0" + } + }, + "_rev": "", + "_id": "hoist-lockfile-2", + "readme": "" +} \ No newline at end of file diff --git a/test/cli/install/registry/packages/hoist-lockfile-3/hoist-lockfile-3-1.0.0.tgz b/test/cli/install/registry/packages/hoist-lockfile-3/hoist-lockfile-3-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3bf1f448c946e6a32b0dcdc0753cd47478c2b47c GIT binary patch literal 180 zcmV;l089TLiwFP!00002|LxDu3W7io2Jk)m6vLj=zCqhVQ17znl%}oXT9@$MWARj7 zr3m(S`C$IR47P0TS+>KH*~Rxxtqg!E3JM9}Jpnd`knaqbjX^=+oS79teZkF7c2vL$ zPrf|&CmsorcJ?ZIPrB|KKc!t?wx_0(G}oKZz02sE-h~0qkYTA-GKj0hm5q44r*MZp iF8JDxQiaXqA?&hFh~{KgQ4~edk39iRGa)_z2mk=1.0.1" + }, + "_id": "hoist-lockfile-3@1.0.0", + "_integrity": "sha512-iGz7jH7jxz/zq4OZM8hhT7kUX2Ye1m+45SoyMVcWTM7ZB+cY306Ff1mQePKTjkn84/pJMITMdRgDv/qF8PuQUw==", + "_nodeVersion": "22.6.0", + "_npmVersion": "10.8.3", + "integrity": "sha512-iGz7jH7jxz/zq4OZM8hhT7kUX2Ye1m+45SoyMVcWTM7ZB+cY306Ff1mQePKTjkn84/pJMITMdRgDv/qF8PuQUw==", + "shasum": "04cab7133b1c33a55aa0b8158d0f615ebdc4b99c", + "dist": { + "integrity": "sha512-iGz7jH7jxz/zq4OZM8hhT7kUX2Ye1m+45SoyMVcWTM7ZB+cY306Ff1mQePKTjkn84/pJMITMdRgDv/qF8PuQUw==", + "shasum": "04cab7133b1c33a55aa0b8158d0f615ebdc4b99c", + "tarball": "http://http://localhost:4873/hoist-lockfile-3/-/hoist-lockfile-3-1.0.0.tgz" + }, + "contributors": [] + } + }, + "time": { + "modified": "2024-12-15T10:02:33.352Z", + "created": "2024-12-15T10:02:33.352Z", + "1.0.0": "2024-12-15T10:02:33.352Z" + }, + "users": {}, + "dist-tags": { + "latest": "1.0.0" + }, + "_uplinks": {}, + "_distfiles": {}, + "_attachments": { + "hoist-lockfile-3-1.0.0.tgz": { + "shasum": "04cab7133b1c33a55aa0b8158d0f615ebdc4b99c", + "version": "1.0.0" + } + }, + "_rev": "", + "_id": "hoist-lockfile-3", + "readme": "" +} \ No newline at end of file diff --git a/test/cli/install/registry/packages/hoist-lockfile-shared/hoist-lockfile-shared-1.0.1.tgz b/test/cli/install/registry/packages/hoist-lockfile-shared/hoist-lockfile-shared-1.0.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..cf3aca12ca4d34006e8bb942f0442397654d2853 GIT binary patch literal 152 zcmV;J0B8RniwFP!00002|LxDQ4#FT5g<NNEf-K`IHu2<#8;dA5lG3!MBq zw-V2WhzEOf{7AfyKF{qKyW#9d*XG_PcjB8edAO8)3}qz+#Ev&FR#jD1t=AjLhd#*w G2mkNNEf-K`IHu2<#8;dA5lG3!MBq zw-V2WhzEOf{7AfyKF{qKyW#9d*XG_PcjB8edAO8)3}v+w5Rx}9R#jD1t=AjQ>^$TE G2mkluhpP H00;m8m_$d4 literal 0 HcmV?d00001 diff --git a/test/cli/install/registry/packages/hoist-lockfile-shared/package.json b/test/cli/install/registry/packages/hoist-lockfile-shared/package.json new file mode 100644 index 0000000000..969fa9dd4e --- /dev/null +++ b/test/cli/install/registry/packages/hoist-lockfile-shared/package.json @@ -0,0 +1,104 @@ +{ + "name": "hoist-lockfile-shared", + "versions": { + "1.0.1": { + "name": "hoist-lockfile-shared", + "version": "1.0.1", + "_id": "hoist-lockfile-shared@1.0.1", + "_integrity": "sha512-wPw8pTRj2OeZ/n7NeixjaSeI7FoM9DbMHWzdLv1kuBesSXJn+17UA0N7LV7t9dREnIMLw7ycRomhDL+56NRBmQ==", + "_nodeVersion": "22.6.0", + "_npmVersion": "10.8.3", + "integrity": "sha512-wPw8pTRj2OeZ/n7NeixjaSeI7FoM9DbMHWzdLv1kuBesSXJn+17UA0N7LV7t9dREnIMLw7ycRomhDL+56NRBmQ==", + "shasum": "fde345ca6900e410c285e0468c8baf1e97400899", + "dist": { + "integrity": "sha512-wPw8pTRj2OeZ/n7NeixjaSeI7FoM9DbMHWzdLv1kuBesSXJn+17UA0N7LV7t9dREnIMLw7ycRomhDL+56NRBmQ==", + "shasum": "fde345ca6900e410c285e0468c8baf1e97400899", + "tarball": "http://http://localhost:4873/hoist-lockfile-shared/-/hoist-lockfile-shared-1.0.1.tgz" + }, + "contributors": [] + }, + "1.0.2": { + "name": "hoist-lockfile-shared", + "version": "1.0.2", + "_id": "hoist-lockfile-shared@1.0.2", + "_integrity": "sha512-p7IQ/BbkTRLG/GUx6j2cDQ+vTUc/v9OW9Ss9igh/GFysbr0Qjriz/DiETnISkxYaTFitqOkUSOUkEKyeLNJsfQ==", + "_nodeVersion": "22.6.0", + "_npmVersion": "10.8.3", + "integrity": "sha512-p7IQ/BbkTRLG/GUx6j2cDQ+vTUc/v9OW9Ss9igh/GFysbr0Qjriz/DiETnISkxYaTFitqOkUSOUkEKyeLNJsfQ==", + "shasum": "027dac365f2e611c171bbca4f3cad0d0dd17d3c1", + "dist": { + "integrity": "sha512-p7IQ/BbkTRLG/GUx6j2cDQ+vTUc/v9OW9Ss9igh/GFysbr0Qjriz/DiETnISkxYaTFitqOkUSOUkEKyeLNJsfQ==", + "shasum": "027dac365f2e611c171bbca4f3cad0d0dd17d3c1", + "tarball": "http://http://localhost:4873/hoist-lockfile-shared/-/hoist-lockfile-shared-1.0.2.tgz" + }, + "contributors": [] + }, + "2.0.1": { + "name": "hoist-lockfile-shared", + "version": "2.0.1", + "_id": "hoist-lockfile-shared@2.0.1", + "_integrity": "sha512-r5/0DwsWyuolaBZtsYFTP0jBhwvDGNIekb/KrgBlPSROcYEgggIFBAuMPe2uU5CrsLkSH+MTc++K/reLLXgHNQ==", + "_nodeVersion": "22.6.0", + "_npmVersion": "10.8.3", + "integrity": "sha512-r5/0DwsWyuolaBZtsYFTP0jBhwvDGNIekb/KrgBlPSROcYEgggIFBAuMPe2uU5CrsLkSH+MTc++K/reLLXgHNQ==", + "shasum": "e125f0cb27dd6e6fd8871060dbf6fba36ad1f917", + "dist": { + "integrity": "sha512-r5/0DwsWyuolaBZtsYFTP0jBhwvDGNIekb/KrgBlPSROcYEgggIFBAuMPe2uU5CrsLkSH+MTc++K/reLLXgHNQ==", + "shasum": "e125f0cb27dd6e6fd8871060dbf6fba36ad1f917", + "tarball": "http://http://localhost:4873/hoist-lockfile-shared/-/hoist-lockfile-shared-2.0.1.tgz" + }, + "contributors": [] + }, + "2.0.2": { + "name": "hoist-lockfile-shared", + "version": "2.0.2", + "_id": "hoist-lockfile-shared@2.0.2", + "_integrity": "sha512-xPWoyP8lv+/JrbClRzhJx1eUsHqDflSTmWOxx82xvMIEs6mbiIuvIp3/L+Ojc6mqex6y426h7L5j0hjLZE3V9w==", + "_nodeVersion": "22.6.0", + "_npmVersion": "10.8.3", + "integrity": "sha512-xPWoyP8lv+/JrbClRzhJx1eUsHqDflSTmWOxx82xvMIEs6mbiIuvIp3/L+Ojc6mqex6y426h7L5j0hjLZE3V9w==", + "shasum": "1ca0ded36e6aa42702055f61e9d65083831ae849", + "dist": { + "integrity": "sha512-xPWoyP8lv+/JrbClRzhJx1eUsHqDflSTmWOxx82xvMIEs6mbiIuvIp3/L+Ojc6mqex6y426h7L5j0hjLZE3V9w==", + "shasum": "1ca0ded36e6aa42702055f61e9d65083831ae849", + "tarball": "http://http://localhost:4873/hoist-lockfile-shared/-/hoist-lockfile-shared-2.0.2.tgz" + }, + "contributors": [] + } + }, + "time": { + "modified": "2024-12-15T09:57:52.172Z", + "created": "2024-12-15T09:57:36.725Z", + "1.0.1": "2024-12-15T09:57:36.725Z", + "1.0.2": "2024-12-15T09:57:44.209Z", + "2.0.1": "2024-12-15T09:57:49.265Z", + "2.0.2": "2024-12-15T09:57:52.172Z" + }, + "users": {}, + "dist-tags": { + "latest": "2.0.2" + }, + "_uplinks": {}, + "_distfiles": {}, + "_attachments": { + "hoist-lockfile-shared-1.0.1.tgz": { + "shasum": "fde345ca6900e410c285e0468c8baf1e97400899", + "version": "1.0.1" + }, + "hoist-lockfile-shared-1.0.2.tgz": { + "shasum": "027dac365f2e611c171bbca4f3cad0d0dd17d3c1", + "version": "1.0.2" + }, + "hoist-lockfile-shared-2.0.1.tgz": { + "shasum": "e125f0cb27dd6e6fd8871060dbf6fba36ad1f917", + "version": "2.0.1" + }, + "hoist-lockfile-shared-2.0.2.tgz": { + "shasum": "1ca0ded36e6aa42702055f61e9d65083831ae849", + "version": "2.0.2" + } + }, + "_rev": "", + "_id": "hoist-lockfile-shared", + "readme": "" +} \ No newline at end of file diff --git a/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap b/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap index 34dee403a4..e241842aa7 100644 --- a/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap @@ -22258,6 +22258,17 @@ exports[`ssr works for 100-ish requests 1`] = ` "id": 2, "path": "node_modules/next/node_modules", }, + { + "dependencies": { + "@types/node": { + "id": 863, + "package_id": 183, + }, + }, + "depth": 1, + "id": 3, + "path": "node_modules/@types/ws/node_modules", + }, { "dependencies": { "debug": { @@ -22266,7 +22277,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 3, + "id": 4, "path": "node_modules/eslint-import-resolver-node/node_modules", }, { @@ -22281,7 +22292,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 4, + "id": 5, "path": "node_modules/eslint-plugin-import/node_modules", }, { @@ -22296,7 +22307,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 6, "path": "node_modules/eslint-plugin-react/node_modules", }, { @@ -22311,7 +22322,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 6, + "id": 7, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22322,7 +22333,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 8, "path": "node_modules/chokidar/node_modules", }, { @@ -22333,7 +22344,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 9, "path": "node_modules/fast-glob/node_modules", }, { @@ -22344,7 +22355,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 10, "path": "node_modules/postcss-load-config/node_modules", }, { @@ -22355,7 +22366,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 11, "path": "node_modules/glob/node_modules", }, { @@ -22370,7 +22381,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 11, + "id": 12, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, { @@ -22381,7 +22392,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 13, "path": "node_modules/eslint-module-utils/node_modules", }, { @@ -22392,7 +22403,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 13, + "id": 14, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22403,7 +22414,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 14, + "id": 15, "path": "node_modules/rimraf/node_modules", }, { @@ -22414,7 +22425,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 15, + "id": 16, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22425,7 +22436,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 16, + "id": 17, "path": "node_modules/path-scurry/node_modules", }, { @@ -22436,7 +22447,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 17, + "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", }, { @@ -22447,9 +22458,20 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 18, + "id": 19, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, + { + "dependencies": { + "@types/node": { + "id": 254, + "package_id": 183, + }, + }, + "depth": 1, + "id": 20, + "path": "node_modules/@types/yauzl/node_modules", + }, { "dependencies": { "emoji-regex": { @@ -22458,7 +22480,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 19, + "id": 21, "path": "node_modules/string-width/node_modules", }, { @@ -22477,7 +22499,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 20, + "id": 22, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22488,7 +22510,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 23, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22499,7 +22521,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 24, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22510,7 +22532,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 23, + "id": 25, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22521,7 +22543,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 24, + "id": 26, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22540,7 +22562,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22551,7 +22573,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 3, - "id": 26, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22562,7 +22584,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 3, - "id": 27, + "id": 29, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22573,7 +22595,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 4, - "id": 28, + "id": 30, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], diff --git a/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap b/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap index e6a7d3b26d..536715c42b 100644 --- a/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap @@ -22258,6 +22258,17 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "id": 2, "path": "node_modules/next/node_modules", }, + { + "dependencies": { + "@types/node": { + "id": 863, + "package_id": 183, + }, + }, + "depth": 1, + "id": 3, + "path": "node_modules/@types/ws/node_modules", + }, { "dependencies": { "debug": { @@ -22266,7 +22277,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 3, + "id": 4, "path": "node_modules/eslint-import-resolver-node/node_modules", }, { @@ -22281,7 +22292,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 4, + "id": 5, "path": "node_modules/eslint-plugin-import/node_modules", }, { @@ -22296,7 +22307,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 6, "path": "node_modules/eslint-plugin-react/node_modules", }, { @@ -22311,7 +22322,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 6, + "id": 7, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22322,7 +22333,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 8, "path": "node_modules/chokidar/node_modules", }, { @@ -22333,7 +22344,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 9, "path": "node_modules/fast-glob/node_modules", }, { @@ -22344,7 +22355,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 10, "path": "node_modules/postcss-load-config/node_modules", }, { @@ -22355,7 +22366,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 11, "path": "node_modules/glob/node_modules", }, { @@ -22370,7 +22381,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 11, + "id": 12, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, { @@ -22381,7 +22392,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 13, "path": "node_modules/eslint-module-utils/node_modules", }, { @@ -22392,7 +22403,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 13, + "id": 14, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22403,7 +22414,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 14, + "id": 15, "path": "node_modules/rimraf/node_modules", }, { @@ -22414,7 +22425,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 15, + "id": 16, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22425,7 +22436,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 16, + "id": 17, "path": "node_modules/path-scurry/node_modules", }, { @@ -22436,7 +22447,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 17, + "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", }, { @@ -22447,9 +22458,20 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 18, + "id": 19, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, + { + "dependencies": { + "@types/node": { + "id": 254, + "package_id": 183, + }, + }, + "depth": 1, + "id": 20, + "path": "node_modules/@types/yauzl/node_modules", + }, { "dependencies": { "emoji-regex": { @@ -22458,7 +22480,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 19, + "id": 21, "path": "node_modules/string-width/node_modules", }, { @@ -22477,7 +22499,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 20, + "id": 22, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22488,7 +22510,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 23, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22499,7 +22521,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 24, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22510,7 +22532,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 23, + "id": 25, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22521,7 +22543,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 24, + "id": 26, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22540,7 +22562,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22551,7 +22573,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 3, - "id": 26, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22562,7 +22584,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 3, - "id": 27, + "id": 29, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22573,7 +22595,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 4, - "id": 28, + "id": 30, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], diff --git a/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap b/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap index 4f39ea6a16..a7e9af8b95 100644 --- a/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap @@ -22258,6 +22258,17 @@ exports[`next build works: bun 1`] = ` "id": 2, "path": "node_modules/next/node_modules", }, + { + "dependencies": { + "@types/node": { + "id": 863, + "package_id": 183, + }, + }, + "depth": 1, + "id": 3, + "path": "node_modules/@types/ws/node_modules", + }, { "dependencies": { "debug": { @@ -22266,7 +22277,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 3, + "id": 4, "path": "node_modules/eslint-import-resolver-node/node_modules", }, { @@ -22281,7 +22292,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 4, + "id": 5, "path": "node_modules/eslint-plugin-import/node_modules", }, { @@ -22296,7 +22307,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 6, "path": "node_modules/eslint-plugin-react/node_modules", }, { @@ -22311,7 +22322,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 6, + "id": 7, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22322,7 +22333,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 8, "path": "node_modules/chokidar/node_modules", }, { @@ -22333,7 +22344,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 9, "path": "node_modules/fast-glob/node_modules", }, { @@ -22344,7 +22355,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 10, "path": "node_modules/postcss-load-config/node_modules", }, { @@ -22355,7 +22366,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 11, "path": "node_modules/glob/node_modules", }, { @@ -22370,7 +22381,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 11, + "id": 12, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, { @@ -22381,7 +22392,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 13, "path": "node_modules/eslint-module-utils/node_modules", }, { @@ -22392,7 +22403,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 13, + "id": 14, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22403,7 +22414,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 14, + "id": 15, "path": "node_modules/rimraf/node_modules", }, { @@ -22414,7 +22425,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 15, + "id": 16, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22425,7 +22436,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 16, + "id": 17, "path": "node_modules/path-scurry/node_modules", }, { @@ -22436,7 +22447,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 17, + "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", }, { @@ -22447,9 +22458,20 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 18, + "id": 19, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, + { + "dependencies": { + "@types/node": { + "id": 254, + "package_id": 183, + }, + }, + "depth": 1, + "id": 20, + "path": "node_modules/@types/yauzl/node_modules", + }, { "dependencies": { "emoji-regex": { @@ -22458,7 +22480,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 19, + "id": 21, "path": "node_modules/string-width/node_modules", }, { @@ -22477,7 +22499,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 20, + "id": 22, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22488,7 +22510,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 23, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22499,7 +22521,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 24, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22510,7 +22532,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 23, + "id": 25, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22521,7 +22543,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 24, + "id": 26, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22540,7 +22562,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22551,7 +22573,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 3, - "id": 26, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22562,7 +22584,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 3, - "id": 27, + "id": 29, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22573,7 +22595,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 4, - "id": 28, + "id": 30, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], @@ -44840,6 +44862,17 @@ exports[`next build works: node 1`] = ` "id": 2, "path": "node_modules/next/node_modules", }, + { + "dependencies": { + "@types/node": { + "id": 863, + "package_id": 183, + }, + }, + "depth": 1, + "id": 3, + "path": "node_modules/@types/ws/node_modules", + }, { "dependencies": { "debug": { @@ -44848,7 +44881,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 3, + "id": 4, "path": "node_modules/eslint-import-resolver-node/node_modules", }, { @@ -44863,7 +44896,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 4, + "id": 5, "path": "node_modules/eslint-plugin-import/node_modules", }, { @@ -44878,7 +44911,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 6, "path": "node_modules/eslint-plugin-react/node_modules", }, { @@ -44893,7 +44926,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 6, + "id": 7, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -44904,7 +44937,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 8, "path": "node_modules/chokidar/node_modules", }, { @@ -44915,7 +44948,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 9, "path": "node_modules/fast-glob/node_modules", }, { @@ -44926,7 +44959,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 10, "path": "node_modules/postcss-load-config/node_modules", }, { @@ -44937,7 +44970,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 11, "path": "node_modules/glob/node_modules", }, { @@ -44952,7 +44985,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 11, + "id": 12, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, { @@ -44963,7 +44996,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 13, "path": "node_modules/eslint-module-utils/node_modules", }, { @@ -44974,7 +45007,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 13, + "id": 14, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -44985,7 +45018,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 14, + "id": 15, "path": "node_modules/rimraf/node_modules", }, { @@ -44996,7 +45029,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 15, + "id": 16, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -45007,7 +45040,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 16, + "id": 17, "path": "node_modules/path-scurry/node_modules", }, { @@ -45018,7 +45051,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 17, + "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", }, { @@ -45029,9 +45062,20 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 18, + "id": 19, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, + { + "dependencies": { + "@types/node": { + "id": 254, + "package_id": 183, + }, + }, + "depth": 1, + "id": 20, + "path": "node_modules/@types/yauzl/node_modules", + }, { "dependencies": { "emoji-regex": { @@ -45040,7 +45084,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 19, + "id": 21, "path": "node_modules/string-width/node_modules", }, { @@ -45059,7 +45103,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 20, + "id": 22, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -45070,7 +45114,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 23, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -45081,7 +45125,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 24, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -45092,7 +45136,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 23, + "id": 25, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -45103,7 +45147,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 24, + "id": 26, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -45122,7 +45166,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -45133,7 +45177,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 3, - "id": 26, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -45144,7 +45188,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 3, - "id": 27, + "id": 29, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -45155,7 +45199,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 4, - "id": 28, + "id": 30, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], From e8b85cff4066ebb4868219b2ad543a81d412600f Mon Sep 17 00:00:00 2001 From: Ashcon Partovi Date: Mon, 16 Dec 2024 17:04:33 -0800 Subject: [PATCH 023/125] ci: Retry and detect flaky tests (#15798) --- scripts/runner.node.mjs | 133 ++++++++---- test/bundler/bundler_edgecase.test.ts | 2 +- test/bundler/bundler_plugin.test.ts | 3 +- test/bundler/expectBundled.ts | 10 +- test/cli/run/require-cache.test.ts | 4 +- test/harness.ts | 4 +- test/js/bun/http/serve.test.ts | 167 +++++++-------- test/js/node/fs/fs.test.ts | 107 ++++------ test/v8/v8.test.ts | 280 +++++++++++++------------- 9 files changed, 368 insertions(+), 342 deletions(-) diff --git a/scripts/runner.node.mjs b/scripts/runner.node.mjs index 17c27bdc14..969ea1e5db 100755 --- a/scripts/runner.node.mjs +++ b/scripts/runner.node.mjs @@ -102,6 +102,10 @@ const { values: options, positionals: filters } = parseArgs({ type: "string", default: undefined, }, + ["retries"]: { + type: "string", + default: isCI ? "4" : "0", // N retries = N+1 attempts + }, }, }); @@ -141,7 +145,11 @@ async function runTests() { let i = 0; let total = vendorTotal + tests.length + 2; - const results = []; + + const okResults = []; + const flakyResults = []; + const failedResults = []; + const maxAttempts = 1 + (parseInt(options["retries"]) || 0); /** * @param {string} title @@ -149,43 +157,79 @@ async function runTests() { * @returns {Promise} */ const runTest = async (title, fn) => { - const label = `${getAnsi("gray")}[${++i}/${total}]${getAnsi("reset")} ${title}`; - const result = await startGroup(label, fn); - results.push(result); + const index = ++i; - if (isBuildkite) { - const { ok, error, stdoutPreview } = result; - if (title.startsWith("vendor")) { - const markdown = formatTestToMarkdown({ ...result, testPath: title }); - if (markdown) { - reportAnnotationToBuildKite({ label: title, content: markdown, style: "warning", priority: 5 }); - } - } else { - const markdown = formatTestToMarkdown(result); - if (markdown) { - reportAnnotationToBuildKite({ label: title, content: markdown, style: "error" }); - } + let result, failure, flaky; + for (let attempt = 1; attempt <= maxAttempts; attempt++) { + if (attempt > 1) { + await new Promise(resolve => setTimeout(resolve, 5000 + Math.random() * 10_000)); } - if (!ok) { - const label = `${getAnsi("red")}[${i}/${total}] ${title} - ${error}${getAnsi("reset")}`; - startGroup(label, () => { - process.stderr.write(stdoutPreview); - }); + result = await startGroup( + attempt === 1 + ? `${getAnsi("gray")}[${index}/${total}]${getAnsi("reset")} ${title}` + : `${getAnsi("gray")}[${index}/${total}]${getAnsi("reset")} ${title} ${getAnsi("gray")}[attempt #${attempt}]${getAnsi("reset")}`, + fn, + ); + + const { ok, stdoutPreview, error } = result; + if (ok) { + if (failure) { + flakyResults.push(failure); + } else { + okResults.push(result); + } + break; + } + + const color = attempt >= maxAttempts ? "red" : "yellow"; + const label = `${getAnsi(color)}[${index}/${total}] ${title} - ${error}${getAnsi("reset")}`; + startGroup(label, () => { + process.stderr.write(stdoutPreview); + }); + + failure ||= result; + flaky ||= true; + + if (attempt >= maxAttempts) { + flaky = false; + failedResults.push(failure); + } + } + + if (!failure) { + return result; + } + + if (isBuildkite) { + // Group flaky tests together, regardless of the title + const context = flaky ? "flaky" : title; + const style = flaky || title.startsWith("vendor") ? "warning" : "error"; + + if (title.startsWith("vendor")) { + const content = formatTestToMarkdown({ ...failure, testPath: title }); + if (content) { + reportAnnotationToBuildKite({ context, label: title, content, style }); + } + } else { + const content = formatTestToMarkdown(failure); + if (content) { + reportAnnotationToBuildKite({ context, label: title, content, style }); + } } } if (isGithubAction) { const summaryPath = process.env["GITHUB_STEP_SUMMARY"]; if (summaryPath) { - const longMarkdown = formatTestToMarkdown(result); + const longMarkdown = formatTestToMarkdown(failure); appendFileSync(summaryPath, longMarkdown); } - const shortMarkdown = formatTestToMarkdown(result, true); + const shortMarkdown = formatTestToMarkdown(failure, true); appendFileSync("comment.md", shortMarkdown); } - if (options["bail"] && !result.ok) { + if (options["bail"]) { process.exit(getExitCode("fail")); } @@ -199,7 +243,7 @@ async function runTests() { } } - if (results.every(({ ok }) => ok)) { + if (!failedResults.length) { for (const testPath of tests) { const title = relative(cwd, join(testsPath, testPath)).replace(/\\/g, "/"); if (title.startsWith("test/js/node/test/parallel/")) { @@ -270,21 +314,37 @@ async function runTests() { } } - const failedTests = results.filter(({ ok }) => !ok); if (isGithubAction) { - reportOutputToGitHubAction("failing_tests_count", failedTests.length); - const markdown = formatTestToMarkdown(failedTests); + reportOutputToGitHubAction("failing_tests_count", failedResults.length); + const markdown = formatTestToMarkdown(failedResults); reportOutputToGitHubAction("failing_tests", markdown); } - if (!isCI) { - !isQuiet && console.log("-------"); - !isQuiet && console.log("passing", results.length - failedTests.length, "/", results.length); - for (const { testPath } of failedTests) { - !isQuiet && console.log("-", testPath); + if (!isCI && !isQuiet) { + console.table({ + "Total Tests": okResults.length + failedResults.length + flakyResults.length, + "Passed Tests": okResults.length, + "Failing Tests": failedResults.length, + "Flaky Tests": flakyResults.length, + }); + + if (failedResults.length) { + console.log(`${getAnsi("red")}Failing Tests:${getAnsi("reset")}`); + for (const { testPath } of failedResults) { + console.log(`${getAnsi("red")}- ${testPath}${getAnsi("reset")}`); + } + } + + if (flakyResults.length) { + console.log(`${getAnsi("yellow")}Flaky Tests:${getAnsi("reset")}`); + for (const { testPath } of flakyResults) { + console.log(`${getAnsi("yellow")}- ${testPath}${getAnsi("reset")}`); + } } } - return results; + + // Exclude flaky tests from the final results + return [...okResults, ...failedResults]; } /** @@ -1293,6 +1353,7 @@ function listArtifactsFromBuildKite(glob, step) { /** * @typedef {object} BuildkiteAnnotation + * @property {string} [context] * @property {string} label * @property {string} content * @property {"error" | "warning" | "info"} [style] @@ -1303,10 +1364,10 @@ function listArtifactsFromBuildKite(glob, step) { /** * @param {BuildkiteAnnotation} annotation */ -function reportAnnotationToBuildKite({ label, content, style = "error", priority = 3, attempt = 0 }) { +function reportAnnotationToBuildKite({ context, label, content, style = "error", priority = 3, attempt = 0 }) { const { error, status, signal, stderr } = spawnSync( "buildkite-agent", - ["annotate", "--append", "--style", `${style}`, "--context", `${label}`, "--priority", `${priority}`], + ["annotate", "--append", "--style", `${style}`, "--context", `${context || label}`, "--priority", `${priority}`], { input: content, stdio: ["pipe", "ignore", "pipe"], diff --git a/test/bundler/bundler_edgecase.test.ts b/test/bundler/bundler_edgecase.test.ts index ae9725fad4..a3bf53f778 100644 --- a/test/bundler/bundler_edgecase.test.ts +++ b/test/bundler/bundler_edgecase.test.ts @@ -1336,7 +1336,7 @@ describe("bundler", () => { target: "bun", run: true, todo: isBroken && isWindows, - debugTimeoutScale: 5, + timeoutScale: 5, }); itBundled("edgecase/PackageExternalDoNotBundleNodeModules", { files: { diff --git a/test/bundler/bundler_plugin.test.ts b/test/bundler/bundler_plugin.test.ts index bd264f17dc..f168f9b3c3 100644 --- a/test/bundler/bundler_plugin.test.ts +++ b/test/bundler/bundler_plugin.test.ts @@ -689,7 +689,7 @@ describe("bundler", () => { expect(resolveCount).toBe(5050); expect(loadCount).toBe(101); }, - debugTimeoutScale: 3, + timeoutScale: 3, }; }); // itBundled("plugin/ManyPlugins", ({ root }) => { @@ -832,4 +832,3 @@ describe("bundler", () => { }; }); }); - diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index e9cba3ca5f..555e2a9e88 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -6,7 +6,7 @@ import { callerSourceOrigin } from "bun:jsc"; import type { Matchers } from "bun:test"; import * as esbuild from "esbuild"; import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "fs"; -import { bunEnv, bunExe, isDebug } from "harness"; +import { bunEnv, bunExe, isCI, isDebug } from "harness"; import { tmpdir } from "os"; import path from "path"; import { SourceMapConsumer } from "source-map"; @@ -278,8 +278,6 @@ export interface BundlerTestInput { /** Multiplier for test timeout */ timeoutScale?: number; - /** Multiplier for test timeout when using bun-debug. Debug builds already have a higher timeout. */ - debugTimeoutScale?: number; /* determines whether or not anything should be passed to outfile, outdir, etc. */ generateOutput?: boolean; @@ -1663,8 +1661,7 @@ export function itBundled( id, () => expectBundled(id, opts as any), // sourcemap code is slow - (opts.snapshotSourceMap ? (isDebug ? Infinity : 30_000) : isDebug ? 15_000 : 5_000) * - ((isDebug ? opts.debugTimeoutScale : opts.timeoutScale) ?? 1), + isCI ? undefined : isDebug ? Infinity : (opts.snapshotSourceMap ? 30_000 : 5_000) * (opts.timeoutScale ?? 1), ); } return ref; @@ -1676,8 +1673,7 @@ itBundled.only = (id: string, opts: BundlerTestInput) => { id, () => expectBundled(id, opts as any), // sourcemap code is slow - (opts.snapshotSourceMap ? (isDebug ? Infinity : 30_000) : isDebug ? 15_000 : 5_000) * - ((isDebug ? opts.debugTimeoutScale : opts.timeoutScale) ?? 1), + isCI ? undefined : isDebug ? Infinity : (opts.snapshotSourceMap ? 30_000 : 5_000) * (opts.timeoutScale ?? 1), ); }; diff --git a/test/cli/run/require-cache.test.ts b/test/cli/run/require-cache.test.ts index dc45bd828a..a950c27a5a 100644 --- a/test/cli/run/require-cache.test.ts +++ b/test/cli/run/require-cache.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { bunEnv, bunExe, isWindows, tempDirWithFiles } from "harness"; +import { bunEnv, bunExe, isBroken, isIntelMacOS, isWindows, tempDirWithFiles } from "harness"; import { join } from "path"; test("require.cache is not an empty object literal when inspected", () => { @@ -32,7 +32,7 @@ test("require.cache does not include unevaluated modules", () => { expect(exitCode).toBe(0); }); -describe("files transpiled and loaded don't leak the output source code", () => { +describe.skipIf(isBroken && isIntelMacOS)("files transpiled and loaded don't leak the output source code", () => { test("via require() with a lot of long export names", () => { let text = ""; for (let i = 0; i < 10000; i++) { diff --git a/test/harness.ts b/test/harness.ts index dd70b7bbed..a6e1950025 100644 --- a/test/harness.ts +++ b/test/harness.ts @@ -18,8 +18,10 @@ export const isWindows = process.platform === "win32"; export const isIntelMacOS = isMacOS && process.arch === "x64"; export const isDebug = Bun.version.includes("debug"); export const isCI = process.env.CI !== undefined; -export const isBuildKite = process.env.BUILDKITE === "true"; export const libcFamily = detectLibc.familySync() as "glibc" | "musl"; +export const isMusl = isLinux && libcFamily === "musl"; +export const isGlibc = isLinux && libcFamily === "glibc"; +export const isBuildKite = process.env.BUILDKITE === "true"; export const isVerbose = process.env.DEBUG === "1"; // Use these to mark a test as flaky or broken. diff --git a/test/js/bun/http/serve.test.ts b/test/js/bun/http/serve.test.ts index daadea5474..7b83ca75ff 100644 --- a/test/js/bun/http/serve.test.ts +++ b/test/js/bun/http/serve.test.ts @@ -1,7 +1,7 @@ import { file, gc, Serve, serve, Server } from "bun"; import { afterAll, afterEach, describe, expect, it, mock } from "bun:test"; import { readFileSync, writeFileSync } from "fs"; -import { bunEnv, bunExe, dumpStats, isIPv4, isIPv6, isPosix, tls, tmpdirSync } from "harness"; +import { bunEnv, bunExe, dumpStats, isBroken, isIntelMacOS, isIPv4, isIPv6, isPosix, tls, tmpdirSync } from "harness"; import { join, resolve } from "path"; // import { renderToReadableStream } from "react-dom/server"; // import app_jsx from "./app.jsx"; @@ -213,92 +213,95 @@ for (let withDelay of [true, false]) { }); } } -describe("1000 uploads & downloads in batches of 64 do not leak ReadableStream", () => { - for (let isDirect of [true, false] as const) { - it( - isDirect ? "direct" : "default", - async () => { - const blob = new Blob([new Uint8Array(1024 * 768).fill(123)]); - Bun.gc(true); +describe.todoIf(isBroken && isIntelMacOS)( + "1000 uploads & downloads in batches of 64 do not leak ReadableStream", + () => { + for (let isDirect of [true, false] as const) { + it( + isDirect ? "direct" : "default", + async () => { + const blob = new Blob([new Uint8Array(1024 * 768).fill(123)]); + Bun.gc(true); - const expected = Bun.CryptoHasher.hash("sha256", blob, "base64"); - const initialCount = heapStats().objectTypeCounts.ReadableStream || 0; + const expected = Bun.CryptoHasher.hash("sha256", blob, "base64"); + const initialCount = heapStats().objectTypeCounts.ReadableStream || 0; - await runTest( - { - async fetch(req) { - var hasher = new Bun.SHA256(); - for await (const chunk of req.body) { - await Bun.sleep(0); - hasher.update(chunk); + await runTest( + { + async fetch(req) { + var hasher = new Bun.SHA256(); + for await (const chunk of req.body) { + await Bun.sleep(0); + hasher.update(chunk); + } + return new Response( + isDirect + ? new ReadableStream({ + type: "direct", + async pull(controller) { + await Bun.sleep(0); + controller.write(Buffer.from(hasher.digest("base64"))); + await controller.flush(); + controller.close(); + }, + }) + : new ReadableStream({ + async pull(controller) { + await Bun.sleep(0); + controller.enqueue(Buffer.from(hasher.digest("base64"))); + controller.close(); + }, + }), + ); + }, + }, + async server => { + const count = 1000; + async function callback() { + const response = await fetch(server.url, { + body: blob, + method: "POST", + }); + + // We are testing for ReadableStream leaks, so we use the ReadableStream here. + const chunks = []; + for await (const chunk of response.body) { + chunks.push(chunk); + } + + const digest = Buffer.from(Bun.concatArrayBuffers(chunks)).toString(); + + expect(digest).toBe(expected); + Bun.gc(false); } - return new Response( - isDirect - ? new ReadableStream({ - type: "direct", - async pull(controller) { - await Bun.sleep(0); - controller.write(Buffer.from(hasher.digest("base64"))); - await controller.flush(); - controller.close(); - }, - }) - : new ReadableStream({ - async pull(controller) { - await Bun.sleep(0); - controller.enqueue(Buffer.from(hasher.digest("base64"))); - controller.close(); - }, - }), + { + let remaining = count; + + const batchSize = 64; + while (remaining > 0) { + const promises = new Array(count); + for (let i = 0; i < batchSize && remaining > 0; i++) { + promises[i] = callback(); + } + await Promise.all(promises); + remaining -= batchSize; + } + } + + Bun.gc(true); + dumpStats(); + expect(heapStats().objectTypeCounts.ReadableStream).toBeWithin( + Math.max(initialCount - count / 2, 0), + initialCount + count / 2, ); }, - }, - async server => { - const count = 1000; - async function callback() { - const response = await fetch(server.url, { - body: blob, - method: "POST", - }); - - // We are testing for ReadableStream leaks, so we use the ReadableStream here. - const chunks = []; - for await (const chunk of response.body) { - chunks.push(chunk); - } - - const digest = Buffer.from(Bun.concatArrayBuffers(chunks)).toString(); - - expect(digest).toBe(expected); - Bun.gc(false); - } - { - let remaining = count; - - const batchSize = 64; - while (remaining > 0) { - const promises = new Array(count); - for (let i = 0; i < batchSize && remaining > 0; i++) { - promises[i] = callback(); - } - await Promise.all(promises); - remaining -= batchSize; - } - } - - Bun.gc(true); - dumpStats(); - expect(heapStats().objectTypeCounts.ReadableStream).toBeWithin( - Math.max(initialCount - count / 2, 0), - initialCount + count / 2, - ); - }, - ); - }, - 100000, - ); - } -}); + ); + }, + 100000, + ); + } + }, +); [200, 200n, 303, 418, 599, 599n].forEach(statusCode => { it(`should response with HTTP status code (${statusCode})`, async () => { diff --git a/test/js/node/fs/fs.test.ts b/test/js/node/fs/fs.test.ts index 3307edae09..d4f52071e5 100644 --- a/test/js/node/fs/fs.test.ts +++ b/test/js/node/fs/fs.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, spyOn } from "bun:test"; -import { bunEnv, bunExe, gc, getMaxFD, isIntelMacOS, isWindows, tempDirWithFiles, tmpdirSync } from "harness"; +import { bunEnv, bunExe, gc, getMaxFD, isBroken, isIntelMacOS, isWindows, tempDirWithFiles, tmpdirSync } from "harness"; import { isAscii } from "node:buffer"; import fs, { closeSync, @@ -2225,110 +2225,73 @@ describe("fs.ReadStream", () => { }); describe("createWriteStream", () => { - it("simple write stream finishes", async () => { - const path = `${tmpdir()}/fs.test.ts/${Date.now()}.createWriteStream.txt`; - const stream = createWriteStream(path); + it.todoIf(isBroken && isWindows)("simple write stream finishes", async () => { + const streamPath = join(tmpdirSync(), "create-write-stream.txt"); + const { promise: done, resolve, reject } = Promise.withResolvers(); + + const stream = createWriteStream(streamPath); + stream.on("error", reject); + stream.on("finish", resolve); stream.write("Test file written successfully"); stream.end(); - return await new Promise((resolve, reject) => { - stream.on("error", e => { - reject(e); - }); - - stream.on("finish", () => { - expect(readFileSync(path, "utf8")).toBe("Test file written successfully"); - resolve(true); - }); - }); + await done; + expect(readFileSync(streamPath, "utf8")).toBe("Test file written successfully"); }); it("writing null throws ERR_STREAM_NULL_VALUES", async () => { - const path = `${tmpdir()}/fs.test.ts/${Date.now()}.createWriteStreamNulls.txt`; - const stream = createWriteStream(path); - try { - stream.write(null); - expect(() => {}).toThrow(Error); - } catch (exception: any) { - expect(exception.code).toBe("ERR_STREAM_NULL_VALUES"); - } + const streamPath = join(tmpdirSync(), "create-write-stream-nulls.txt"); + const stream = createWriteStream(streamPath); + expect.toThrowWithCode(() => stream.write(null), "ERR_STREAM_NULL_VALUES"); }); it("writing null throws ERR_STREAM_NULL_VALUES (objectMode: true)", async () => { - const path = `${tmpdir()}/fs.test.ts/${Date.now()}.createWriteStreamNulls.txt`; - const stream = createWriteStream(path, { + const streamPath = join(tmpdirSync(), "create-write-stream-nulls-object-mode.txt"); + const stream = createWriteStream(streamPath, { // @ts-ignore-next-line objectMode: true, }); - try { - stream.write(null); - expect(() => {}).toThrow(Error); - } catch (exception: any) { - expect(exception.code).toBe("ERR_STREAM_NULL_VALUES"); - } + expect.toThrowWithCode(() => stream.write(null), "ERR_STREAM_NULL_VALUES"); }); it("writing false throws ERR_INVALID_ARG_TYPE", async () => { - const path = `${tmpdir()}/fs.test.ts/${Date.now()}.createWriteStreamFalse.txt`; - const stream = createWriteStream(path); - try { - stream.write(false); - expect(() => {}).toThrow(Error); - } catch (exception: any) { - expect(exception.code).toBe("ERR_INVALID_ARG_TYPE"); - } + const streamPath = join(tmpdirSync(), "create-write-stream-false.txt"); + const stream = createWriteStream(streamPath); + expect.toThrowWithCode(() => stream.write(false), "ERR_INVALID_ARG_TYPE"); }); it("writing false throws ERR_INVALID_ARG_TYPE (objectMode: true)", async () => { - const path = `${tmpdir()}/fs.test.ts/${Date.now()}.createWriteStreamFalse.txt`; - const stream = createWriteStream(path, { + const streamPath = join(tmpdirSync(), "create-write-stream-false-object-mode.txt"); + const stream = createWriteStream(streamPath, { // @ts-ignore-next-line objectMode: true, }); - try { - stream.write(false); - expect(() => {}).toThrow(Error); - } catch (exception: any) { - expect(exception.code).toBe("ERR_INVALID_ARG_TYPE"); - } + expect.toThrowWithCode(() => stream.write(false), "ERR_INVALID_ARG_TYPE"); }); it("writing in append mode should not truncate the file", async () => { - const path = `${tmpdir()}/fs.test.ts/${Date.now()}.createWriteStreamAppend.txt`; - const stream = createWriteStream(path, { + const streamPath = join(tmpdirSync(), "create-write-stream-append.txt"); + const stream = createWriteStream(streamPath, { // @ts-ignore-next-line flags: "a", }); + + const { promise: done1, resolve: resolve1, reject: reject1 } = Promise.withResolvers(); + stream.on("error", reject1); + stream.on("finish", resolve1); stream.write("first line\n"); stream.end(); + await done1; - await new Promise((resolve, reject) => { - stream.on("error", e => { - reject(e); - }); - - stream.on("finish", () => { - resolve(true); - }); - }); - - const stream2 = createWriteStream(path, { - // @ts-ignore-next-line - flags: "a", - }); + const { promise: done2, resolve: resolve2, reject: reject2 } = Promise.withResolvers(); + const stream2 = createWriteStream(streamPath, { flags: "a" }); + stream2.on("error", reject2); + stream2.on("finish", resolve2); stream2.write("second line\n"); stream2.end(); + await done2; - return await new Promise((resolve, reject) => { - stream2.on("error", e => { - reject(e); - }); - - stream2.on("finish", () => { - expect(readFileSync(path, "utf8")).toBe("first line\nsecond line\n"); - resolve(true); - }); - }); + expect(readFileSync(streamPath, "utf8")).toBe("first line\nsecond line\n"); }); it("should emit open and call close callback", done => { diff --git a/test/v8/v8.test.ts b/test/v8/v8.test.ts index ad7b2b1a3d..1f4ff131ea 100644 --- a/test/v8/v8.test.ts +++ b/test/v8/v8.test.ts @@ -1,6 +1,6 @@ import { spawn, spawnSync } from "bun"; import { beforeAll, describe, expect, it } from "bun:test"; -import { bunEnv, bunExe, tmpdirSync, isWindows } from "harness"; +import { bunEnv, bunExe, tmpdirSync, isWindows, isMusl, isBroken } from "harness"; import assert from "node:assert"; import fs from "node:fs/promises"; import { join, basename } from "path"; @@ -84,163 +84,165 @@ async function build( }; } -beforeAll(async () => { - // set up clean directories for our 4 builds - directories.bunRelease = tmpdirSync(); - directories.bunDebug = tmpdirSync(); - directories.node = tmpdirSync(); - directories.badModules = tmpdirSync(); +describe.todoIf(isBroken && isMusl)("node:v8", () => { + beforeAll(async () => { + // set up clean directories for our 4 builds + directories.bunRelease = tmpdirSync(); + directories.bunDebug = tmpdirSync(); + directories.node = tmpdirSync(); + directories.badModules = tmpdirSync(); - await install(srcDir, directories.bunRelease, Runtime.bun); - await install(srcDir, directories.bunDebug, Runtime.bun); - await install(srcDir, directories.node, Runtime.node); - await install(join(__dirname, "bad-modules"), directories.badModules, Runtime.node); + await install(srcDir, directories.bunRelease, Runtime.bun); + await install(srcDir, directories.bunDebug, Runtime.bun); + await install(srcDir, directories.node, Runtime.node); + await install(join(__dirname, "bad-modules"), directories.badModules, Runtime.node); - const results = await Promise.all([ - build(srcDir, directories.bunRelease, Runtime.bun, BuildMode.release), - build(srcDir, directories.bunDebug, Runtime.bun, BuildMode.debug), - build(srcDir, directories.node, Runtime.node, BuildMode.release), - build(join(__dirname, "bad-modules"), directories.badModules, Runtime.node, BuildMode.release), - ]); - for (const r of results) { - console.log(r.description, "stdout:"); - console.log(r.out); - console.log(r.description, "stderr:"); - console.log(r.err); - } -}); + const results = await Promise.all([ + build(srcDir, directories.bunRelease, Runtime.bun, BuildMode.release), + build(srcDir, directories.bunDebug, Runtime.bun, BuildMode.debug), + build(srcDir, directories.node, Runtime.node, BuildMode.release), + build(join(__dirname, "bad-modules"), directories.badModules, Runtime.node, BuildMode.release), + ]); + for (const r of results) { + console.log(r.description, "stdout:"); + console.log(r.out); + console.log(r.description, "stderr:"); + console.log(r.err); + } + }); -describe("module lifecycle", () => { - it("can call a basic native function", () => { - checkSameOutput("test_v8_native_call", []); - }); -}); - -describe("primitives", () => { - it("can create and distinguish between null, undefined, true, and false", () => { - checkSameOutput("test_v8_primitives", []); - }); -}); - -describe("Number", () => { - it("can create small integer", () => { - checkSameOutput("test_v8_number_int", []); - }); - // non-i32 v8::Number is not implemented yet - it("can create large integer", () => { - checkSameOutput("test_v8_number_large_int", []); - }); - it("can create fraction", () => { - checkSameOutput("test_v8_number_fraction", []); - }); -}); - -describe("String", () => { - it("can create and read back strings with only ASCII characters", () => { - checkSameOutput("test_v8_string_ascii", []); - }); - // non-ASCII strings are not implemented yet - it("can create and read back strings with UTF-8 characters", () => { - checkSameOutput("test_v8_string_utf8", []); - }); - it("handles replacement correctly in strings with invalid UTF-8 sequences", () => { - checkSameOutput("test_v8_string_invalid_utf8", []); - }); - it("can create strings from null-terminated Latin-1 data", () => { - checkSameOutput("test_v8_string_latin1", []); - }); - describe("WriteUtf8", () => { - it("truncates the string correctly", () => { - checkSameOutput("test_v8_string_write_utf8", []); + describe("module lifecycle", () => { + it("can call a basic native function", () => { + checkSameOutput("test_v8_native_call", []); }); }); -}); -describe("External", () => { - it("can create an external and read back the correct value", () => { - checkSameOutput("test_v8_external", []); - }); -}); - -describe("Object", () => { - it("can create an object and set properties", () => { - checkSameOutput("test_v8_object", []); - }); -}); -describe("Array", () => { - // v8::Array::New is broken as it still tries to reinterpret locals as JSValues - it.skip("can create an array from a C array of Locals", () => { - checkSameOutput("test_v8_array_new", []); - }); -}); - -describe("ObjectTemplate", () => { - it("creates objects with internal fields", () => { - checkSameOutput("test_v8_object_template", []); - }); -}); - -describe("FunctionTemplate", () => { - it("keeps the data parameter alive", () => { - checkSameOutput("test_v8_function_template", []); - }); -}); - -describe("Function", () => { - it("correctly receives all its arguments from JS", () => { - checkSameOutput("print_values_from_js", [5.0, true, null, false, "meow", {}]); - checkSameOutput("print_native_function", []); + describe("primitives", () => { + it("can create and distinguish between null, undefined, true, and false", () => { + checkSameOutput("test_v8_primitives", []); + }); }); - it("correctly receives the this value from JS", () => { - checkSameOutput("call_function_with_weird_this_values", []); - }); -}); - -describe("error handling", () => { - it("throws an error for modules built using the wrong ABI version", () => { - expect(() => require(join(directories.badModules, "build/Release/mismatched_abi_version.node"))).toThrow( - "The module 'mismatched_abi_version' was compiled against a different Node.js ABI version using NODE_MODULE_VERSION 42.", - ); + describe("Number", () => { + it("can create small integer", () => { + checkSameOutput("test_v8_number_int", []); + }); + // non-i32 v8::Number is not implemented yet + it("can create large integer", () => { + checkSameOutput("test_v8_number_large_int", []); + }); + it("can create fraction", () => { + checkSameOutput("test_v8_number_fraction", []); + }); }); - it("throws an error for modules with no entrypoint", () => { - expect(() => require(join(directories.badModules, "build/Release/no_entrypoint.node"))).toThrow( - "The module 'no_entrypoint' has no declared entry point.", - ); + describe("String", () => { + it("can create and read back strings with only ASCII characters", () => { + checkSameOutput("test_v8_string_ascii", []); + }); + // non-ASCII strings are not implemented yet + it("can create and read back strings with UTF-8 characters", () => { + checkSameOutput("test_v8_string_utf8", []); + }); + it("handles replacement correctly in strings with invalid UTF-8 sequences", () => { + checkSameOutput("test_v8_string_invalid_utf8", []); + }); + it("can create strings from null-terminated Latin-1 data", () => { + checkSameOutput("test_v8_string_latin1", []); + }); + describe("WriteUtf8", () => { + it("truncates the string correctly", () => { + checkSameOutput("test_v8_string_write_utf8", []); + }); + }); }); -}); -describe("Global", () => { - it("can create, modify, and read the value from global handles", () => { - checkSameOutput("test_v8_global", []); + describe("External", () => { + it("can create an external and read back the correct value", () => { + checkSameOutput("test_v8_external", []); + }); }); -}); -describe("HandleScope", () => { - it("can hold a lot of locals", () => { - checkSameOutput("test_many_v8_locals", []); + describe("Object", () => { + it("can create an object and set properties", () => { + checkSameOutput("test_v8_object", []); + }); }); - it("keeps GC objects alive", () => { - checkSameOutput("test_handle_scope_gc", []); - }, 10000); -}); - -describe("EscapableHandleScope", () => { - it("keeps handles alive in the outer scope", () => { - checkSameOutput("test_v8_escapable_handle_scope", []); + describe("Array", () => { + // v8::Array::New is broken as it still tries to reinterpret locals as JSValues + it.skip("can create an array from a C array of Locals", () => { + checkSameOutput("test_v8_array_new", []); + }); }); -}); -describe("uv_os_getpid", () => { - it.skipIf(isWindows)("returns the same result as getpid on POSIX", () => { - checkSameOutput("test_uv_os_getpid", []); + describe("ObjectTemplate", () => { + it("creates objects with internal fields", () => { + checkSameOutput("test_v8_object_template", []); + }); }); -}); -describe("uv_os_getppid", () => { - it.skipIf(isWindows)("returns the same result as getppid on POSIX", () => { - checkSameOutput("test_uv_os_getppid", []); + describe("FunctionTemplate", () => { + it("keeps the data parameter alive", () => { + checkSameOutput("test_v8_function_template", []); + }); + }); + + describe("Function", () => { + it("correctly receives all its arguments from JS", () => { + checkSameOutput("print_values_from_js", [5.0, true, null, false, "meow", {}]); + checkSameOutput("print_native_function", []); + }); + + it("correctly receives the this value from JS", () => { + checkSameOutput("call_function_with_weird_this_values", []); + }); + }); + + describe("error handling", () => { + it("throws an error for modules built using the wrong ABI version", () => { + expect(() => require(join(directories.badModules, "build/Release/mismatched_abi_version.node"))).toThrow( + "The module 'mismatched_abi_version' was compiled against a different Node.js ABI version using NODE_MODULE_VERSION 42.", + ); + }); + + it("throws an error for modules with no entrypoint", () => { + expect(() => require(join(directories.badModules, "build/Release/no_entrypoint.node"))).toThrow( + "The module 'no_entrypoint' has no declared entry point.", + ); + }); + }); + + describe("Global", () => { + it("can create, modify, and read the value from global handles", () => { + checkSameOutput("test_v8_global", []); + }); + }); + + describe("HandleScope", () => { + it("can hold a lot of locals", () => { + checkSameOutput("test_many_v8_locals", []); + }); + it("keeps GC objects alive", () => { + checkSameOutput("test_handle_scope_gc", []); + }, 10000); + }); + + describe("EscapableHandleScope", () => { + it("keeps handles alive in the outer scope", () => { + checkSameOutput("test_v8_escapable_handle_scope", []); + }); + }); + + describe("uv_os_getpid", () => { + it.skipIf(isWindows)("returns the same result as getpid on POSIX", () => { + checkSameOutput("test_uv_os_getpid", []); + }); + }); + + describe("uv_os_getppid", () => { + it.skipIf(isWindows)("returns the same result as getppid on POSIX", () => { + checkSameOutput("test_uv_os_getppid", []); + }); }); }); From f2d955f686b7576993d58b1f5290f0b45354f5fe Mon Sep 17 00:00:00 2001 From: Michael H Date: Tue, 17 Dec 2024 12:29:12 +1100 Subject: [PATCH 024/125] vscode extension: use new debug terminal provider (#15801) Co-authored-by: Jarred Sumner --- packages/bun-vscode/src/features/debug.ts | 44 ++++++++++++++++++-- packages/bun-vscode/src/vscode-js-debug.d.ts | 39 +++++++++++++++++ 2 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 packages/bun-vscode/src/vscode-js-debug.d.ts diff --git a/packages/bun-vscode/src/features/debug.ts b/packages/bun-vscode/src/features/debug.ts index a48284dea3..242aed26e1 100644 --- a/packages/bun-vscode/src/features/debug.ts +++ b/packages/bun-vscode/src/features/debug.ts @@ -64,8 +64,11 @@ export function registerDebugger(context: vscode.ExtensionContext, factory?: vsc vscode.DebugConfigurationProviderTriggerKind.Dynamic, ), vscode.debug.registerDebugAdapterDescriptorFactory("bun", factory ?? new InlineDebugAdapterFactory()), - vscode.window.onDidOpenTerminal(injectDebugTerminal), ); + + if (getConfig("debugTerminal.enabled")) { + injectDebugTerminal2().then(context.subscriptions.push) + } } function runFileCommand(resource?: vscode.Uri): void { @@ -94,8 +97,6 @@ function debugFileCommand(resource?: vscode.Uri) { } async function injectDebugTerminal(terminal: vscode.Terminal): Promise { - if (!getConfig("debugTerminal.enabled")) return; - const { name, creationOptions } = terminal; if (name !== "JavaScript Debug Terminal") { return; @@ -134,6 +135,41 @@ async function injectDebugTerminal(terminal: vscode.Terminal): Promise { setTimeout(() => terminal.dispose(), 100); } +async function injectDebugTerminal2() { + const jsDebugExt = vscode.extensions.getExtension('ms-vscode.js-debug-nightly') || vscode.extensions.getExtension('ms-vscode.js-debug'); + if (!jsDebugExt) { + return vscode.window.onDidOpenTerminal(injectDebugTerminal) + } + + await jsDebugExt.activate() + const jsDebug: import('@vscode/js-debug').IExports = jsDebugExt.exports; + if (!jsDebug) { + return vscode.window.onDidOpenTerminal(injectDebugTerminal) + } + + return jsDebug.registerDebugTerminalOptionsProvider({ + async provideTerminalOptions(options) { + const session = new TerminalDebugSession(); + await session.initialize(); + + const { adapter, signal } = session; + + const stopOnEntry = getConfig("debugTerminal.stopOnEntry") === true; + const query = stopOnEntry ? "break=1" : "wait=1"; + + return { + ...options, + env: { + ...options.env, + "BUN_INSPECT": `${adapter.url}?${query}`, + "BUN_INSPECT_NOTIFY": signal.url, + BUN_INSPECT_CONNECT_TO: " ", + }, + }; + }, + }); +} + class DebugConfigurationProvider implements vscode.DebugConfigurationProvider { provideDebugConfigurations(folder?: vscode.WorkspaceFolder): vscode.ProviderResult { return [DEBUG_CONFIGURATION, RUN_CONFIGURATION, ATTACH_CONFIGURATION]; @@ -295,7 +331,7 @@ class FileDebugSession extends DebugSession { } this.adapter.on("Adapter.reverseRequest", ({ command, arguments: args }) => - this.sendRequest(command, args, 5000, () => {}), + this.sendRequest(command, args, 5000, () => { }), ); adapters.set(url, this); diff --git a/packages/bun-vscode/src/vscode-js-debug.d.ts b/packages/bun-vscode/src/vscode-js-debug.d.ts new file mode 100644 index 0000000000..475a60f8f7 --- /dev/null +++ b/packages/bun-vscode/src/vscode-js-debug.d.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + +declare module '@vscode/js-debug' { + import type * as vscode from 'vscode'; + + /** @see {IExports.registerDebugTerminalOptionsProvider} */ + export interface IDebugTerminalOptionsProvider { + /** + * Called when the user creates a JavaScript Debug Terminal. It's called + * with the options js-debug wants to use to create the terminal. It should + * modify and return the options to use in the terminal. + * + * In order to avoid conflicting with existing logic, participants should + * try to modify options in a additive way. For example prefer appending + * to rather than reading and overwriting `options.env.PATH`. + */ + provideTerminalOptions(options: vscode.TerminalOptions): vscode.ProviderResult; + } + + /** + * Defines the exports of the `js-debug` extension. Once you have this typings + * file, these can be acquired in your extension using the following code: + * + * ``` + * const jsDebugExt = vscode.extensions.getExtension('ms-vscode.js-debug-nightly') + * || vscode.extensions.getExtension('ms-vscode.js-debug'); + * await jsDebugExt.activate() + * const jsDebug: import('@vscode/js-debug').IExports = jsDebug.exports; + * ``` + */ + export interface IExports { + /** + * Registers a participant used when the user creates a JavaScript Debug Terminal. + */ + registerDebugTerminalOptionsProvider(provider: IDebugTerminalOptionsProvider): vscode.Disposable; + } +} \ No newline at end of file From 4bef96e8d1e7b6f7cdad39cd5de8afd3f1506064 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 16 Dec 2024 18:19:43 -0800 Subject: [PATCH 025/125] Prevent unnecessary postinstall script from causing bun install to hang in unreliable networks --- src/install/default-trusted-dependencies.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/install/default-trusted-dependencies.txt b/src/install/default-trusted-dependencies.txt index 270a9eccf5..85b0876636 100644 --- a/src/install/default-trusted-dependencies.txt +++ b/src/install/default-trusted-dependencies.txt @@ -91,7 +91,6 @@ @splunk/otel @strapi/strapi @sveltejs/kit -@swc/core @syncfusion/ej2-angular-base @taquito/taquito @temporalio/core-bridge From f276484f254dc070f74e184a39c644aefad7f1a5 Mon Sep 17 00:00:00 2001 From: pfg Date: Mon, 16 Dec 2024 18:31:41 -0800 Subject: [PATCH 026/125] Add lldb scripts for zig & jsc (#15807) --- .vscode/launch.json | 58 +- misctools/lldb/lldb_commands | 7 + misctools/lldb/lldb_pretty_printers.py | 733 +++++++++++++ misctools/lldb/lldb_webkit.py | 1303 ++++++++++++++++++++++++ 4 files changed, 2072 insertions(+), 29 deletions(-) create mode 100644 misctools/lldb/lldb_commands create mode 100644 misctools/lldb/lldb_pretty_printers.py create mode 100644 misctools/lldb/lldb_webkit.py diff --git a/.vscode/launch.json b/.vscode/launch.json index 02a747cde7..817b7533d3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -38,7 +38,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -60,7 +60,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -76,7 +76,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -92,7 +92,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -108,7 +108,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -125,7 +125,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -147,7 +147,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -169,7 +169,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -188,7 +188,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -203,7 +203,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -221,7 +221,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -236,7 +236,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -253,7 +253,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -275,7 +275,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -297,7 +297,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -313,7 +313,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -329,7 +329,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -345,7 +345,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -361,7 +361,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -378,7 +378,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -400,7 +400,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -421,7 +421,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, // bun test [*] { @@ -437,7 +437,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -452,7 +452,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -468,7 +468,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -488,7 +488,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, { "type": "lldb", @@ -503,7 +503,7 @@ }, "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, // Windows: bun test [file] { @@ -1125,7 +1125,7 @@ ], "console": "internalConsole", // Don't pause when the GC runs while the debugger is open. - "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], + "postRunCommands": ["command source '${workspaceFolder}/misctools/lldb/lldb_commands'"], }, ], "inputs": [ diff --git a/misctools/lldb/lldb_commands b/misctools/lldb/lldb_commands new file mode 100644 index 0000000000..d4ad6a560b --- /dev/null +++ b/misctools/lldb/lldb_commands @@ -0,0 +1,7 @@ +process handle -p true -s false -n false SIGUSR1 + +command script import misctools/lldb/lldb_pretty_printers.py +type category enable zig.lang +type category enable zig.std + +command script import misctools/lldb/lldb_webkit.py diff --git a/misctools/lldb/lldb_pretty_printers.py b/misctools/lldb/lldb_pretty_printers.py new file mode 100644 index 0000000000..0ed2e6667e --- /dev/null +++ b/misctools/lldb/lldb_pretty_printers.py @@ -0,0 +1,733 @@ +# https://github.com/ziglang/zig/blob/master/tools/lldb_pretty_printers.py + +# pretty printing for the zig language, zig standard library, and zig stage 2 compiler. +# put commands in ~/.lldbinit to run them automatically when starting lldb +# `command script import /path/to/zig/tools/lldb_pretty_printers.py` to import this file +# `type category enable zig.lang` to enable pretty printing for the zig language +# `type category enable zig.std` to enable pretty printing for the zig standard library +# `type category enable zig.stage2` to enable pretty printing for the zig stage 2 compiler +import lldb +import re + +page_size = 1 << 12 + +def log2_int(i): return i.bit_length() - 1 + +# Define Zig Language + +zig_keywords = { + 'addrspace', + 'align', + 'allowzero', + 'and', + 'anyframe', + 'anytype', + 'asm', + 'async', + 'await', + 'break', + 'callconv', + 'catch', + 'comptime', + 'const', + 'continue', + 'defer', + 'else', + 'enum', + 'errdefer', + 'error', + 'export', + 'extern', + 'fn', + 'for', + 'if', + 'inline', + 'noalias', + 'noinline', + 'nosuspend', + 'opaque', + 'or', + 'orelse', + 'packed', + 'pub', + 'resume', + 'return', + 'linksection', + 'struct', + 'suspend', + 'switch', + 'test', + 'threadlocal', + 'try', + 'union', + 'unreachable', + 'usingnamespace', + 'var', + 'volatile', + 'while', +} +zig_primitives = { + 'anyerror', + 'anyframe', + 'anyopaque', + 'bool', + 'c_int', + 'c_long', + 'c_longdouble', + 'c_longlong', + 'c_short', + 'c_uint', + 'c_ulong', + 'c_ulonglong', + 'c_ushort', + 'comptime_float', + 'comptime_int', + 'f128', + 'f16', + 'f32', + 'f64', + 'f80', + 'false', + 'isize', + 'noreturn', + 'null', + 'true', + 'type', + 'undefined', + 'usize', + 'void', +} +zig_integer_type = re.compile('[iu][1-9][0-9]+') +zig_identifier_regex = re.compile('[A-Z_a-z][0-9A-Z_a-z]*') +def zig_IsVariableName(string): return string != '_' and string not in zig_keywords and string not in zig_primitives and not zig_integer_type.fullmatch(string) and zig_identifier_regex.fullmatch(string) +def zig_IsFieldName(string): return string not in zig_keywords and zig_identifier_regex.fullmatch(string) + +class zig_Slice_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.ptr = self.value.GetChildMemberWithName('ptr') + self.len = self.value.GetChildMemberWithName('len').unsigned if self.ptr.unsigned > page_size else 0 + self.elem_type = self.ptr.type.GetPointeeType() + self.elem_size = self.elem_type.size + except: pass + def has_children(self): return True + def num_children(self): return self.len or 0 + def get_child_index(self, name): + try: return int(name.removeprefix('[').removesuffix(']')) + except: return -1 + def get_child_at_index(self, index): + if index not in range(self.len): return None + try: return self.ptr.CreateChildAtOffset('[%d]' % index, index * self.elem_size, self.elem_type) + except: return None + +def zig_String_decode(value, offset=0, length=None): + try: + value = value.GetNonSyntheticValue() + data = value.GetChildMemberWithName('ptr').GetPointeeData(offset, length if length is not None else value.GetChildMemberWithName('len').unsigned) + b = bytes(data.uint8) + b = b.replace(b'\\', b'\\\\') + b = b.replace(b'\n', b'\\n') + b = b.replace(b'\r', b'\\r') + b = b.replace(b'\t', b'\\t') + b = b.replace(b'"', b'\\"') + b = b.replace(b'\'', b'\\\'') + s = b.decode(encoding='ascii', errors='backslashreplace') + return s if s.isprintable() else ''.join((c if c.isprintable() else '\\x%02x' % ord(c) for c in s)) + except: return None +def zig_String_SummaryProvider(value, _=None): return '"%s"' % zig_String_decode(value) +def zig_String_AsIdentifier(value, pred): + string = zig_String_decode(value) + return string if pred(string) else '@"%s"' % string + +class zig_Optional_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.child = self.value.GetChildMemberWithName('some').unsigned == 1 and self.value.GetChildMemberWithName('data').Clone('child') + except: pass + def has_children(self): return bool(self.child) + def num_children(self): return int(self.child) + def get_child_index(self, name): return 0 if self.child and (name == 'child' or name == '?') else -1 + def get_child_at_index(self, index): return self.child if self.child and index == 0 else None +def zig_Optional_SummaryProvider(value, _=None): + child = value.GetChildMemberWithName('child') + return child or 'null' + +class zig_ErrorUnion_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.error_set = self.value.GetChildMemberWithName('tag').Clone('error_set') + self.payload = self.value.GetChildMemberWithName('value').Clone('payload') if self.error_set.unsigned == 0 else None + except: pass + def has_children(self): return True + def num_children(self): return 1 + def get_child_index(self, name): return 0 if name == ('payload' if self.payload else 'error_set') else -1 + def get_child_at_index(self, index): return self.payload or self.error_set if index == 0 else None + +class zig_TaggedUnion_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.tag = self.value.GetChildMemberWithName('tag') + self.payload = self.value.GetChildMemberWithName('payload').GetChildMemberWithName(self.tag.value) + except: pass + def has_children(self): return True + def num_children(self): return 1 + (self.payload is not None) + def get_child_index(self, name): + try: return ('tag', 'payload').index(name) + except: return -1 + def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None + +# Define Zig Standard Library + +class std_SegmentedList_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.prealloc_segment = self.value.GetChildMemberWithName('prealloc_segment') + self.dynamic_segments = zig_Slice_SynthProvider(self.value.GetChildMemberWithName('dynamic_segments')) + self.dynamic_segments.update() + self.len = self.value.GetChildMemberWithName('len').unsigned + except: pass + def has_children(self): return True + def num_children(self): return self.len + def get_child_index(self, name): + try: return int(name.removeprefix('[').removesuffix(']')) + except: return -1 + def get_child_at_index(self, index): + try: + if index not in range(self.len): return None + prealloc_item_count = len(self.prealloc_segment) + if index < prealloc_item_count: return self.prealloc_segment.child[index] + prealloc_exp = prealloc_item_count.bit_length() - 1 + shelf_index = log2_int(index + 1) if prealloc_item_count == 0 else log2_int(index + prealloc_item_count) - prealloc_exp - 1 + shelf = self.dynamic_segments.get_child_at_index(shelf_index) + box_index = (index + 1) - (1 << shelf_index) if prealloc_item_count == 0 else index + prealloc_item_count - (1 << ((prealloc_exp + 1) + shelf_index)) + elem_type = shelf.type.GetPointeeType() + return shelf.CreateChildAtOffset('[%d]' % index, box_index * elem_type.size, elem_type) + except: return None + +class std_MultiArrayList_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.len = 0 + + value_type = self.value.type + for helper in self.value.target.FindFunctions('%s.dbHelper' % value_type.name, lldb.eFunctionNameTypeFull): + ptr_self_type, ptr_child_type, ptr_field_type, ptr_entry_type = helper.function.type.GetFunctionArgumentTypes() + if ptr_self_type.GetPointeeType() == value_type: break + else: return + + self.entry_type = ptr_entry_type.GetPointeeType() + self.bytes = self.value.GetChildMemberWithName('bytes') + self.len = self.value.GetChildMemberWithName('len').unsigned + self.capacity = self.value.GetChildMemberWithName('capacity').unsigned + except: pass + def has_children(self): return True + def num_children(self): return self.len + def get_child_index(self, name): + try: return int(name.removeprefix('[').removesuffix(']')) + except: return -1 + def get_child_at_index(self, index): + try: + if index not in range(self.len): return None + offset = 0 + data = lldb.SBData() + for field in self.entry_type.fields: + field_type = field.type.GetPointeeType() + field_size = field_type.size + data.Append(self.bytes.CreateChildAtOffset(field.name, offset + index * field_size, field_type).address_of.data) + offset += self.capacity * field_size + return self.bytes.CreateValueFromData('[%d]' % index, data, self.entry_type) + except: return None +class std_MultiArrayList_Slice_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.len = 0 + + value_type = self.value.type + for helper in self.value.target.FindFunctions('%s.dbHelper' % value_type.name, lldb.eFunctionNameTypeFull): + ptr_self_type, ptr_child_type, ptr_field_type, ptr_entry_type = helper.function.type.GetFunctionArgumentTypes() + if ptr_self_type.GetPointeeType() == value_type: break + else: return + + self.fields = {member.name: index for index, member in enumerate(ptr_field_type.GetPointeeType().enum_members)} + self.entry_type = ptr_entry_type.GetPointeeType() + self.ptrs = self.value.GetChildMemberWithName('ptrs') + self.len = self.value.GetChildMemberWithName('len').unsigned + self.capacity = self.value.GetChildMemberWithName('capacity').unsigned + except: pass + def has_children(self): return True + def num_children(self): return self.len + def get_child_index(self, name): + try: return int(name.removeprefix('[').removesuffix(']')) + except: return -1 + def get_child_at_index(self, index): + try: + if index not in range(self.len): return None + data = lldb.SBData() + for field in self.entry_type.fields: + field_type = field.type.GetPointeeType() + data.Append(self.ptrs.child[self.fields[field.name.removesuffix('_ptr')]].CreateChildAtOffset(field.name, index * field_type.size, field_type).address_of.data) + return self.ptrs.CreateValueFromData('[%d]' % index, data, self.entry_type) + except: return None + +class std_HashMapUnmanaged_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.capacity = 0 + self.indices = tuple() + + self.metadata = self.value.GetChildMemberWithName('metadata') + if not self.metadata.unsigned: return + + value_type = self.value.type + for helper in self.value.target.FindFunctions('%s.dbHelper' % value_type.name, lldb.eFunctionNameTypeFull): + ptr_self_type, ptr_hdr_type, ptr_entry_type = helper.function.type.GetFunctionArgumentTypes() + if ptr_self_type.GetPointeeType() == value_type: break + else: return + self.entry_type = ptr_entry_type.GetPointeeType() + + hdr_type = ptr_hdr_type.GetPointeeType() + hdr = self.metadata.CreateValueFromAddress('header', self.metadata.deref.load_addr - hdr_type.size, hdr_type) + self.values = hdr.GetChildMemberWithName('values') + self.keys = hdr.GetChildMemberWithName('keys') + self.capacity = hdr.GetChildMemberWithName('capacity').unsigned + + self.indices = tuple(i for i, value in enumerate(self.metadata.GetPointeeData(0, self.capacity).sint8) if value < 0) + except: pass + def has_children(self): return True + def num_children(self): return len(self.indices) + def get_capacity(self): return self.capacity + def get_child_index(self, name): + try: return int(name.removeprefix('[').removesuffix(']')) + except: return -1 + def get_child_at_index(self, index): + try: + fields = {name: base.CreateChildAtOffset(name, self.indices[index] * pointee_type.size, pointee_type).address_of.data for name, base, pointee_type in ((name, base, base.type.GetPointeeType()) for name, base in (('key_ptr', self.keys), ('value_ptr', self.values)))} + data = lldb.SBData() + for field in self.entry_type.fields: data.Append(fields[field.name]) + return self.metadata.CreateValueFromData('[%d]' % index, data, self.entry_type) + except: return None +def std_HashMapUnmanaged_SummaryProvider(value, _=None): + synth = std_HashMapUnmanaged_SynthProvider(value.GetNonSyntheticValue(), _) + synth.update() + return 'len=%d capacity=%d' % (synth.num_children(), synth.get_capacity()) + +# formats a struct of fields of the form `name_ptr: *Type` by auto dereferencing its fields +class std_Entry_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.children = tuple(child.Clone(child.name.removesuffix('_ptr')) for child in self.value.children if child.type.GetPointeeType().size != 0) + self.indices = {child.name: i for i, child in enumerate(self.children)} + except: pass + def has_children(self): return self.num_children() != 0 + def num_children(self): return len(self.children) + def get_child_index(self, name): return self.indices.get(name) + def get_child_at_index(self, index): return self.children[index].deref if index in range(len(self.children)) else None + +# Define Zig Stage2 Compiler + +class TagAndPayload_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + self.tag = self.value.GetChildMemberWithName('tag') or self.value.GetChildMemberWithName('tag_ptr').deref.Clone('tag') + data = self.value.GetChildMemberWithName('data_ptr') or self.value.GetChildMemberWithName('data') + self.payload = data.GetChildMemberWithName('payload').GetChildMemberWithName(data.GetChildMemberWithName('tag').value) + except: pass + def has_children(self): return True + def num_children(self): return 2 + def get_child_index(self, name): + try: return ('tag', 'payload').index(name) + except: return -1 + def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None + +def InstRef_SummaryProvider(value, _=None): + return value if any(value.unsigned == member.unsigned for member in value.type.enum_members) else ( + 'InternPool.Index(%d)' % value.unsigned if value.unsigned < 0x80000000 else 'instructions[%d]' % (value.unsigned - 0x80000000)) + +def InstIndex_SummaryProvider(value, _=None): + return 'instructions[%d]' % value.unsigned + +class zig_DeclIndex_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + ip = InternPool_Find(self.value.thread) + if not ip: return + self.ptr = ip.GetChildMemberWithName('allocated_decls').GetChildAtIndex(self.value.unsigned).address_of.Clone('decl') + except: pass + def has_children(self): return True + def num_children(self): return 1 + def get_child_index(self, name): return 0 if name == 'decl' else -1 + def get_child_at_index(self, index): return self.ptr if index == 0 else None + +class Module_Namespace__Module_Namespace_Index_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + ip = InternPool_Find(self.value.thread) + if not ip: return + self.ptr = ip.GetChildMemberWithName('allocated_namespaces').GetChildAtIndex(self.value.unsigned).address_of.Clone('namespace') + except: pass + def has_children(self): return True + def num_children(self): return 1 + def get_child_index(self, name): return 0 if name == 'namespace' else -1 + def get_child_at_index(self, index): return self.ptr if index == 0 else None + +class TagOrPayloadPtr_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + value_type = self.value.type + for helper in self.value.target.FindFunctions('%s.dbHelper' % value_type.name, lldb.eFunctionNameTypeFull): + ptr_self_type, ptr_tag_to_payload_map_type = helper.function.type.GetFunctionArgumentTypes() + self_type = ptr_self_type.GetPointeeType() + if self_type == value_type: break + else: return + tag_to_payload_map = {field.name: field.type for field in ptr_tag_to_payload_map_type.GetPointeeType().fields} + + tag = self.value.GetChildMemberWithName('tag_if_small_enough') + if tag.unsigned < page_size: + self.tag = tag.Clone('tag') + self.payload = None + else: + ptr_otherwise = self.value.GetChildMemberWithName('ptr_otherwise') + self.tag = ptr_otherwise.GetChildMemberWithName('tag') + self.payload = ptr_otherwise.Cast(tag_to_payload_map[self.tag.value]).GetChildMemberWithName('data').Clone('payload') + except: pass + def has_children(self): return True + def num_children(self): return 1 + (self.payload is not None) + def get_child_index(self, name): + try: return ('tag', 'payload').index(name) + except: return -1 + def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None + +def Module_Decl_name(decl): + error = lldb.SBError() + return decl.process.ReadCStringFromMemory(decl.GetChildMemberWithName('name').deref.load_addr, 256, error) + +def Module_Namespace_RenderFullyQualifiedName(namespace): + parent = namespace.GetChildMemberWithName('parent') + if parent.unsigned < page_size: return zig_String_decode(namespace.GetChildMemberWithName('file_scope').GetChildMemberWithName('sub_file_path')).removesuffix('.zig').replace('/', '.') + return '.'.join((Module_Namespace_RenderFullyQualifiedName(parent), Module_Decl_name(namespace.GetChildMemberWithName('ty').GetChildMemberWithName('payload').GetChildMemberWithName('owner_decl').GetChildMemberWithName('decl')))) + +def Module_Decl_RenderFullyQualifiedName(decl): return '.'.join((Module_Namespace_RenderFullyQualifiedName(decl.GetChildMemberWithName('src_namespace')), Module_Decl_name(decl))) + +def OwnerDecl_RenderFullyQualifiedName(payload): return Module_Decl_RenderFullyQualifiedName(payload.GetChildMemberWithName('owner_decl').GetChildMemberWithName('decl')) + +def InternPool_Find(thread): + for frame in thread: + ip = frame.FindVariable('ip') or frame.FindVariable('intern_pool') + if ip: return ip + mod = frame.FindVariable('zcu') or frame.FindVariable('mod') or frame.FindVariable('module') + if mod: + ip = mod.GetChildMemberWithName('intern_pool') + if ip: return ip + +class InternPool_Index_SynthProvider: + def __init__(self, value, _=None): self.value = value + def update(self): + try: + index_type = self.value.type + for helper in self.value.target.FindFunctions('%s.dbHelper' % index_type.name, lldb.eFunctionNameTypeFull): + ptr_self_type, ptr_tag_to_encoding_map_type = helper.function.type.GetFunctionArgumentTypes() + if ptr_self_type.GetPointeeType() == index_type: break + else: return + tag_to_encoding_map = {field.name: field.type for field in ptr_tag_to_encoding_map_type.GetPointeeType().fields} + + ip = InternPool_Find(self.value.thread) + if not ip: return + self.item = ip.GetChildMemberWithName('items').GetChildAtIndex(self.value.unsigned) + extra = ip.GetChildMemberWithName('extra').GetChildMemberWithName('items') + self.tag = self.item.GetChildMemberWithName('tag').Clone('tag') + self.data = None + self.trailing = None + data = self.item.GetChildMemberWithName('data') + encoding_type = tag_to_encoding_map[self.tag.value] + dynamic_values = {} + for encoding_field in encoding_type.fields: + if encoding_field.name == 'data': + if encoding_field.type.IsPointerType(): + extra_index = data.unsigned + self.data = extra.GetChildAtIndex(extra_index).address_of.Cast(encoding_field.type).deref.Clone('data') + extra_index += encoding_field.type.GetPointeeType().num_fields + else: + self.data = data.Cast(encoding_field.type).Clone('data') + elif encoding_field.name == 'trailing': + trailing_data = lldb.SBData() + for trailing_field in encoding_field.type.fields: + trailing_data.Append(extra.GetChildAtIndex(extra_index).address_of.data) + trailing_len = dynamic_values['trailing.%s.len' % trailing_field.name].unsigned + trailing_data.Append(lldb.SBData.CreateDataFromInt(trailing_len, trailing_data.GetAddressByteSize())) + extra_index += trailing_len + self.trailing = self.data.CreateValueFromData('trailing', trailing_data, encoding_field.type) + else: + for path in encoding_field.type.GetPointeeType().name.removeprefix('%s::' % encoding_type.name).removeprefix('%s.' % encoding_type.name).partition('__')[0].split(' orelse '): + if path.startswith('data.'): + root = self.data + path = path[len('data'):] + else: return + dynamic_value = root.GetValueForExpressionPath(path) + if dynamic_value: + dynamic_values[encoding_field.name] = dynamic_value + break + except: pass + def has_children(self): return True + def num_children(self): return 2 + (self.trailing is not None) + def get_child_index(self, name): + try: return ('tag', 'data', 'trailing').index(name) + except: return -1 + def get_child_at_index(self, index): return (self.tag, self.data, self.trailing)[index] if index in range(3) else None + +def InternPool_NullTerminatedString_SummaryProvider(value, _=None): + try: + ip = InternPool_Find(value.thread) + if not ip: return + items = ip.GetChildMemberWithName('string_bytes').GetChildMemberWithName('items') + b = bytearray() + i = 0 + while True: + x = items.GetChildAtIndex(value.unsigned + i).GetValueAsUnsigned() + if x == 0: break + b.append(x) + i += 1 + s = b.decode(encoding='utf8', errors='backslashreplace') + s1 = s if s.isprintable() else ''.join((c if c.isprintable() else '\\x%02x' % ord(c) for c in s)) + return '"%s"' % s1 + except: + pass + +def type_Type_pointer(payload): + pointee_type = payload.GetChildMemberWithName('pointee_type') + sentinel = payload.GetChildMemberWithName('sentinel').GetChildMemberWithName('child') + align = payload.GetChildMemberWithName('align').unsigned + addrspace = payload.GetChildMemberWithName('addrspace').value + bit_offset = payload.GetChildMemberWithName('bit_offset').unsigned + host_size = payload.GetChildMemberWithName('host_size').unsigned + vector_index = payload.GetChildMemberWithName('vector_index') + allowzero = payload.GetChildMemberWithName('allowzero').unsigned + const = not payload.GetChildMemberWithName('mutable').unsigned + volatile = payload.GetChildMemberWithName('volatile').unsigned + size = payload.GetChildMemberWithName('size').value + + if size == 'One': summary = '*' + elif size == 'Many': summary = '[*' + elif size == 'Slice': summary = '[' + elif size == 'C': summary = '[*c' + if sentinel: summary += ':%s' % value_Value_SummaryProvider(sentinel) + if size != 'One': summary += ']' + if allowzero: summary += 'allowzero ' + if align != 0 or host_size != 0 or vector_index.value != 'none': summary += 'align(%d%s%s) ' % (align, ':%d:%d' % (bit_offset, host_size) if bit_offset != 0 or host_size != 0 else '', ':?' if vector_index.value == 'runtime' else ':%d' % vector_index.unsigned if vector_index.value != 'none' else '') + if addrspace != 'generic': summary += 'addrspace(.%s) ' % addrspace + if const: summary += 'const ' + if volatile: summary += 'volatile ' + summary += type_Type_SummaryProvider(pointee_type) + return summary + +def type_Type_function(payload): + param_types = payload.GetChildMemberWithName('param_types').children + comptime_params = payload.GetChildMemberWithName('comptime_params').GetPointeeData(0, len(param_types)).uint8 + return_type = payload.GetChildMemberWithName('return_type') + alignment = payload.GetChildMemberWithName('alignment').unsigned + noalias_bits = payload.GetChildMemberWithName('noalias_bits').unsigned + cc = payload.GetChildMemberWithName('cc').value + is_var_args = payload.GetChildMemberWithName('is_var_args').unsigned + + return 'fn(%s)%s%s %s' % (', '.join(tuple(''.join(('comptime ' if comptime_param else '', 'noalias ' if noalias_bits & 1 << i else '', type_Type_SummaryProvider(param_type))) for i, (comptime_param, param_type) in enumerate(zip(comptime_params, param_types))) + (('...',) if is_var_args else ())), ' align(%d)' % alignment if alignment != 0 else '', ' callconv(.%s)' % cc if cc != 'Unspecified' else '', type_Type_SummaryProvider(return_type)) + +def type_Type_SummaryProvider(value, _=None): + tag = value.GetChildMemberWithName('tag').value + return type_tag_handlers.get(tag, lambda payload: tag)(value.GetChildMemberWithName('payload')) + +type_tag_handlers = { + 'atomic_order': lambda payload: 'std.builtin.AtomicOrder', + 'atomic_rmw_op': lambda payload: 'std.builtin.AtomicRmwOp', + 'calling_convention': lambda payload: 'std.builtin.CallingConvention', + 'address_space': lambda payload: 'std.builtin.AddressSpace', + 'float_mode': lambda payload: 'std.builtin.FloatMode', + 'reduce_op': lambda payload: 'std.builtin.ReduceOp', + 'modifier': lambda payload: 'std.builtin.CallModifier', + 'prefetch_options': lambda payload: 'std.builtin.PrefetchOptions', + 'export_options': lambda payload: 'std.builtin.ExportOptions', + 'extern_options': lambda payload: 'std.builtin.ExternOptions', + 'type_info': lambda payload: 'std.builtin.Type', + + 'enum_literal': lambda payload: '@TypeOf(.enum_literal)', + 'null': lambda payload: '@TypeOf(null)', + 'undefined': lambda payload: '@TypeOf(undefined)', + 'empty_struct_literal': lambda payload: '@TypeOf(.{})', + + 'anyerror_void_error_union': lambda payload: 'anyerror!void', + 'slice_const_u8': lambda payload: '[]const u8', + 'slice_const_u8_sentinel_0': lambda payload: '[:0]const u8', + 'fn_noreturn_no_args': lambda payload: 'fn() noreturn', + 'fn_void_no_args': lambda payload: 'fn() void', + 'fn_naked_noreturn_no_args': lambda payload: 'fn() callconv(.Naked) noreturn', + 'fn_ccc_void_no_args': lambda payload: 'fn() callconv(.C) void', + 'single_const_pointer_to_comptime_int': lambda payload: '*const comptime_int', + 'manyptr_u8': lambda payload: '[*]u8', + 'manyptr_const_u8': lambda payload: '[*]const u8', + 'manyptr_const_u8_sentinel_0': lambda payload: '[*:0]const u8', + + 'function': type_Type_function, + 'error_union': lambda payload: '%s!%s' % (type_Type_SummaryProvider(payload.GetChildMemberWithName('error_set')), type_Type_SummaryProvider(payload.GetChildMemberWithName('payload'))), + 'array_u8': lambda payload: '[%d]u8' % payload.unsigned, + 'array_u8_sentinel_0': lambda payload: '[%d:0]u8' % payload.unsigned, + 'vector': lambda payload: '@Vector(%d, %s)' % (payload.GetChildMemberWithName('len').unsigned, type_Type_SummaryProvider(payload.GetChildMemberWithName('elem_type'))), + 'array': lambda payload: '[%d]%s' % (payload.GetChildMemberWithName('len').unsigned, type_Type_SummaryProvider(payload.GetChildMemberWithName('elem_type'))), + 'array_sentinel': lambda payload: '[%d:%s]%s' % (payload.GetChildMemberWithName('len').unsigned, value_Value_SummaryProvider(payload.GetChildMemberWithName('sentinel')), type_Type_SummaryProvider(payload.GetChildMemberWithName('elem_type'))), + 'tuple': lambda payload: 'tuple{%s}' % ', '.join(('comptime %%s = %s' % value_Value_SummaryProvider(value) if value.GetChildMemberWithName('tag').value != 'unreachable_value' else '%s') % type_Type_SummaryProvider(type) for type, value in zip(payload.GetChildMemberWithName('types').children, payload.GetChildMemberWithName('values').children)), + 'anon_struct': lambda payload: 'struct{%s}' % ', '.join(('comptime %%s: %%s = %s' % value_Value_SummaryProvider(value) if value.GetChildMemberWithName('tag').value != 'unreachable_value' else '%s: %s') % (zig_String_AsIdentifier(name, zig_IsFieldName), type_Type_SummaryProvider(type)) for name, type, value in zip(payload.GetChildMemberWithName('names').children, payload.GetChildMemberWithName('types').children, payload.GetChildMemberWithName('values').children)), + 'pointer': type_Type_pointer, + 'single_const_pointer': lambda payload: '*const %s' % type_Type_SummaryProvider(payload), + 'single_mut_pointer': lambda payload: '*%s' % type_Type_SummaryProvider(payload), + 'many_const_pointer': lambda payload: '[*]const %s' % type_Type_SummaryProvider(payload), + 'many_mut_pointer': lambda payload: '[*]%s' % type_Type_SummaryProvider(payload), + 'c_const_pointer': lambda payload: '[*c]const %s' % type_Type_SummaryProvider(payload), + 'c_mut_pointer': lambda payload: '[*c]%s' % type_Type_SummaryProvider(payload), + 'slice_const': lambda payload: '[]const %s' % type_Type_SummaryProvider(payload), + 'mut_slice': lambda payload: '[]%s' % type_Type_SummaryProvider(payload), + 'int_signed': lambda payload: 'i%d' % payload.unsigned, + 'int_unsigned': lambda payload: 'u%d' % payload.unsigned, + 'optional': lambda payload: '?%s' % type_Type_SummaryProvider(payload), + 'optional_single_mut_pointer': lambda payload: '?*%s' % type_Type_SummaryProvider(payload), + 'optional_single_const_pointer': lambda payload: '?*const %s' % type_Type_SummaryProvider(payload), + 'anyframe_T': lambda payload: 'anyframe->%s' % type_Type_SummaryProvider(payload), + 'error_set': lambda payload: type_tag_handlers['error_set_merged'](payload.GetChildMemberWithName('names')), + 'error_set_single': lambda payload: 'error{%s}' % zig_String_AsIdentifier(payload, zig_IsFieldName), + 'error_set_merged': lambda payload: 'error{%s}' % ','.join(zig_String_AsIdentifier(child.GetChildMemberWithName('key'), zig_IsFieldName) for child in payload.GetChildMemberWithName('entries').children), + 'error_set_inferred': lambda payload: '@typeInfo(@typeInfo(@TypeOf(%s)).@"fn".return_type.?).error_union.error_set' % OwnerDecl_RenderFullyQualifiedName(payload.GetChildMemberWithName('func')), + + 'enum_full': OwnerDecl_RenderFullyQualifiedName, + 'enum_nonexhaustive': OwnerDecl_RenderFullyQualifiedName, + 'enum_numbered': OwnerDecl_RenderFullyQualifiedName, + 'enum_simple': OwnerDecl_RenderFullyQualifiedName, + 'struct': OwnerDecl_RenderFullyQualifiedName, + 'union': OwnerDecl_RenderFullyQualifiedName, + 'union_safety_tagged': OwnerDecl_RenderFullyQualifiedName, + 'union_tagged': OwnerDecl_RenderFullyQualifiedName, + 'opaque': OwnerDecl_RenderFullyQualifiedName, +} + +def value_Value_str_lit(payload): + for frame in payload.thread: + mod = frame.FindVariable('zcu') or frame.FindVariable('mod') or frame.FindVariable('module') + if mod: break + else: return + return '"%s"' % zig_String_decode(mod.GetChildMemberWithName('string_literal_bytes').GetChildMemberWithName('items'), payload.GetChildMemberWithName('index').unsigned, payload.GetChildMemberWithName('len').unsigned) + +def value_Value_SummaryProvider(value, _=None): + tag = value.GetChildMemberWithName('tag').value + return value_tag_handlers.get(tag, lambda payload: tag.removesuffix('_type'))(value.GetChildMemberWithName('payload')) + +value_tag_handlers = { + 'undef': lambda payload: 'undefined', + 'zero': lambda payload: '0', + 'one': lambda payload: '1', + 'void_value': lambda payload: '{}', + 'unreachable_value': lambda payload: 'unreachable', + 'null_value': lambda payload: 'null', + 'bool_true': lambda payload: 'true', + 'bool_false': lambda payload: 'false', + + 'empty_struct_value': lambda payload: '.{}', + 'empty_array': lambda payload: '.{}', + + 'ty': type_Type_SummaryProvider, + 'int_type': lambda payload: '%c%d' % (payload.GetChildMemberWithName('bits').unsigned, 's' if payload.GetChildMemberWithName('signed').unsigned == 1 else 'u'), + 'int_u64': lambda payload: '%d' % payload.unsigned, + 'int_i64': lambda payload: '%d' % payload.signed, + 'int_big_positive': lambda payload: sum(child.unsigned << i * child.type.size * 8 for i, child in enumerate(payload.children)), + 'int_big_negative': lambda payload: '-%s' % value_tag_handlers['int_big_positive'](payload), + 'function': OwnerDecl_RenderFullyQualifiedName, + 'extern_fn': OwnerDecl_RenderFullyQualifiedName, + 'variable': lambda payload: value_Value_SummaryProvider(payload.GetChildMemberWithName('decl').GetChildMemberWithName('val')), + 'runtime_value': value_Value_SummaryProvider, + 'decl_ref': lambda payload: value_Value_SummaryProvider(payload.GetChildMemberWithName('decl').GetChildMemberWithName('val')), + 'decl_ref_mut': lambda payload: value_Value_SummaryProvider(payload.GetChildMemberWithName('decl_index').GetChildMemberWithName('decl').GetChildMemberWithName('val')), + 'comptime_field_ptr': lambda payload: '&%s' % value_Value_SummaryProvider(payload.GetChildMemberWithName('field_val')), + 'elem_ptr': lambda payload: '(%s)[%d]' % (value_Value_SummaryProvider(payload.GetChildMemberWithName('array_ptr')), payload.GetChildMemberWithName('index').unsigned), + 'field_ptr': lambda payload: '(%s).field[%d]' % (value_Value_SummaryProvider(payload.GetChildMemberWithName('container_ptr')), payload.GetChildMemberWithName('field_index').unsigned), + 'bytes': lambda payload: '"%s"' % zig_String_decode(payload), + 'str_lit': value_Value_str_lit, + 'repeated': lambda payload: '.{%s} ** _' % value_Value_SummaryProvider(payload), + 'empty_array_sentinel': lambda payload: '.{%s}' % value_Value_SummaryProvider(payload), + 'slice': lambda payload: '(%s)[0..%s]' % tuple(value_Value_SummaryProvider(payload.GetChildMemberWithName(name)) for name in ('ptr', 'len')), + 'float_16': lambda payload: payload.value, + 'float_32': lambda payload: payload.value, + 'float_64': lambda payload: payload.value, + 'float_80': lambda payload: payload.value, + 'float_128': lambda payload: payload.value, + 'enum_literal': lambda payload: '.%s' % zig_String_AsIdentifier(payload, zig_IsFieldName), + 'enum_field_index': lambda payload: 'field[%d]' % payload.unsigned, + 'error': lambda payload: 'error.%s' % zig_String_AsIdentifier(payload.GetChildMemberWithName('name'), zig_IsFieldName), + 'eu_payload': value_Value_SummaryProvider, + 'eu_payload_ptr': lambda payload: '&((%s).* catch unreachable)' % value_Value_SummaryProvider(payload.GetChildMemberWithName('container_ptr')), + 'opt_payload': value_Value_SummaryProvider, + 'opt_payload_ptr': lambda payload: '&(%s).*.?' % value_Value_SummaryProvider(payload.GetChildMemberWithName('container_ptr')), + 'aggregate': lambda payload: '.{%s}' % ', '.join(map(value_Value_SummaryProvider, payload.children)), + 'union': lambda payload: '.{.%s = %s}' % tuple(value_Value_SummaryProvider(payload.GetChildMemberWithName(name)) for name in ('tag', 'val')), + + 'lazy_align': lambda payload: '@alignOf(%s)' % type_Type_SummaryProvider(payload), + 'lazy_size': lambda payload: '@sizeOf(%s)' % type_Type_SummaryProvider(payload), +} + +# Initialize + +def add(debugger, *, category, regex=False, type, identifier=None, synth=False, inline_children=False, expand=False, summary=False): + prefix = '.'.join((__name__, (identifier or type).replace('.', '_').replace(':', '_'))) + if summary: debugger.HandleCommand('type summary add --category %s%s%s "%s"' % (category, ' --inline-children' if inline_children else ''.join((' --expand' if expand else '', ' --python-function %s_SummaryProvider' % prefix if summary == True else ' --summary-string "%s"' % summary)), ' --regex' if regex else '', type)) + if synth: debugger.HandleCommand('type synthetic add --category %s%s --python-class %s_SynthProvider "%s"' % (category, ' --regex' if regex else '', prefix, type)) + +def MultiArrayList_Entry(type): return '^multi_array_list\\.MultiArrayList\\(%s\\)\\.Entry__struct_[1-9][0-9]*$' % type + +def __lldb_init_module(debugger, _=None): + # Initialize Zig Categories + debugger.HandleCommand('type category define --language c99 zig.lang zig.std') + + # Initialize Zig Language + add(debugger, category='zig.lang', regex=True, type='^\\[\\]', identifier='zig_Slice', synth=True, expand=True, summary='len=${svar%#}') + add(debugger, category='zig.lang', type='[]u8', identifier='zig_String', summary=True) + add(debugger, category='zig.lang', regex=True, type='^\\?', identifier='zig_Optional', synth=True, summary=True) + add(debugger, category='zig.lang', regex=True, type='^(error{.*}|anyerror)!', identifier='zig_ErrorUnion', synth=True, inline_children=True, summary=True) + + # Initialize Zig Standard Library + add(debugger, category='zig.std', type='mem.Allocator', summary='${var.ptr}') + add(debugger, category='zig.std', regex=True, type='^segmented_list\\.SegmentedList\\(.*\\)$', identifier='std_SegmentedList', synth=True, expand=True, summary='len=${var.len}') + add(debugger, category='zig.std', regex=True, type='^multi_array_list\\.MultiArrayList\\(.*\\)$', identifier='std_MultiArrayList', synth=True, expand=True, summary='len=${var.len} capacity=${var.capacity}') + add(debugger, category='zig.std', regex=True, type='^multi_array_list\\.MultiArrayList\\(.*\\)\\.Slice$', identifier='std_MultiArrayList_Slice', synth=True, expand=True, summary='len=${var.len} capacity=${var.capacity}') + add(debugger, category='zig.std', regex=True, type=MultiArrayList_Entry('.*'), identifier='std_Entry', synth=True, inline_children=True, summary=True) + add(debugger, category='zig.std', regex=True, type='^hash_map\\.HashMapUnmanaged\\(.*\\)$', identifier='std_HashMapUnmanaged', synth=True, expand=True, summary=True) + add(debugger, category='zig.std', regex=True, type='^hash_map\\.HashMapUnmanaged\\(.*\\)\\.Entry$', identifier = 'std_Entry', synth=True, inline_children=True, summary=True) + + # Initialize Zig Stage2 Compiler + add(debugger, category='zig.stage2', type='Zir.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) + add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Zir\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) + add(debugger, category='zig.stage2', regex=True, type='^Zir\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) + add(debugger, category='zig.stage2', type='Zir.Inst::Zir.Inst.Ref', identifier='InstRef', summary=True) + add(debugger, category='zig.stage2', type='Zir.Inst::Zir.Inst.Index', identifier='InstIndex', summary=True) + add(debugger, category='zig.stage2', type='Air.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) + add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Ref', identifier='InstRef', summary=True) + add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Index', identifier='InstIndex', summary=True) + add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) + add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) + add(debugger, category='zig.stage2', type='zig.DeclIndex', synth=True) + add(debugger, category='zig.stage2', type='Module.Namespace::Module.Namespace.Index', synth=True) + add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True) + add(debugger, category='zig.stage2', type='InternPool.Index', synth=True) + add(debugger, category='zig.stage2', type='InternPool.NullTerminatedString', summary=True) + add(debugger, category='zig.stage2', type='InternPool.Key', identifier='zig_TaggedUnion', synth=True) + add(debugger, category='zig.stage2', type='InternPool.Key.Int.Storage', identifier='zig_TaggedUnion', synth=True) + add(debugger, category='zig.stage2', type='InternPool.Key.ErrorUnion.Value', identifier='zig_TaggedUnion', synth=True) + add(debugger, category='zig.stage2', type='InternPool.Key.Float.Storage', identifier='zig_TaggedUnion', synth=True) + add(debugger, category='zig.stage2', type='InternPool.Key.Ptr.Addr', identifier='zig_TaggedUnion', synth=True) + add(debugger, category='zig.stage2', type='InternPool.Key.Aggregate.Storage', identifier='zig_TaggedUnion', synth=True) + add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True) diff --git a/misctools/lldb/lldb_webkit.py b/misctools/lldb/lldb_webkit.py new file mode 100644 index 0000000000..a6b11771ee --- /dev/null +++ b/misctools/lldb/lldb_webkit.py @@ -0,0 +1,1303 @@ +# https://github.com/oven-sh/WebKit/blob/main/Tools/lldb/lldb_webkit.py + +# Copyright (C) 2012-2024 Apple Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" + LLDB Support for WebKit Types + + Add the following to your .lldbinit file to add WebKit Type summaries in LLDB and Xcode: + + command script import {Path to WebKit Root}/Tools/lldb/lldb_webkit.py + +""" + +import re +import string +import struct +import sys + +import lldb + +if sys.version_info >= (3, 10): + # The key argument was added in 3.10. + from bisect import bisect_right +else: + def bisect_right(a, x, lo=0, hi=None, *, key=lambda x: x): + if lo < 0: + raise ValueError('lo must be non-negative') + if hi is None: + hi = len(a) + while lo < hi: + mid = (lo + hi) // 2 + if x < key(a[mid]): + hi = mid + else: + lo = mid + 1 + return lo + + +def addSummaryAndSyntheticFormattersForRawBitmaskType(debugger, type_name, enumerator_value_to_name_map, flags_mask=None): + class GeneratedRawBitmaskProvider(RawBitmaskProviderBase): + ENUMERATOR_VALUE_TO_NAME_MAP = enumerator_value_to_name_map.copy() + FLAGS_MASK = flags_mask + + def raw_bitmask_summary_provider(valobj, dict): + provider = GeneratedRawBitmaskProvider(valobj, dict) + return "{ size = %d }" % provider.size + + # Add the provider class and summary function to the global scope so that LLDB + # can find them. + python_type_name = type_name.replace('::', '') # Remove qualifications (e.g. WebCore::X becomes WebCoreX) + synthetic_provider_class_name = python_type_name + 'Provider' + summary_provider_function_name = python_type_name + '_SummaryProvider' + globals()[synthetic_provider_class_name] = GeneratedRawBitmaskProvider + globals()[summary_provider_function_name] = raw_bitmask_summary_provider + + debugger.HandleCommand('type summary add --expand -F lldb_webkit.%s "%s"' % (summary_provider_function_name, type_name)) + debugger.HandleCommand('type synthetic add %s --python-class lldb_webkit.%s' % (type_name, synthetic_provider_class_name)) + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand('command script add -f lldb_webkit.btjs btjs') + debugger.HandleCommand('command script add -f lldb_webkit.llintLocate llintLocate') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFString_SummaryProvider WTF::String') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFStringImpl_SummaryProvider WTF::StringImpl') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFStringView_SummaryProvider WTF::StringView') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFAtomString_SummaryProvider WTF::AtomString') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFVector_SummaryProvider -x "^WTF::Vector<.+>$"') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFHashTable_SummaryProvider -x "^WTF::HashTable<.+>$"') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFHashMap_SummaryProvider -x "^WTF::HashMap<.+>$"') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFHashSet_SummaryProvider -x "^WTF::HashSet<.+>$"') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFMediaTime_SummaryProvider WTF::MediaTime') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFOptionSet_SummaryProvider -x "^WTF::OptionSet<.+>$"') + debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFCompactPointerTuple_SummaryProvider -x "^WTF::CompactPointerTuple<.+,.+>$"') + + debugger.HandleCommand('type summary add -F lldb_webkit.WTFURL_SummaryProvider WTF::URL') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreColor_SummaryProvider WebCore::Color') + + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLayoutUnit_SummaryProvider WebCore::LayoutUnit') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLayoutSize_SummaryProvider WebCore::LayoutSize') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLayoutPoint_SummaryProvider WebCore::LayoutPoint') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLayoutRect_SummaryProvider WebCore::LayoutRect') + + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreIntSize_SummaryProvider WebCore::IntSize') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreIntPoint_SummaryProvider WebCore::IntPoint') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreIntRect_SummaryProvider WebCore::IntRect') + + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreFloatSize_SummaryProvider WebCore::FloatSize') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreFloatPoint_SummaryProvider WebCore::FloatPoint') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreFloatRect_SummaryProvider WebCore::FloatRect') + + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLength_SummaryProvider WebCore::Length') + + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreSecurityOrigin_SummaryProvider WebCore::SecurityOrigin') + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreFrame_SummaryProvider WebCore::Frame') + + for className in ['Document', 'FTPDirectoryDocument', 'HTMLDocument', 'ImageDocument', 'MediaDocument', 'PluginDocument', 'SVGDocument', 'SinkDocument', 'TextDocument', 'XMLDocument']: + debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreDocument_SummaryProvider WebCore::' + className) + + # synthetic types (see ) + debugger.HandleCommand('type synthetic add -x "^WTF::Vector<.+>$" --python-class lldb_webkit.WTFVectorProvider') + debugger.HandleCommand('type synthetic add -x "^WTF::HashTable<.+>$" --python-class lldb_webkit.WTFHashTableProvider') + debugger.HandleCommand('type synthetic add -x "^WTF::OptionSet<.+>$" --python-class lldb_webkit.WTFOptionSetProvider') + debugger.HandleCommand('type synthetic add -x "^WTF::CompactPointerTuple<.+,.+>$" --python-class lldb_webkit.WTFCompactPointerTupleProvider') + + addSummaryAndSyntheticFormattersForRawBitmaskType(debugger, "WebEventFlags", { + 0x00010000: "WebEventFlagMaskLeftCommandKey", + 0x00020000: "WebEventFlagMaskLeftShiftKey", + 0x00040000: "WebEventFlagMaskLeftCapsLockKey", + 0x00080000: "WebEventFlagMaskLeftOptionKey", + 0x00100000: "WebEventFlagMaskLeftControlKey", + 0x00800000: "WebEventFlagMaskRightControlKey", + 0x00200000: "WebEventFlagMaskRightShiftKey", + 0x00400000: "WebEventFlagMaskRightOptionKey", + 0x01000000: "WebEventFlagMaskRightCommandKey", + }) + + # AppKit + NSEventModifierFlagDeviceIndependentFlagsMask = 0xffff0000 + addSummaryAndSyntheticFormattersForRawBitmaskType(debugger, "NSEventModifierFlags", { + 1 << 16: "NSEventModifierFlagCapsLock", + 1 << 17: "NSEventModifierFlagShift", + 1 << 18: "NSEventModifierFlagControl", + 1 << 19: "NSEventModifierFlagOption", + 1 << 20: "NSEventModifierFlagCommand", + 1 << 21: "NSEventModifierFlagNumericPad", + 1 << 22: "NSEventModifierFlagHelp", + 1 << 23: "NSEventModifierFlagFunction", + }, flags_mask=NSEventModifierFlagDeviceIndependentFlagsMask) + + +def WTFString_SummaryProvider(valobj, dict): + provider = WTFStringProvider(valobj, dict) + return "{ length = %d, contents = '%s' }" % (provider.get_length(), provider.to_string()) + + +def WTFStringImpl_SummaryProvider(valobj, dict): + provider = WTFStringImplProvider(valobj, dict) + if not provider.is_initialized(): + return "" + return "{ length = %d, is8bit = %d, contents = '%s' }" % (provider.get_length(), provider.is_8bit(), provider.to_string()) + + +def WTFStringView_SummaryProvider(valobj, dict): + provider = WTFStringViewProvider(valobj, dict) + return "{ length = %d, contents = '%s' }" % (provider.get_length(), provider.to_string()) + + +def WTFAtomString_SummaryProvider(valobj, dict): + return WTFString_SummaryProvider(valobj.GetChildMemberWithName('m_string'), dict) + + +def WTFVector_SummaryProvider(valobj, dict): + provider = WTFVectorProvider(valobj, dict) + return "{ size = %d, capacity = %d }" % (provider.size, provider.capacity) + + +def WTFHashTable_SummaryProvider(valobj, dict): + provider = WTFHashTableProvider(valobj, dict) + return "{ tableSize = %d, keyCount = %d }" % (provider.tableSize(), provider.keyCount()) + + +def WTFHashMap_SummaryProvider(valobj, dict): + provider = WTFHashMapProvider(valobj, dict) + return "{ tableSize = %d, keyCount = %d }" % (provider.tableSize(), provider.keyCount()) + + +def WTFHashSet_SummaryProvider(valobj, dict): + provider = WTFHashSetProvider(valobj, dict) + return "{ tableSize = %d, keyCount = %d }" % (provider.tableSize(), provider.keyCount()) + + +def WTFOptionSet_SummaryProvider(valobj, dict): + provider = WTFOptionSetProvider(valobj, dict) + return "{ size = %d }" % provider.size + + +def WTFMediaTime_SummaryProvider(valobj, dict): + provider = WTFMediaTimeProvider(valobj, dict) + if provider.isInvalid(): + return "{ Invalid }" + if provider.isPositiveInfinity(): + return "{ +Infinity }" + if provider.isNegativeInfinity(): + return "{ -Infinity }" + if provider.isIndefinite(): + return "{ Indefinite }" + if provider.hasDoubleValue(): + return "{ %f }" % (provider.timeValueAsDouble()) + return "{ %d/%d, %f }" % (provider.timeValue(), provider.timeScale(), float(provider.timeValue()) / provider.timeScale()) + + +def WTFCompactPointerTuple_SummaryProvider(valobj, dict): + provider = WTFCompactPointerTupleProvider(valobj, dict) + return "{ type = %s }" % provider.type_as_string() + + +def WebCoreColor_SummaryProvider(valobj, dict): + provider = WebCoreColorProvider(valobj, dict) + return "{ %s }" % provider.to_string() + + +def WTFURL_SummaryProvider(valobj, dict): + provider = WTFURLProvider(valobj, dict) + return "{ %s }" % provider.to_string() + + +def WebCoreLayoutUnit_SummaryProvider(valobj, dict): + provider = WebCoreLayoutUnitProvider(valobj, dict) + return "{ %s }" % provider.to_string() + + +def WebCoreLayoutSize_SummaryProvider(valobj, dict): + provider = WebCoreLayoutSizeProvider(valobj, dict) + return "{ width = %s, height = %s }" % (provider.get_width(), provider.get_height()) + + +def WebCoreLayoutPoint_SummaryProvider(valobj, dict): + provider = WebCoreLayoutPointProvider(valobj, dict) + return "{ x = %s, y = %s }" % (provider.get_x(), provider.get_y()) + + +def WebCoreLayoutRect_SummaryProvider(valobj, dict): + provider = WebCoreLayoutRectProvider(valobj, dict) + return "{ x = %s, y = %s, width = %s, height = %s }" % (provider.get_x(), provider.get_y(), provider.get_width(), provider.get_height()) + + +def WebCoreIntSize_SummaryProvider(valobj, dict): + provider = WebCoreIntSizeProvider(valobj, dict) + return "{ width = %s, height = %s }" % (provider.get_width(), provider.get_height()) + + +def WebCoreIntPoint_SummaryProvider(valobj, dict): + provider = WebCoreIntPointProvider(valobj, dict) + return "{ x = %s, y = %s }" % (provider.get_x(), provider.get_y()) + + +def WebCoreFloatSize_SummaryProvider(valobj, dict): + provider = WebCoreFloatSizeProvider(valobj, dict) + return "{ width = %s, height = %s }" % (provider.get_width(), provider.get_height()) + + +def WebCoreFloatPoint_SummaryProvider(valobj, dict): + provider = WebCoreFloatPointProvider(valobj, dict) + return "{ x = %s, y = %s }" % (provider.get_x(), provider.get_y()) + + +def WebCoreIntRect_SummaryProvider(valobj, dict): + provider = WebCoreIntRectProvider(valobj, dict) + return "{ x = %s, y = %s, width = %s, height = %s }" % (provider.get_x(), provider.get_y(), provider.get_width(), provider.get_height()) + + +def WebCoreFloatRect_SummaryProvider(valobj, dict): + provider = WebCoreFloatRectProvider(valobj, dict) + return "{ x = %s, y = %s, width = %s, height = %s }" % (provider.get_x(), provider.get_y(), provider.get_width(), provider.get_height()) + + +def WebCoreLength_SummaryProvider(valobj, dict): + provider = WebCoreLengthProvider(valobj, dict) + quirky = ' (quirky)' if provider.has_quirk() else "" + + if (provider.is_auto()): + return "{ auto%s }" % (quirky) + + if (provider.is_undefined()): + return "{ undefined%s }" % (quirky) + + if (provider.is_calculated()): + return "{ calc%s }" % (quirky) + + if (provider.is_fixed()): + return "{ %spx%s }" % (provider.get_numeric_value(), quirky) + + if (provider.is_percent()): + return "{ %s%%%s }" % (provider.get_numeric_value(), quirky) + + return "{ %s %s%s }" % (provider.get_type_string(), provider.get_numeric_value(), quirky) + + +def WebCoreSecurityOrigin_SummaryProvider(valobj, dict): + provider = WebCoreSecurityOriginProvider(valobj, dict) + return '{ %s, domain = %s, hasUniversalAccess = %d }' % (provider.to_string(), provider.domain(), provider.has_universal_access()) + + +def WebCoreFrame_SummaryProvider(valobj, dict): + provider = WebCoreFrameProvider(valobj, dict) + document = provider.document() + if document: + origin = document.origin() + url = document.url() + backForwardCacheState = document.page_cache_state() + else: + origin = '' + url = '' + backForwardCacheState = '' + return '{ origin = %s, url = %s, isMainFrame = %d, backForwardCacheState = %s }' % (origin, url, provider.is_main_frame(), backForwardCacheState) + + +def WebCoreDocument_SummaryProvider(valobj, dict): + provider = WebCoreDocumentProvider(valobj, dict) + frame = provider.frame() + in_main_frame = '%d' % frame.is_main_frame() if frame else 'Detached' + return '{ origin = %s, url = %s, inMainFrame = %s, backForwardCacheState = %s }' % (provider.origin(), provider.url(), in_main_frame, provider.page_cache_state()) + + +def btjs(debugger, command, result, internal_dict): + '''Prints a stack trace of current thread with JavaScript frames decoded. Takes optional frame count argument''' + + target = debugger.GetSelectedTarget() + addressFormat = '#0{width}x'.format(width=target.GetAddressByteSize() * 2 + 2) + process = target.GetProcess() + thread = process.GetSelectedThread() + jscModule = target.module["JavaScriptCore"] + + if jscModule.FindSymbol("JSC::CallFrame::describeFrame").GetSize() or jscModule.FindSymbol("_ZN3JSC9CallFrame13describeFrameEv").GetSize(): + annotateJSFrames = True + else: + annotateJSFrames = False + + if not annotateJSFrames: + print("Warning: Can't find JSC::CallFrame::describeFrame() in executable to annotate JavaScript frames") + + backtraceDepth = thread.GetNumFrames() + + if len(command) > 0: + try: + backtraceDepth = int(command) + except ValueError: + return + + threadFormat = '* thread #{num}: tid = {tid:#x}, {pcAddr:' + addressFormat + '}, queue = \'{queueName}, stop reason = {stopReason}' + # FIXME: GetStopDescription needs to be pass a stupidly large length because lldb has weird utf-8 encoding errors if it's too small. See: rdar://problem/57980599 + print(threadFormat.format(num=thread.GetIndexID(), tid=thread.GetThreadID(), pcAddr=thread.GetFrameAtIndex(0).GetPC(), queueName=thread.GetQueueName(), stopReason=thread.GetStopDescription(300))) + + llintStart = jscModule.FindSymbol("jsc_llint_begin").addr.GetLoadAddress(target) + llintEnd = jscModule.FindSymbol("jsc_llint_end").addr.GetLoadAddress(target) + + for frame in thread: + if backtraceDepth < 1: + break + + backtraceDepth = backtraceDepth - 1 + + if annotateJSFrames and (not frame.GetSymbol() or (llintStart < frame.pc and frame.pc < llintEnd)): + callFrame = frame.GetSP() + JSFrameDescription = frame.EvaluateExpression("((JSC::CallFrame*)0x%x)->describeFrame()" % frame.GetFP()).GetSummary() + if not JSFrameDescription: + JSFrameDescription = frame.EvaluateExpression("(char*)_ZN3JSC9CallFrame13describeFrameEv(0x%x)" % frame.GetFP()).GetSummary() + if JSFrameDescription: + JSFrameDescription = JSFrameDescription.strip('"') + frameFormat = ' frame #{num}: {addr:' + addressFormat + '} {desc}' + print(frameFormat.format(num=frame.GetFrameID(), addr=frame.GetPC(), desc=JSFrameDescription)) + continue + print(' %s' % frame) + + +# FIXME: This seems like we should be able to do this with a formatter https://lldb.llvm.org/use/formatting.html +# If we did we could also add info about what JIT location we're at. +# FIXME: Once rdar://133349487 is resolved we hopefully shouldn't need this anymore. +def llintLocate(debugger, commond, result, internal_dict): + target = debugger.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetSelectedThread() + jscModule = target.module["JavaScriptCore"] + + frame = thread.GetFrameAtIndex(0) + pc = frame.GetPC() + + if frame.GetSymbol() and frame.GetSymbol().GetName() == "jsc_llint_begin": + llintRegex = re.compile("^op_|^llint_|^jsc_|^wasm|^ipint_") + llintSymbols = jscModule.symbol[llintRegex] + + index = bisect_right(llintSymbols, pc, key=lambda symbol: symbol.addr.GetLoadAddress(target)) + + closestSymbol = llintSymbols[index] + # if we're exactly on a symbol then bisect_right will return the next symbol. In that case we want the "previous" symbol. + if not closestSymbol or closestSymbol.addr.GetLoadAddress(target) > pc: + closestSymbol = llintSymbols[index - 1] + if closestSymbol: + print("{name} at {pcStart}".format(name=closestSymbol.name, pcStart=closestSymbol.addr)) + return + + print("not in llint") + + +# FIXME: Provide support for the following types: +# def WTFVector_SummaryProvider(valobj, dict): +# def WTFCString_SummaryProvider(valobj, dict): +# def WebCoreQualifiedName_SummaryProvider(valobj, dict): +# def JSCIdentifier_SummaryProvider(valobj, dict): +# def JSCJSString_SummaryProvider(valobj, dict): + + +def guess_string_length(valobj, charSize, error): + if not valobj.GetValue(): + return 0 + + maxLength = 256 + + pointer = valobj.GetValueAsUnsigned() + contents = valobj.GetProcess().ReadMemory(pointer, maxLength * charSize, lldb.SBError()) + format = 'B' if charSize == 1 else 'H' + + for i in xrange(0, maxLength): + if not struct.unpack_from(format, contents, i * charSize)[0]: + return i + + return maxLength + +def ustring_to_string(valobj, error, length=None): + if length is None: + length = guess_string_length(valobj, 2, error) + else: + length = int(length) + + if length == 0: + return "" + + pointer = valobj.GetValueAsUnsigned() + contents = valobj.GetProcess().ReadMemory(pointer, length * 2, lldb.SBError()) + + # lldb does not (currently) support returning unicode from python summary providers, + # so potentially convert this to ascii by escaping + string = contents.decode('utf16') + try: + return str(string) + except: + return string.encode('unicode_escape') + +def lstring_to_string(valobj, error, length=None): + if length is None: + length = guess_string_length(valobj, 1, error) + else: + length = int(length) + + if length == 0: + return "" + + pointer = valobj.GetValueAsUnsigned() + contents = valobj.GetProcess().ReadMemory(pointer, length, lldb.SBError()) + if not contents: + return "" + + # lldb does not (currently) support returning unicode from python summary providers, + # so potentially convert this to ascii by escaping + string = contents.decode('utf8') + try: + return str(string) + except: + return string.encode('unicode_escape') + +class WTFStringImplProvider: + def __init__(self, valobj, dict): + # FIXME: For some reason lldb(1) sometimes has an issue accessing members of WTF::StringImplShape + # via a WTF::StringImpl pointer (why?). As a workaround we explicitly cast to WTF::StringImplShape*. + string_impl_shape_ptr_type = valobj.GetTarget().FindFirstType('WTF::StringImplShape').GetPointerType() + self.valobj = valobj.Cast(string_impl_shape_ptr_type) + + def get_length(self): + return self.valobj.GetChildMemberWithName('m_length').GetValueAsUnsigned(0) + + def get_data8(self): + return self.valobj.GetChildAtIndex(2).GetChildMemberWithName('m_data8') + + def get_data16(self): + return self.valobj.GetChildAtIndex(2).GetChildMemberWithName('m_data16') + + def to_string(self): + error = lldb.SBError() + + if not self.is_initialized(): + return u"" + + if self.is_8bit(): + return lstring_to_string(self.get_data8(), error, self.get_length()) + return ustring_to_string(self.get_data16(), error, self.get_length()) + + def is_8bit(self): + # FIXME: find a way to access WTF::StringImpl::s_hashFlag8BitBuffer + return bool(self.valobj.GetChildMemberWithName('m_hashAndFlags').GetValueAsUnsigned(0) \ + & 1 << 2) + + def is_initialized(self): + return self.valobj.GetValueAsUnsigned() != 0 + + +class WTFStringViewProvider: + def __init__(self, valobj, dict): + self.valobj = valobj + + def is_8bit(self): + return bool(self.valobj.GetChildMemberWithName('m_is8Bit').GetValueAsUnsigned(0)) + + def get_length(self): + return self.valobj.GetChildMemberWithName('m_length').GetValueAsUnsigned(0) + + def get_characters(self): + return self.valobj.GetChildMemberWithName('m_characters') + + def to_string(self): + error = lldb.SBError() + + if not self.get_characters() or not self.get_length(): + return u"" + + if self.is_8bit(): + return lstring_to_string(self.get_characters(), error, self.get_length()) + return ustring_to_string(self.get_characters(), error, self.get_length()) + + +class WTFStringProvider: + def __init__(self, valobj, dict): + self.valobj = valobj + + def stringimpl(self): + impl_ptr = self.valobj.GetChildMemberWithName('m_impl').GetChildMemberWithName('m_ptr') + return WTFStringImplProvider(impl_ptr, dict) + + def get_length(self): + impl = self.stringimpl() + if not impl: + return 0 + return impl.get_length() + + def to_string(self): + impl = self.stringimpl() + if not impl: + return u"" + return impl.to_string() + + +class WebCoreColorProvider: + SEMANTIC_FLAG = 1 << 0 + USE_COLOR_FUNCTION_SERIALIZATION_FLAG = 1 << 1 + VALID_FLAG = 1 << 2 + OUT_OF_LINE_FLAG = 1 << 3 + + COLOR_VALUE_MASK = (1 << 48) - 1 # only correct for 64-bit + FLAGS_SHIFT = 48 + FLAGS_SIZE = 8 + COLOR_SPACE_SHIFT = FLAGS_SHIFT + FLAGS_SIZE + + "Print a WebCore::Color" + def __init__(self, valobj, dict): + self.valobj = valobj + + def _is_out_of_line(self, rgba_and_flags): + flags = self._flags(rgba_and_flags) + return bool(flags & self.OUT_OF_LINE_FLAG) + + def _is_valid(self, rgba_and_flags): + flags = self._flags(rgba_and_flags) + return bool(flags & self.VALID_FLAG) + + def _is_semantic(self, rgba_and_flags): + flags = self._flags(rgba_and_flags) + return bool(flags & self.SEMANTIC_FLAG) + + def _color_space(self, rgba_and_flags): + return rgba_and_flags >> self.COLOR_SPACE_SHIFT + + def _flags(self, rgba_and_flags): + return rgba_and_flags >> self.FLAGS_SHIFT + + def _to_string_out_of_line(self): + rgba_and_flags = self.valobj.GetChildMemberWithName('m_colorAndFlags').GetValueAsUnsigned(0) + + out_of_line_components_type = self.valobj.GetTarget().FindFirstType('WebCore::Color::OutOfLineComponents') + out_of_line_components = self.valobj.CreateValueFromAddress('out_of_line_components', rgba_and_flags & self.COLOR_VALUE_MASK, out_of_line_components_type) + + color_space = self._color_space(rgba_and_flags) + + # From ColorSpace.h. + color_spaces = [ + 'A98RGB', + 'DisplayP3', + 'ExtendedA98RGB', + 'ExtendedDisplayP3', + 'ExtendedLinearSRGB', + 'ExtendedProPhotoRGB', + 'ExtendedRec2020', + 'ExtendedSRGB', + 'HSL', + 'HWB', + 'LCH', + 'Lab', + 'LinearSRGB', + 'OKLCH', + 'OKLab', + 'ProPhotoRGB', + 'Rec2020', + 'SRGB', + 'XYZ_D50', + 'XYZ_D65', + ] + + profile = color_spaces[color_space] if color_space < len(color_spaces) else 'unknown' + + color_components = out_of_line_components.GetChildMemberWithName('m_components') + std_array_elems = color_components.GetChildMemberWithName('components').GetChildMemberWithName('__elems_') + + red = float(std_array_elems.GetChildAtIndex(0).GetValue()) + green = float(std_array_elems.GetChildAtIndex(1).GetValue()) + blue = float(std_array_elems.GetChildAtIndex(2).GetValue()) + alpha = float(std_array_elems.GetChildAtIndex(3).GetValue()) + + semantic = ' semantic' if self._is_semantic(rgba_and_flags) else "" + + return "color(%s %1.2f %1.2f %1.2f / %1.2f)%s" % (profile, red, green, blue, alpha, semantic) + + def to_string(self): + rgba_and_flags = self.valobj.GetChildMemberWithName('m_colorAndFlags').GetValueAsUnsigned(0) + + if self._is_out_of_line(rgba_and_flags): + return self._to_string_out_of_line() + + if not self._is_valid(rgba_and_flags): + return 'invalid' + + color = rgba_and_flags & self.COLOR_VALUE_MASK + red = (color >> 24) & 0xFF + green = (color >> 16) & 0xFF + blue = (color >> 8) & 0xFF + alpha = (color & 0xFF) / 255.0 + + semantic = ' semantic' if self._is_semantic(rgba_and_flags) else "" + + result = 'rgba(%d, %d, %d, %1.2f)%s' % (red, green, blue, alpha, semantic) + return result + + +class WebCoreLayoutUnitProvider: + "Print a WebCore::LayoutUnit" + def __init__(self, valobj, dict): + self.valobj = valobj + + def to_string(self): + layoutUnitValue = self.valobj.GetChildMemberWithName('m_value').GetValueAsSigned(0) + return "%gpx (%d)" % (float(layoutUnitValue) / 64, layoutUnitValue) + + +class WebCoreLayoutSizeProvider: + "Print a WebCore::LayoutSize" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_width(self): + return WebCoreLayoutUnitProvider(self.valobj.GetChildMemberWithName('m_width'), dict).to_string() + + def get_height(self): + return WebCoreLayoutUnitProvider(self.valobj.GetChildMemberWithName('m_height'), dict).to_string() + + +class WebCoreLayoutPointProvider: + "Print a WebCore::LayoutPoint" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_x(self): + return WebCoreLayoutUnitProvider(self.valobj.GetChildMemberWithName('m_x'), dict).to_string() + + def get_y(self): + return WebCoreLayoutUnitProvider(self.valobj.GetChildMemberWithName('m_y'), dict).to_string() + + +class WebCoreLayoutRectProvider: + "Print a WebCore::LayoutRect" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_x(self): + return WebCoreLayoutPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_x() + + def get_y(self): + return WebCoreLayoutPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_y() + + def get_width(self): + return WebCoreLayoutSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_width() + + def get_height(self): + return WebCoreLayoutSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_height() + + +class WebCoreIntPointProvider: + "Print a WebCore::IntPoint" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_x(self): + return self.valobj.GetChildMemberWithName('m_x').GetValueAsSigned() + + def get_y(self): + return self.valobj.GetChildMemberWithName('m_y').GetValueAsSigned() + + +class WebCoreIntSizeProvider: + "Print a WebCore::IntSize" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_width(self): + return self.valobj.GetChildMemberWithName('m_width').GetValueAsSigned() + + def get_height(self): + return self.valobj.GetChildMemberWithName('m_height').GetValueAsSigned() + + +class WebCoreIntRectProvider: + "Print a WebCore::IntRect" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_x(self): + return WebCoreIntPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_x() + + def get_y(self): + return WebCoreIntPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_y() + + def get_width(self): + return WebCoreIntSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_width() + + def get_height(self): + return WebCoreIntSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_height() + + +class WebCoreFloatPointProvider: + "Print a WebCore::FloatPoint" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_x(self): + return float(self.valobj.GetChildMemberWithName('m_x').GetValue()) + + def get_y(self): + return float(self.valobj.GetChildMemberWithName('m_y').GetValue()) + + +class WebCoreFloatSizeProvider: + "Print a WebCore::FloatSize" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_width(self): + return float(self.valobj.GetChildMemberWithName('m_width').GetValue()) + + def get_height(self): + return float(self.valobj.GetChildMemberWithName('m_height').GetValue()) + + +class WebCoreFloatRectProvider: + "Print a WebCore::FloatRect" + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_x(self): + return WebCoreFloatPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_x() + + def get_y(self): + return WebCoreFloatPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_y() + + def get_width(self): + return WebCoreFloatSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_width() + + def get_height(self): + return WebCoreFloatSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_height() + + +class WebCoreLengthProvider: + "Print a WebCore::Length" + + AUTO_TYPE = 0 + RELATIVE_TYPE = 1 + PERCENT_TYPE = 2 + FIXED_TYPE = 3 + INTRINSIC_TYPE = 4 + MIN_INTRINSIC_TYPE = 5 + MIN_CONTENT_TYPE = 6 + MAX_CONTENT_TYPE = 7 + FILL_AVAILABLE_TYPE = 8 + FIT_CONTENT_TYPE = 9 + CALCULATED_TYPE = 10 + UNDEFINED_TYPE = 11 + + def __init__(self, valobj, dict): + self.valobj = valobj + + def get_type(self): + return self.valobj.GetChildMemberWithName('m_type').GetValueAsUnsigned(0) + + def get_type_string(self): + length_type = self.get_type() + + type_names = [ + "Auto", + "Relative", + "Percent", + "Fixed", + "Intrinsic", + "MinIntrinsic", + "MinContent", + "MaxContent", + "FillAvailable", + "FitContent", + "Calculated", + "Undefined", + ] + + if (length_type <= self.UNDEFINED_TYPE): + return type_names[length_type] + + return "Unknown" + + def is_auto(self): + return self.get_type() == self.AUTO_TYPE + + def is_undefined(self): + return self.get_type() == self.UNDEFINED_TYPE + + def is_calculated(self): + return self.get_type() == self.CALCULATED_TYPE + + def is_fixed(self): + return self.get_type() == self.FIXED_TYPE + + def is_percent(self): + return self.get_type() == self.PERCENT_TYPE + + def has_quirk(self): + return bool(self.valobj.GetChildMemberWithName('m_hasQuirk').GetValueAsUnsigned(0)) + + def is_float(self): + return bool(self.valobj.GetChildMemberWithName('m_isFloat').GetValueAsUnsigned(0)) + + def get_numeric_value(self): + length_type = self.get_type() + if (length_type == self.CALCULATED_TYPE): + return 0 + + if (self.is_float()): + return self.valobj.GetChildMemberWithName('m_floatValue').GetValue() + + return self.valobj.GetChildMemberWithName('m_intValue').GetValueAsSigned() + + + +class WTFURLProvider: + "Print a WTF::URL" + def __init__(self, valobj, dict): + self.valobj = valobj + + def to_string(self): + return WTFStringProvider(self.valobj.GetChildMemberWithName('m_string'), dict).to_string() + + +class StdOptionalWrapper: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def has_value(self): + return bool(self.valobj.GetChildMemberWithName('init_').GetValueAsUnsigned(0)) + + def value(self): + return self.valobj.GetChildMemberWithName('storage_').GetChildMemberWithName('value_') + + +class WebCoreSecurityOriginProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + self._data_ptr = self.valobj.GetChildMemberWithName('m_data') + + def is_unique(self): + return bool(self.valobj.GetChildMemberWithName('m_isUnique').GetValueAsUnsigned(0)) + + def scheme(self): + return WTFStringProvider(self._data_ptr.GetChildMemberWithName('protocol'), dict()).to_string() + + def host(self): + return WTFStringProvider(self._data_ptr.GetChildMemberWithName('host'), dict()).to_string() + + def port(self): + optional_port = StdOptionalWrapper(self._data_ptr.GetChildMemberWithName('port'), dict()) + if not optional_port.has_value(): + return None + return optional_port.value().GetValueAsUnsigned(0) + + def domain(self): + return WTFStringProvider(self.valobj.GetChildMemberWithName('m_domain'), dict()).to_string() + + def has_universal_access(self): + return bool(self.valobj.GetChildMemberWithName('m_universalAccess').GetValueAsUnsigned(0)) + + def to_string(self): + if self.is_unique(): + return 'Unique' + scheme = self.scheme() + host = self.host() + port = self.port() + if not scheme and not host and not port: + return '' + if scheme == 'file:': + return 'file://' + result = '{}://{}'.format(scheme, host) + if port: + result += ':' + str(port) + return result + + +class WebCoreFrameProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def is_main_frame(self): + return self.valobj.GetAddress().GetFileAddress() == self.valobj.GetChildMemberWithName('m_mainFrame').GetAddress().GetFileAddress() + + def document(self): + document_ptr = self.valobj.GetChildMemberWithName('m_doc').GetChildMemberWithName('m_ptr') + if not document_ptr or not bool(document_ptr.GetValueAsUnsigned(0)): + return None + return WebCoreDocumentProvider(document_ptr, dict()) + + +class WebCoreDocumentProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def url(self): + return WTFURLProvider(self.valobj.GetChildMemberWithName('m_url'), dict()).to_string() + + def origin(self): + security_origin_ptr = self.valobj.GetChildMemberWithName('m_securityOriginPolicy').GetChildMemberWithName('m_ptr').GetChildMemberWithName('m_securityOrigin').GetChildMemberWithName('m_ptr') + return WebCoreSecurityOriginProvider(security_origin_ptr, dict()).to_string() + + def page_cache_state(self): + return self.valobj.GetChildMemberWithName('m_backForwardCacheState').GetValue() + + def frame(self): + frame_ptr = self.valobj.GetChildMemberWithName('m_frame') + if not frame_ptr or not bool(frame_ptr.GetValueAsUnsigned(0)): + return None + return WebCoreFrameProvider(frame_ptr, dict()) + + +class FlagEnumerationProvider(object): + def __init__(self, valobj, internal_dict): + self.valobj = valobj + self._elements = [] + self.update() + + # Subclasses must override this to return a dictionary that maps emumerator values to names. + def _enumerator_value_to_name_map(self): + pass + + # Subclasses must override this to return the bitmask. + def _bitmask(self): + pass + + # Subclasses can override this to perform any computations when LLDB needs to refresh + # this provider. + def _update(self): + pass + + # Subclasses can override this to provide the index that corresponds to the specified name. + # If this method is overridden then it is also expected that _get_child_at_index() will be + # overridden to provide the value for the index returned by this method. Note that the + # returned index must be greater than or equal to self.size in order to avoid breaking + # printing of synthetic children. + def _get_child_index(self, name): + return None + + # Subclasses can override this to provide the SBValue for the specified index. It is only + # meaningful to override this method if _get_child_index() is also overridden. + def _get_child_at_index(self, index): + return None + + @property + def size(self): + return len(self._elements) + + # LLDB overrides + def has_children(self): + return bool(self._elements) + + def num_children(self): + return len(self._elements) + + def get_child_index(self, name): + return self._get_child_index(name) + + def get_child_at_index(self, index): + if index < 0 or not self.valobj.IsValid(): + return None + if index < len(self._elements): + (name, value) = self._elements[index] + return self.valobj.CreateValueFromExpression(name, str(value)) + return self._get_child_at_index(index) + + def update(self): + self._update() + + enumerator_value_to_name_map = self._enumerator_value_to_name_map() + if not enumerator_value_to_name_map: + return + + bitmask_with_all_options_set = sum(enumerator_value_to_name_map) + bitmask = self._bitmask() + if bitmask > bitmask_with_all_options_set: + return # Since this is an invalid value, return so the raw hex form is written out. + + # self.valobj looks like it contains a valid value. + # Iterate from least significant bit to most significant bit. + elements = [] + while bitmask > 0: + current = bitmask & -bitmask # Isolate the rightmost set bit. + elements.append((enumerator_value_to_name_map[current], current)) # e.g. ('Spelling', 4) + bitmask = bitmask & (bitmask - 1) # Turn off the rightmost set bit. + self._elements = elements + +class WTFOptionSetProvider(FlagEnumerationProvider): + def _enumerator_value_to_name_map(self): + template_argument_sbType = self.valobj.GetType().GetTemplateArgumentType(0) + enumerator_value_to_name_map = {} + for sbTypeEnumMember in template_argument_sbType.get_enum_members_array(): + enumerator_value = sbTypeEnumMember.GetValueAsUnsigned() + if enumerator_value not in enumerator_value_to_name_map: + enumerator_value_to_name_map[enumerator_value] = sbTypeEnumMember.GetName() + return enumerator_value_to_name_map + + def _bitmask(self): + return self.storage.GetValueAsUnsigned(0) + + def _update(self): + self.storage = self.valobj.GetChildMemberWithName('m_storage') # May be an invalid value. + + def _get_child_index(self, name): + if name == 'm_storage': + return self.size + return None + + def _get_child_at_index(self, index): + if index == self.size: + return self.storage + return None + + +class RawBitmaskProviderBase(FlagEnumerationProvider): + ENUMERATOR_VALUE_TO_NAME_MAP = {} + FLAGS_MASK = None # Useful when a bitmask represents multiple disjoint sets of flags (e.g. NSEventModifierFlags). + + def _enumerator_value_to_name_map(self): + return self.ENUMERATOR_VALUE_TO_NAME_MAP + + def _bitmask(self): + result = self.valobj.GetValueAsUnsigned(0) + if self.FLAGS_MASK is not None: + result = result & self.FLAGS_MASK + return result + + +class WTFCompactPointerTupleProvider(object): + + TYPE_MASK = 0xFFFF000000000000 + POINTER_MASK = ~TYPE_MASK + + def __init__(self, valobj, internal_dict): + self.valobj = valobj + self._is32Bit = valobj.GetTarget().GetAddressByteSize() == 4 + self._pointer = None + self._type = None + self.update() + + def type_as_string(self): + if not self.is_human_readable_type(): + return "%s" % self._type.GetValueAsUnsigned(0) + return "%s" % self._type.GetValue() + + def is_human_readable_type(self): + # The default summary provider for uint8_t, unsigned char emits the ASCII printable character or equivalent + # C escape sequence (e.g. \a = 0x07). Typically the CompactPointerTuple is used to encode non-character integral + # data. In this context it is less readable to use the default summary provider. So, we don't. + return self.valobj.GetType().GetTemplateArgumentType(1).GetBasicType() != lldb.eBasicTypeUnsignedChar + + # LLDB overrides + def has_children(self): + return self._type is not None and self._pointer is not None + + def num_children(self): + if not self.has_children: + return 0 + return 2 + + def get_child_index(self, name): + if name == '[0]': + return 0 + if name == '[1]': + return 1 + if self._is32Bit: + if name == 'm_pointer': + return 2 + if name == 'm_type': + return 3 + else: + if name == 'm_data': + return 2 + return None + + def get_child_at_index(self, index): + if index < 0 or not self.valobj.IsValid(): + return None + if index == 0: + return self._pointer + if index == 1: + return self._type + if self._is32Bit: + if index == 2: + return self._pointer + if index == 3: + return self._type + else: + if index == 2: + return self.valobj.GetChildMemberWithName('m_data') + return None + + def update(self): + if self._is32Bit: + self._pointer = self.valobj.GetChildMemberWithName('m_pointer') + self._type = self.valobj.GetChildMemberWithName('m_type') + else: + data = self.valobj.GetChildMemberWithName('m_data').GetValueAsUnsigned(0) + byte_order = self.valobj.GetTarget().GetByteOrder() + address_byte_size = self.valobj.GetTarget().GetAddressByteSize() + + pointer_data = lldb.SBData.CreateDataFromUInt64Array(byte_order, address_byte_size, [data & self.POINTER_MASK]) + self._pointer = self.valobj.CreateValueFromData('[0]', pointer_data, self.valobj.GetType().GetTemplateArgumentType(0)) + + type_data = lldb.SBData.CreateDataFromUInt64Array(byte_order, address_byte_size, [(data >> 48) & 0xFFFF]) + type_to_use = self.valobj.GetType().GetTemplateArgumentType(1) + if not self.is_human_readable_type(): + type_to_use = self.valobj.GetTarget().GetBasicType(lldb.eBasicTypeUnsignedInt) + self._type = self.valobj.CreateValueFromData('[1]', type_data, type_to_use) + + +class WTFVectorProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + self.update() + + def num_children(self): + return self.size + 3 + + def get_child_index(self, name): + if name == "m_size": + return self.size + elif name == "m_capacity": + return self.size + 1 + elif name == "m_buffer": + return self.size + 2 + else: + return int(name.lstrip('[').rstrip(']')) + + def get_child_at_index(self, index): + if index == self.size: + return self.valobj.GetChildMemberWithName("m_size") + elif index == self.size + 1: + return self.valobj.GetChildMemberWithName("m_capacity") + elif index == self.size + 2: + return self.buffer + elif index < self.size: + offset = index * self.data_size + child = self.buffer.CreateChildAtOffset('[' + str(index) + ']', offset, self.data_type) + return child + else: + return None + + def update(self): + self.buffer = self.valobj.GetChildMemberWithName('m_buffer') + self.size = self.valobj.GetChildMemberWithName('m_size').GetValueAsUnsigned(0) + self.capacity = self.valobj.GetChildMemberWithName('m_capacity').GetValueAsUnsigned(0) + self.data_type = self.buffer.GetType().GetPointeeType() + self.data_size = self.data_type.GetByteSize() + + def has_children(self): + return True + + +class WTFHashMapProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + impl_ptr = self.valobj.GetChildMemberWithName('m_impl') + self._hash_table_provider = WTFHashTableProvider(impl_ptr, dict) + + def tableSize(self): + return self._hash_table_provider.tableSize() + + def keyCount(self): + return self._hash_table_provider.keyCount() + + +class WTFHashSetProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + impl_ptr = self.valobj.GetChildMemberWithName('m_impl') + self._hash_table_provider = WTFHashTableProvider(impl_ptr, dict) + + def tableSize(self): + return self._hash_table_provider.tableSize() + + def keyCount(self): + return self._hash_table_provider.keyCount() + + +class WTFHashTableProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + self.update() + + def metadataWithIndex(self, index): + table_pointer = self.valobj.GetChildMemberWithName('m_tableForLLDB') + metadata_pointer = table_pointer.GetValueAsUnsigned() + 4 * index + byte_order = self.valobj.GetTarget().GetByteOrder() + address_byte_size = self.valobj.GetTarget().GetAddressByteSize() + pointer_data = lldb.SBData.CreateDataFromUInt64Array(byte_order, address_byte_size, [metadata_pointer]) + return self.valobj.CreateValueFromData('[0]', pointer_data, table_pointer.GetType()).Dereference().GetValueAsUnsigned() + + def tableSize(self): + return self.metadataWithIndex(-1) + + def keyCount(self): + return self.metadataWithIndex(-3) + + # Synthetic children provider methods. + def num_children(self): + return self.tableSize() + 1 + + def get_child_index(self, name): + if name == "m_table": + return self.tableSize() + else: + return int(name.lstrip('[').rstrip(']')) + + def get_child_at_index(self, index): + if index == self.tableSize(): + return self.valobj.GetChildMemberWithName('m_table') + elif index < self.tableSize(): + table = self.valobj.GetChildMemberWithName('m_table') + return table.CreateChildAtOffset('[' + str(index) + ']', index * self.data_size, self.data_type) + else: + return None + + def update(self): + self.data_type = self.valobj.GetType().GetTemplateArgumentType(1) + self.data_size = self.data_type.GetByteSize() + + def has_children(self): + return True + + +class WTFMediaTimeProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def timeValue(self): + return self.valobj.GetChildMemberWithName('m_timeValue').GetValueAsSigned(0) + + def timeValueAsDouble(self): + error = lldb.SBError() + return self.valobj.GetChildMemberWithName('m_timeValueAsDouble').GetData().GetDouble(error, 0) + + def timeScale(self): + return self.valobj.GetChildMemberWithName('m_timeScale').GetValueAsSigned(0) + + def isInvalid(self): + return not self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 0) + + def isPositiveInfinity(self): + return self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 2) + + def isNegativeInfinity(self): + return self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 3) + + def isIndefinite(self): + return self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 4) + + def hasDoubleValue(self): + return self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 5) From 3906d02e2cf7239f7d108c63b577c36e68d0ca38 Mon Sep 17 00:00:00 2001 From: Zack Radisic <56137411+zackradisic@users.noreply.github.com> Date: Mon, 16 Dec 2024 19:40:53 -0800 Subject: [PATCH 027/125] CSS fixes (#15806) --- src/bundler.zig | 3 +- src/bundler/bundle_v2.zig | 22 ++- src/css/css_internals.zig | 13 +- src/css/css_parser.zig | 10 +- src/css/declaration.zig | 2 +- src/css/dependencies.zig | 4 +- src/css/printer.zig | 19 ++- src/css/properties/custom.zig | 4 + src/css/properties/generate_properties.ts | 4 +- src/css/properties/properties_generated.zig | 3 +- src/css/properties/properties_impl.zig | 1 + src/css/properties/transform.zig | 4 +- src/css/rules/rules.zig | 2 - src/css/selectors/parser.zig | 77 +++++---- src/css/selectors/selector.zig | 5 +- src/css/targets.zig | 172 +++++++++++++++++++- src/css/values/color_js.zig | 2 +- test/bundler/esbuild/css.test.ts | 1 + test/js/bun/css/css.test.ts | 32 +++- test/js/bun/css/doesnt_crash.test.ts | 12 +- test/js/bun/css/util.ts | 10 +- 21 files changed, 324 insertions(+), 78 deletions(-) diff --git a/src/bundler.zig b/src/bundler.zig index 5a11d98b28..ed9c903a87 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -13,7 +13,7 @@ const C = bun.C; const std = @import("std"); const lex = bun.js_lexer; const logger = bun.logger; -const options = @import("options.zig"); +pub const options = @import("options.zig"); const js_parser = bun.js_parser; const JSON = bun.JSON; const js_printer = bun.js_printer; @@ -958,6 +958,7 @@ pub const Bundler = struct { return null; } const result = sheet.toCss(alloc, bun.css.PrinterOptions{ + .targets = bun.css.Targets.forBundlerTarget(bundler.options.target), .minify = bundler.options.minify_whitespace, }, null) catch |e| { bun.handleErrorReturnTrace(e, @errorReturnTrace()); diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index 66c4018634..c03935eecb 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -3744,7 +3744,7 @@ pub const ParseTask = struct { }, }; if (css_ast.minify(allocator, bun.css.MinifyOptions{ - .targets = .{}, + .targets = bun.css.Targets.forBundlerTarget(bundler.options.target), .unused_symbols = .{}, }).asErr()) |e| { try e.addToLogger(log, &source); @@ -9106,13 +9106,15 @@ pub const LinkerContext = struct { }; var import_records = BabyList(ImportRecord).init(&import_records_); const css: *const bun.css.BundlerStyleSheet = &chunk.content.css.asts[imports_in_chunk_index]; + const printer_options = bun.css.PrinterOptions{ + // TODO: make this more configurable + .minify = c.options.minify_whitespace, + .targets = bun.css.Targets.forBundlerTarget(c.options.target), + }; _ = css.toCssWithWriter( worker.allocator, &buffer_writer, - bun.css.PrinterOptions{ - // TODO: make this more configurable - .minify = c.options.minify_whitespace, - }, + printer_options, &import_records, ) catch { @panic("TODO: HANDLE THIS ERROR!"); @@ -9126,13 +9128,15 @@ pub const LinkerContext = struct { }, .source_index => |idx| { const css: *const bun.css.BundlerStyleSheet = &chunk.content.css.asts[imports_in_chunk_index]; + const printer_options = bun.css.PrinterOptions{ + .targets = bun.css.Targets.forBundlerTarget(c.options.target), + // TODO: make this more configurable + .minify = c.options.minify_whitespace or c.options.minify_syntax or c.options.minify_identifiers, + }; _ = css.toCssWithWriter( worker.allocator, &buffer_writer, - bun.css.PrinterOptions{ - // TODO: make this more configurable - .minify = c.options.minify_whitespace or c.options.minify_syntax or c.options.minify_identifiers, - }, + printer_options, &c.graph.ast.items(.import_records)[idx.get()], ) catch { @panic("TODO: HANDLE THIS ERROR!"); diff --git a/src/css/css_internals.zig b/src/css/css_internals.zig index 46b7f133f0..09a86a80a0 100644 --- a/src/css/css_internals.zig +++ b/src/css/css_internals.zig @@ -60,18 +60,19 @@ pub fn testingImpl(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, c const expected = expected_bunstr.toUTF8(bun.default_allocator); defer expected.deinit(); - const options_arg = arguments.nextEat(); + const browser_options_arg = arguments.nextEat(); var log = bun.logger.Log.init(alloc); defer log.deinit(); + var browsers: ?bun.css.targets.Browsers = null; const parser_options = parser_options: { const opts = bun.css.ParserOptions.default(alloc, &log); // if (test_kind == .prefix) break :parser_options opts; - if (options_arg) |optargs| { + if (browser_options_arg) |optargs| { if (optargs.isObject()) { - // minify_options.targets.browsers = targetsFromJS(globalThis, optarg); + browsers = try targetsFromJS(globalThis, optargs); } } @@ -88,11 +89,7 @@ pub fn testingImpl(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, c .result => |stylesheet_| { var stylesheet = stylesheet_; var minify_options: bun.css.MinifyOptions = bun.css.MinifyOptions.default(); - if (options_arg) |optarg| { - if (optarg.isObject()) { - minify_options.targets.browsers = try targetsFromJS(globalThis, optarg); - } - } + minify_options.targets.browsers = browsers; _ = stylesheet.minify(alloc, minify_options).assert(); const result = stylesheet.toCss(alloc, bun.css.PrinterOptions{ diff --git a/src/css/css_parser.zig b/src/css/css_parser.zig index 40ceaa2966..306b4d4dcd 100644 --- a/src/css/css_parser.zig +++ b/src/css/css_parser.zig @@ -186,8 +186,14 @@ pub const VendorPrefix = packed struct(u8) { } /// Returns VendorPrefix::None if empty. - pub fn orNone(this: VendorPrefix) VendorPrefix { - return this.bitwiseOr(VendorPrefix{ .none = true }); + pub inline fn orNone(this: VendorPrefix) VendorPrefix { + return this._or(VendorPrefix{ .none = true }); + } + + /// **WARNING**: NOT THE SAME as .bitwiseOr!! + pub inline fn _or(this: VendorPrefix, other: VendorPrefix) VendorPrefix { + if (this.isEmpty()) return other; + return this; } }; diff --git a/src/css/declaration.zig b/src/css/declaration.zig index f84c4f9c11..a7ec7e1182 100644 --- a/src/css/declaration.zig +++ b/src/css/declaration.zig @@ -47,7 +47,7 @@ pub const DeclarationBlock = struct { var arraylist = ArrayList(u8){}; const w = arraylist.writer(bun.default_allocator); defer arraylist.deinit(bun.default_allocator); - var printer = css.Printer(@TypeOf(w)).new(bun.default_allocator, std.ArrayList(u8).init(bun.default_allocator), w, .{}, null); + var printer = css.Printer(@TypeOf(w)).new(bun.default_allocator, std.ArrayList(u8).init(bun.default_allocator), w, css.PrinterOptions.default(), null); defer printer.deinit(); this.self.toCss(@TypeOf(w), &printer) catch |e| return try writer.print("\n", .{@errorName(e)}); try writer.writeAll(arraylist.items); diff --git a/src/css/dependencies.zig b/src/css/dependencies.zig index 7d922244dd..453f9cefb3 100644 --- a/src/css/dependencies.zig +++ b/src/css/dependencies.zig @@ -70,7 +70,7 @@ pub const ImportDependency = struct { allocator, css.css_rules.supports.SupportsCondition, supports, - css.PrinterOptions{}, + css.PrinterOptions.default(), null, ) catch bun.Output.panic( "Unreachable code: failed to stringify SupportsCondition.\n\nThis is a bug in Bun's CSS printer. Please file a bug report at https://github.com/oven-sh/bun/issues/new/choose", @@ -80,7 +80,7 @@ pub const ImportDependency = struct { } else null; const media = if (rule.media.media_queries.items.len > 0) media: { - const s = css.to_css.string(allocator, css.MediaList, &rule.media, css.PrinterOptions{}, null) catch bun.Output.panic( + const s = css.to_css.string(allocator, css.MediaList, &rule.media, css.PrinterOptions.default(), null) catch bun.Output.panic( "Unreachable code: failed to stringify MediaList.\n\nThis is a bug in Bun's CSS printer. Please file a bug report at https://github.com/oven-sh/bun/issues/new/choose", .{}, ); diff --git a/src/css/printer.zig b/src/css/printer.zig index 9d7b029e2a..c50adb3bcd 100644 --- a/src/css/printer.zig +++ b/src/css/printer.zig @@ -26,7 +26,7 @@ pub const PrinterOptions = struct { /// An optional project root path, used to generate relative paths for sources used in CSS module hashes. project_root: ?[]const u8 = null, /// Targets to output the CSS for. - targets: Targets = .{}, + targets: Targets, /// Whether to analyze dependencies (i.e. `@import` and `url()`). /// If true, the dependencies are returned as part of the /// [ToCssResult](super::stylesheet::ToCssResult). @@ -39,6 +39,23 @@ pub const PrinterOptions = struct { /// from JavaScript. Useful for polyfills, for example. pseudo_classes: ?PseudoClasses = null, public_path: []const u8 = "", + + pub fn default() PrinterOptions { + return .{ + .targets = Targets{ + .browsers = null, + }, + }; + } + + pub fn defaultWithMinify(minify: bool) PrinterOptions { + return .{ + .targets = Targets{ + .browsers = null, + }, + .minify = minify, + }; + } }; /// A mapping of user action pseudo classes to replace with class names. diff --git a/src/css/properties/custom.zig b/src/css/properties/custom.zig index eaa7ad2f89..cfde458ae0 100644 --- a/src/css/properties/custom.zig +++ b/src/css/properties/custom.zig @@ -1433,6 +1433,10 @@ pub const UnparsedProperty = struct { pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { return css.implementDeepClone(@This(), this, allocator); } + + pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { + return css.implementEql(@This(), lhs, rhs); + } }; /// A CSS custom property, representing any unknown property. diff --git a/src/css/properties/generate_properties.ts b/src/css/properties/generate_properties.ts index e7f79c1e2e..f55f04d022 100644 --- a/src/css/properties/generate_properties.ts +++ b/src/css/properties/generate_properties.ts @@ -287,7 +287,8 @@ function generatePropertyImpl(property_defs: Record): strin return `.${escapeIdent(name)} => |*v| css.generic.eql(${meta.ty}, v, &rhs.${escapeIdent(name)}),`; }) .join("\n")} - .all, .unparsed => true, + .unparsed => |*u| u.eql(&rhs.unparsed), + .all => true, .custom => |*c| c.eql(&rhs.custom), }; } @@ -1077,6 +1078,7 @@ generateCode({ "margin-right": { ty: "LengthPercentageOrAuto", logical_group: { ty: "margin", category: "physical" }, + eval_branch_quota: 5000, }, "margin-block-start": { ty: "LengthPercentageOrAuto", diff --git a/src/css/properties/properties_generated.zig b/src/css/properties/properties_generated.zig index be76ee77a7..46615f071a 100644 --- a/src/css/properties/properties_generated.zig +++ b/src/css/properties/properties_generated.zig @@ -6951,7 +6951,8 @@ pub const Property = union(PropertyIdTag) { .@"mask-box-image-width" => |*v| css.generic.eql(Rect(BorderImageSideWidth), &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image-width"[1]), .@"mask-box-image-outset" => |*v| css.generic.eql(Rect(LengthOrNumber), &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image-outset"[1]), .@"mask-box-image-repeat" => |*v| css.generic.eql(BorderImageRepeat, &v[0], &v[0]) and v[1].eq(rhs.@"mask-box-image-repeat"[1]), - .all, .unparsed => true, + .unparsed => |*u| u.eql(&rhs.unparsed), + .all => true, .custom => |*c| c.eql(&rhs.custom), }; } diff --git a/src/css/properties/properties_impl.zig b/src/css/properties/properties_impl.zig index 6a56e20d0e..871a61cdd3 100644 --- a/src/css/properties/properties_impl.zig +++ b/src/css/properties/properties_impl.zig @@ -20,6 +20,7 @@ pub fn PropertyIdImpl() type { var first = true; const name = this.name(this); const prefix_value = this.prefix().orNone(); + inline for (VendorPrefix.FIELDS) |field| { if (@field(prefix_value, field)) { var prefix: VendorPrefix = .{}; diff --git a/src/css/properties/transform.zig b/src/css/properties/transform.zig index bcc9ebce99..8a1c879798 100644 --- a/src/css/properties/transform.zig +++ b/src/css/properties/transform.zig @@ -77,9 +77,7 @@ pub const TransformList = struct { dest.allocator, scratchbuf, base_writer, - css.PrinterOptions{ - .minify = true, - }, + css.PrinterOptions.defaultWithMinify(true), dest.import_records, ); defer p.deinit(); diff --git a/src/css/rules/rules.zig b/src/css/rules/rules.zig index a66ebd6cd2..951a302c92 100644 --- a/src/css/rules/rules.zig +++ b/src/css/rules/rules.zig @@ -290,8 +290,6 @@ pub fn CssRuleList(comptime AtRule: type) type { // Attempt to merge the new rule with the last rule we added. var merged = false; - const ZACK_REMOVE_THIS = false; - _ = ZACK_REMOVE_THIS; // autofix if (rules.items.len > 0 and rules.items[rules.items.len - 1] == .style) { const last_style_rule = &rules.items[rules.items.len - 1].style; if (mergeStyleRules(AtRule, sty, last_style_rule, context)) { diff --git a/src/css/selectors/parser.zig b/src/css/selectors/parser.zig index c545c826b9..bcd01753cc 100644 --- a/src/css/selectors/parser.zig +++ b/src/css/selectors/parser.zig @@ -927,7 +927,7 @@ pub const PseudoClass = union(enum) { const writer = s.writer(dest.allocator); const W2 = @TypeOf(writer); const scratchbuf = std.ArrayList(u8).init(dest.allocator); - var printer = Printer(W2).new(dest.allocator, scratchbuf, writer, css.PrinterOptions{}, dest.import_records); + var printer = Printer(W2).new(dest.allocator, scratchbuf, writer, css.PrinterOptions.default(), dest.import_records); try serialize.serializePseudoClass(this, W2, &printer, null); return dest.writeStr(s.items); } @@ -1059,10 +1059,13 @@ pub const SelectorParser = struct { } /// Whether the given function name is an alias for the `:is()` function. - fn parseAnyPrefix(this: *const SelectorParser, name: []const u8) ?css.VendorPrefix { - _ = this; // autofix - _ = name; // autofix - return null; + fn parseAnyPrefix(_: *const SelectorParser, name: []const u8) ?css.VendorPrefix { + const Map = comptime bun.ComptimeStringMap(css.VendorPrefix, .{ + .{ "-webkit-any", css.VendorPrefix{ .webkit = true } }, + .{ "-moz-any", css.VendorPrefix{ .moz = true } }, + }); + + return Map.getAnyCase(name); } pub fn parseNonTsPseudoClass( @@ -1287,6 +1290,10 @@ pub const SelectorParser = struct { return .{ .result = pseudo_class }; } + pub fn parseHost(_: *SelectorParser) bool { + return true; + } + pub fn parseNonTsFunctionalPseudoClass( this: *SelectorParser, name: []const u8, @@ -1689,7 +1696,7 @@ pub fn GenericSelector(comptime Impl: type) type { var arraylist = ArrayList(u8){}; const w = arraylist.writer(bun.default_allocator); defer arraylist.deinit(bun.default_allocator); - var printer = css.Printer(@TypeOf(w)).new(bun.default_allocator, std.ArrayList(u8).init(bun.default_allocator), w, .{}, null); + var printer = css.Printer(@TypeOf(w)).new(bun.default_allocator, std.ArrayList(u8).init(bun.default_allocator), w, css.PrinterOptions.default(), null); defer printer.deinit(); css.selector.tocss_servo.toCss_Selector(this.this, @TypeOf(w), &printer) catch |e| return try writer.print("\n", .{@errorName(e)}); try writer.writeAll(arraylist.items); @@ -2544,7 +2551,7 @@ pub const PseudoElement = union(enum) { const writer = s.writer(dest.allocator); const W2 = @TypeOf(writer); const scratchbuf = std.ArrayList(u8).init(dest.allocator); - var printer = Printer(W2).new(dest.allocator, scratchbuf, writer, css.PrinterOptions{}, dest.import_records); + var printer = Printer(W2).new(dest.allocator, scratchbuf, writer, css.PrinterOptions.default(), dest.import_records); try serialize.serializePseudoElement(this, W2, &printer, null); return dest.writeStr(s.items); } @@ -2689,6 +2696,7 @@ pub fn parse_one_simple_selector( const S = SimpleSelectorParseResult(Impl); const start = input.state(); + const token_location = input.currentSourceLocation(); const token = switch (input.nextIncludingWhitespace()) { .result => |v| v.*, .err => { @@ -2700,7 +2708,7 @@ pub fn parse_one_simple_selector( switch (token) { .idhash => |id| { if (state.intersects(SelectorParsingState.AFTER_PSEUDO)) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; + return .{ .err = token_location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unexpected_selector_after_pseudo_element = .{ .idhash = id } })) }; } const component: GenericComponent(Impl) = .{ .id = .{ .v = id } }; return .{ .result = S{ @@ -2709,18 +2717,20 @@ pub fn parse_one_simple_selector( }, .open_square => { if (state.intersects(SelectorParsingState.AFTER_PSEUDO)) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; + return .{ .err = token_location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unexpected_selector_after_pseudo_element = .open_square })) }; } const Closure = struct { parser: *SelectorParser, - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(GenericComponent(Impl)) { - return parse_attribute_selector(Impl, this.parser, input2); - } }; var closure = Closure{ .parser = parser, }; - const attr = switch (input.parseNestedBlock(GenericComponent(Impl), &closure, Closure.parsefn)) { + const attr = switch (input.parseNestedBlock(GenericComponent(Impl), &closure, struct { + pub fn parsefn(this: *Closure, input2: *css.Parser) Result(GenericComponent(Impl)) { + return parse_attribute_selector(Impl, this.parser, input2); + } + } + .parsefn)) { .err => |e| return .{ .err = e }, .result => |v| v, }; @@ -2878,7 +2888,7 @@ pub fn parse_one_simple_selector( switch (d) { '.' => { if (state.intersects(SelectorParsingState.AFTER_PSEUDO)) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; + return .{ .err = token_location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unexpected_selector_after_pseudo_element = .{ .delim = '.' } })) }; } const location = input.currentSourceLocation(); const class = switch ((switch (input.nextIncludingWhitespace()) { @@ -3167,6 +3177,9 @@ pub fn parse_functional_pseudo_class( return .{ .result = .{ .non_ts_pseudo_class = result } }; } +const TreeStructuralPseudoClass = enum { @"first-child", @"last-child", @"only-child", root, empty, scope, host, @"first-of-type", @"last-of-type", @"only-of-type" }; +const TreeStructuralPseudoClassMap = bun.ComptimeEnumMap(TreeStructuralPseudoClass); + pub fn parse_simple_pseudo_class( comptime Impl: type, parser: *SelectorParser, @@ -3179,28 +3192,20 @@ pub fn parse_simple_pseudo_class( } if (state.allowsTreeStructuralPseudoClasses()) { - // css.todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "first-child")) { - return .{ .result = .{ .nth = NthSelectorData.first(false) } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "last-child")) { - return .{ .result = .{ .nth = NthSelectorData.last(false) } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "only-child")) { - return .{ .result = .{ .nth = NthSelectorData.only(false) } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "root")) { - return .{ .result = .root }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "empty")) { - return .{ .result = .empty }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "scope")) { - return .{ .result = .scope }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "host")) { - return .{ .result = .{ .host = null } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "first-of-type")) { - return .{ .result = .{ .nth = NthSelectorData.first(true) } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "last-of-type")) { - return .{ .result = .{ .nth = NthSelectorData.last(true) } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "only-of-type")) { - return .{ .result = .{ .nth = NthSelectorData.only(true) } }; - } else {} + if (TreeStructuralPseudoClassMap.getAnyCase(name)) |pseudo_class| { + switch (pseudo_class) { + .@"first-child" => return .{ .result = .{ .nth = NthSelectorData.first(false) } }, + .@"last-child" => return .{ .result = .{ .nth = NthSelectorData.last(false) } }, + .@"only-child" => return .{ .result = .{ .nth = NthSelectorData.only(false) } }, + .root => return .{ .result = .root }, + .empty => return .{ .result = .empty }, + .scope => return .{ .result = .scope }, + .host => if (parser.parseHost()) return .{ .result = .{ .host = null } }, + .@"first-of-type" => return .{ .result = .{ .nth = NthSelectorData.first(true) } }, + .@"last-of-type" => return .{ .result = .{ .nth = NthSelectorData.last(true) } }, + .@"only-of-type" => return .{ .result = .{ .nth = NthSelectorData.only(true) } }, + } + } } // The view-transition pseudo elements accept the :only-child pseudo class. diff --git a/src/css/selectors/selector.zig b/src/css/selectors/selector.zig index 84364080ae..6388630930 100644 --- a/src/css/selectors/selector.zig +++ b/src/css/selectors/selector.zig @@ -708,7 +708,7 @@ pub const serialize = struct { const writer = id.writer(); css.serializer.serializeIdentifier(v.value, writer) catch return dest.addFmtError(); - const s = try css.to_css.string(dest.allocator, CSSString, &v.value, css.PrinterOptions{}, dest.import_records); + const s = try css.to_css.string(dest.allocator, CSSString, &v.value, css.PrinterOptions.default(), dest.import_records); if (id.items.len > 0 and id.items.len < s.len) { try dest.writeStr(id.items); @@ -748,7 +748,7 @@ pub const serialize = struct { try dest.writeStr(":not("); }, .any => |v| { - const vp = dest.vendor_prefix.bitwiseOr(v.vendor_prefix); + const vp = dest.vendor_prefix._or(v.vendor_prefix); if (vp.intersects(css.VendorPrefix{ .webkit = true, .moz = true })) { try dest.writeChar(':'); try vp.toCss(W, dest); @@ -1039,6 +1039,7 @@ pub const serialize = struct { // If the printer has a vendor prefix override, use that. const vp = if (!d.vendor_prefix.isEmpty()) d.vendor_prefix.bitwiseAnd(prefix).orNone() else prefix; try vp.toCss(W, d); + debug("VENDOR PREFIX {d} OVERRIDE {d}", .{ vp.asBits(), d.vendor_prefix.asBits() }); return vp; } diff --git a/src/css/targets.zig b/src/css/targets.zig index ab720f8304..29b63d02ed 100644 --- a/src/css/targets.zig +++ b/src/css/targets.zig @@ -17,6 +17,27 @@ pub const Targets = struct { /// Features that should never be compiled, even when unsupported by targets. exclude: Features = .{}, + /// Set a sane default for bundler + pub fn browserDefault() Targets { + return .{ + .browsers = Browsers.browserDefault, + }; + } + + /// Set a sane default for bundler + pub fn runtimeDefault() Targets { + return .{ + .browsers = null, + }; + } + + pub fn forBundlerTarget(target: bun.bundler.options.Target) Targets { + return switch (target) { + .node, .bun => runtimeDefault(), + .browser, .bun_macro, .bake_server_components_ssr => browserDefault(), + }; + } + pub fn prefixes(this: *const Targets, prefix: css.VendorPrefix, feature: css.prefixes.Feature) css.VendorPrefix { if (prefix.contains(css.VendorPrefix{ .none = true }) and !this.exclude.contains(css.targets.Features{ .vendor_prefixes = true })) { if (this.include.contains(css.targets.Features{ .vendor_prefixes = true })) { @@ -125,8 +146,155 @@ pub const Features = packed struct(u32) { }; pub fn BrowsersImpl(comptime T: type) type { - _ = T; // autofix - return struct {}; + return struct { + pub const browserDefault = convertFromString(&.{ + "es2020", // support import.meta.url + "edge88", + "firefox78", + "chrome87", + "safari14", + }) catch |e| std.debug.panic("WOOPSIE: {s}\n", .{@errorName(e)}); + + // pub const bundlerDefault = T{ + // .chrome = 80 << 16, + // .edge = 80 << 16, + // .firefox = 78 << 16, + // .safari = 14 << 16, + // .opera = 67 << 16, + // }; + + pub fn convertFromString(esbuild_target: []const []const u8) anyerror!T { + var browsers: T = .{}; + + for (esbuild_target) |str| { + var entries_buf: [5][]const u8 = undefined; + const entries_without_es: [][]const u8 = entries_without_es: { + if (str.len <= 2 or !(str[0] == 'e' and str[1] == 's')) { + entries_buf[0] = str; + break :entries_without_es entries_buf[0..1]; + } + + const number_part = str[2..]; + const year = try std.fmt.parseInt(u16, number_part, 10); + switch (year) { + // https://caniuse.com/?search=es2015 + 2015 => { + entries_buf[0..5].* = .{ "chrome49", "edge13", "safari10", "firefox44", "opera36" }; + break :entries_without_es entries_buf[0..5]; + }, + // https://caniuse.com/?search=es2016 + 2016 => { + entries_buf[0..5].* = .{ "chrome50", "edge13", "safari10", "firefox43", "opera37" }; + break :entries_without_es entries_buf[0..5]; + }, + // https://caniuse.com/?search=es2017 + 2017 => { + entries_buf[0..5].* = .{ "chrome58", "edge15", "safari11", "firefox52", "opera45" }; + break :entries_without_es entries_buf[0..5]; + }, + // https://caniuse.com/?search=es2018 + 2018 => { + entries_buf[0..5].* = .{ "chrome63", "edge79", "safari12", "firefox58", "opera50" }; + break :entries_without_es entries_buf[0..5]; + }, + // https://caniuse.com/?search=es2019 + 2019 => { + entries_buf[0..5].* = .{ "chrome73", "edge79", "safari12.1", "firefox64", "opera60" }; + break :entries_without_es entries_buf[0..5]; + }, + // https://caniuse.com/?search=es2020 + 2020 => { + entries_buf[0..5].* = .{ "chrome80", "edge80", "safari14.1", "firefox80", "opera67" }; + break :entries_without_es entries_buf[0..5]; + }, + // https://caniuse.com/?search=es2021 + 2021 => { + entries_buf[0..5].* = .{ "chrome85", "edge85", "safari14.1", "firefox80", "opera71" }; + break :entries_without_es entries_buf[0..5]; + }, + // https://caniuse.com/?search=es2022 + 2022 => { + entries_buf[0..5].* = .{ "chrome94", "edge94", "safari16.4", "firefox93", "opera80" }; + break :entries_without_es entries_buf[0..5]; + }, + // https://caniuse.com/?search=es2023 + 2023 => { + entries_buf[0..4].* = .{ "chrome110", "edge110", "safari16.4", "opera96" }; + break :entries_without_es entries_buf[0..4]; + }, + else => { + if (@inComptime()) { + @compileLog("Invalid target: " ++ str); + } + return error.UnsupportedCSSTarget; + }, + } + }; + + for_loop: for (entries_without_es) |entry| { + if (bun.strings.eql(entry, "esnext")) continue; + const maybe_idx: ?usize = maybe_idx: { + for (entry, 0..) |c, i| { + if (std.ascii.isDigit(c)) break :maybe_idx i; + } + break :maybe_idx null; + }; + + if (maybe_idx) |idx| { + const Browser = enum { + chrome, + edge, + firefox, + ie, + ios_saf, + opera, + safari, + no_mapping, + }; + const Map = bun.ComptimeStringMap(Browser, .{ + .{ "chrome", Browser.chrome }, + .{ "edge", Browser.edge }, + .{ "firefox", Browser.firefox }, + .{ "hermes", Browser.no_mapping }, + .{ "ie", Browser.ie }, + .{ "ios", Browser.ios_saf }, + .{ "node", Browser.no_mapping }, + .{ "opera", Browser.opera }, + .{ "rhino", Browser.no_mapping }, + .{ "safari", Browser.safari }, + }); + const browser = Map.get(entry[0..idx]); + if (browser == null or browser.? == .no_mapping) continue; // No mapping available + + const major, const minor = major_minor: { + const version_str = entry[idx..]; + const dot_index = std.mem.indexOfScalar(u8, version_str, '.') orelse version_str.len; + const major = std.fmt.parseInt(u16, version_str[0..dot_index], 10) catch continue; + const minor = if (dot_index < version_str.len) + std.fmt.parseInt(u16, version_str[dot_index + 1 ..], 10) catch 0 + else + 0; + break :major_minor .{ major, minor }; + }; + + const version: u32 = (@as(u32, major) << 16) | @as(u32, minor << 8); + switch (browser.?) { + inline else => |browser_name| { + if (@field(browsers, @tagName(browser_name)) == null or + version < @field(browsers, @tagName(browser_name)).?) + { + @field(browsers, @tagName(browser_name)) = version; + } + continue :for_loop; + }, + } + } + } + } + + return browsers; + } + }; } pub fn FeaturesImpl(comptime T: type) type { diff --git a/src/css/values/color_js.zig b/src/css/values/color_js.zig index 052d92ed70..d1dd0f6abc 100644 --- a/src/css/values/color_js.zig +++ b/src/css/values/color_js.zig @@ -426,7 +426,7 @@ pub fn jsFunctionColor(globalThis: *JSC.JSGlobalObject, callFrame: *JSC.CallFram allocator, std.ArrayList(u8).init(allocator), writer, - .{}, + css.PrinterOptions.default(), null, ); diff --git a/test/bundler/esbuild/css.test.ts b/test/bundler/esbuild/css.test.ts index 2666a81c42..db04947753 100644 --- a/test/bundler/esbuild/css.test.ts +++ b/test/bundler/esbuild/css.test.ts @@ -41,6 +41,7 @@ body { itBundled("css/CSSNesting", { experimentalCss: true, + target: "bun", files: { "/entry.css": /* css */ ` body { diff --git a/test/js/bun/css/css.test.ts b/test/js/bun/css/css.test.ts index da634ba716..2e4405893a 100644 --- a/test/js/bun/css/css.test.ts +++ b/test/js/bun/css/css.test.ts @@ -8,7 +8,37 @@ import path from "path"; import { attrTest, cssTest, indoc, minify_test, minifyTest, prefix_test } from "./util"; describe("css tests", () => { - test("edge case", () => { + describe("pseudo-class edge case", () => { + cssTest( + indoc`[type="file"]::file-selector-button:-moz-any() { + --pico-background-color: var(--pico-primary-hover-background); + --pico-border-color: var(--pico-primary-hover-border); + --pico-box-shadow: var(--pico-button-hover-box-shadow, 0 0 0 #0000); + --pico-color: var(--pico-primary-inverse); + }`, + indoc`[type="file"]::-webkit-file-upload-button:-webkit-any() { + --pico-background-color: var(--pico-primary-hover-background); + --pico-border-color: var(--pico-primary-hover-border); + --pico-box-shadow: var(--pico-button-hover-box-shadow, 0 0 0 #0000); + --pico-color: var(--pico-primary-inverse); + } + [type="file"]::file-selector-button:is() { + --pico-background-color: var(--pico-primary-hover-background); + --pico-border-color: var(--pico-primary-hover-border); + --pico-box-shadow: var(--pico-button-hover-box-shadow, 0 0 0 #0000); + --pico-color: var(--pico-primary-inverse); + }`, + { + chrome: 80 << 16, + edge: 80 << 16, + firefox: 78 << 16, + safari: 14 << 16, + opera: 67 << 16, + }, + ); + }); + + test("calc edge case", () => { minifyTest( // Problem: the value is being printed as Infinity in our restrict_prec thing but the internal thing actually wants it as 3.40282e38px `.rounded-full { diff --git a/test/js/bun/css/doesnt_crash.test.ts b/test/js/bun/css/doesnt_crash.test.ts index 8cca195bb6..c7cdad5947 100644 --- a/test/js/bun/css/doesnt_crash.test.ts +++ b/test/js/bun/css/doesnt_crash.test.ts @@ -19,7 +19,14 @@ describe("doesnt_crash", async () => { absolute = absolute.replaceAll("\\", "/"); const file = path.basename(absolute); - for (let minify of [false, true]) { + const configs: { target: string; minify: boolean }[] = [ + { target: "bun", minify: false }, + { target: "bun", minify: true }, + { target: "browser", minify: false }, + { target: "browser", minify: true }, + ]; + + for (const { target, minify } of configs) { test(`${file} - ${minify ? "minify" : "not minify"}`, async () => { const timeLog = `Transpiled ${file} - ${minify ? "minify" : "not minify"}`; console.time(timeLog); @@ -27,6 +34,7 @@ describe("doesnt_crash", async () => { entrypoints: [absolute], experimentalCss: true, minify: minify, + target, }); console.timeEnd(timeLog); @@ -42,9 +50,11 @@ describe("doesnt_crash", async () => { { const timeLog = `Re-transpiled ${file} - ${minify ? "minify" : "not minify"}`; console.time(timeLog); + console.log(" Transpiled file path:", outfile1); const { logs, outputs } = await Bun.build({ entrypoints: [outfile1], experimentalCss: true, + target, minify: minify, }); diff --git a/test/js/bun/css/util.ts b/test/js/bun/css/util.ts index 09b4701739..0ec5da219c 100644 --- a/test/js/bun/css/util.ts +++ b/test/js/bun/css/util.ts @@ -30,12 +30,14 @@ export function prefix_test(source: string, expected: string, targets: Browsers) }); } -export function css_test(source: string, expected: string) { - return cssTest(source, expected); +export function css_test(source: string, expected: string, browsers?: Browsers) { + return cssTest(source, expected, browsers); } -export function cssTest(source: string, expected: string) { +export function cssTest(source: string, expected: string, browsers?: Browsers) { test(source, () => { - expect(testWithOptions(source, expected)).toEqualIgnoringWhitespace(expected); + const output = testWithOptions(source, expected, browsers); + console.log("Output", output); + expect(output).toEqualIgnoringWhitespace(expected); }); } From aada6f930fbd41d355168f8590c32bcb7a5b833f Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 16 Dec 2024 20:16:23 -0800 Subject: [PATCH 028/125] Fix heap snapshots memory usage stats. Introduce `estimateDirectMemoryUsageOf` function in `"bun:jsc"` (#15790) --- docs/api/utils.md | 25 ++ packages/bun-types/bun.d.ts | 2 + packages/bun-types/jsc.d.ts | 12 + packages/bun-uws/src/WebSocket.h | 4 + src/bun.js/api/BunObject.classes.ts | 1 + src/bun.js/api/bun/process.zig | 4 + src/bun.js/api/bun/socket.zig | 4 + src/bun.js/api/bun/subprocess.zig | 43 +++ src/bun.js/api/server.classes.ts | 1 + src/bun.js/api/server.zig | 35 +++ src/bun.js/api/sockets.classes.ts | 1 + src/bun.js/api/streams.classes.ts | 1 + src/bun.js/bindings/CommonJSModuleRecord.cpp | 20 +- src/bun.js/bindings/CommonJSModuleRecord.h | 2 + src/bun.js/bindings/DOMFormData.cpp | 15 ++ src/bun.js/bindings/DOMFormData.h | 1 + src/bun.js/bindings/DOMURL.h | 5 + src/bun.js/bindings/URLSearchParams.cpp | 9 + src/bun.js/bindings/URLSearchParams.h | 1 + src/bun.js/bindings/blob.cpp | 5 + src/bun.js/bindings/blob.h | 2 + src/bun.js/bindings/headers.h | 7 +- src/bun.js/bindings/webcore/AbortSignal.cpp | 5 + src/bun.js/bindings/webcore/AbortSignal.h | 2 + src/bun.js/bindings/webcore/JSAbortSignal.cpp | 7 + src/bun.js/bindings/webcore/JSAbortSignal.h | 2 + src/bun.js/bindings/webcore/JSDOMFormData.cpp | 7 + src/bun.js/bindings/webcore/JSDOMFormData.h | 1 + src/bun.js/bindings/webcore/JSDOMURL.cpp | 7 + src/bun.js/bindings/webcore/JSDOMURL.h | 2 + .../bindings/webcore/JSFetchHeaders.cpp | 13 +- src/bun.js/bindings/webcore/JSFetchHeaders.h | 1 + .../bindings/webcore/JSURLSearchParams.cpp | 8 + .../bindings/webcore/JSURLSearchParams.h | 1 + src/bun.js/bindings/webcore/JSWebSocket.cpp | 6 + src/bun.js/bindings/webcore/JSWebSocket.h | 1 + src/bun.js/bindings/webcore/WebSocket.cpp | 25 ++ src/bun.js/bindings/webcore/WebSocket.h | 2 + src/bun.js/modules/BunJSCModule.h | 23 +- src/bun.js/webcore/blob.zig | 20 ++ src/bun.js/webcore/body.zig | 10 + src/bun.js/webcore/request.zig | 4 + src/bun.js/webcore/response.classes.ts | 1 + src/bun.js/webcore/streams.zig | 59 +++++ src/codegen/class-definitions.ts | 15 ++ src/codegen/generate-classes.ts | 66 ++++- src/codegen/generate-jssink.ts | 37 ++- src/deps/libuwsockets.cpp | 163 ++++++------ src/deps/uws.zig | 20 +- src/http/websocket_http_client.zig | 21 ++ src/io/PipeReader.zig | 8 + src/io/PipeWriter.zig | 20 ++ src/string.zig | 4 + test/js/bun/util/heap-snapshot.test.ts | 187 ++++++++++++++ test/js/bun/util/heap.ts | 244 ++++++++++++++++++ 55 files changed, 1093 insertions(+), 99 deletions(-) create mode 100644 test/js/bun/util/heap-snapshot.test.ts create mode 100644 test/js/bun/util/heap.ts diff --git a/docs/api/utils.md b/docs/api/utils.md index 3b87922106..c7743c2d43 100644 --- a/docs/api/utils.md +++ b/docs/api/utils.md @@ -771,3 +771,28 @@ console.log(obj); // => { foo: "bar" } ``` Internally, [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) and [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) serialize and deserialize the same way. This exposes the underlying [HTML Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) to JavaScript as an ArrayBuffer. + +## `estimateDirectMemoryUsageOf` in `bun:jsc` + +The `estimateDirectMemoryUsageOf` function returns a best-effort estimate of the memory usage of an object in bytes, excluding the memory usage of properties or other objects it references. For accurate per-object memory usage, use `Bun.generateHeapSnapshot`. + +```js +import { estimateDirectMemoryUsageOf } from "bun:jsc"; + +const obj = { foo: "bar" }; +const usage = estimateDirectMemoryUsageOf(obj); +console.log(usage); // => 16 + +const buffer = Buffer.alloc(1024 * 1024); +estimateDirectMemoryUsageOf(buffer); +// => 1048624 + +const req = new Request("https://bun.sh"); +estimateDirectMemoryUsageOf(req); +// => 167 + +const array = Array(1024).fill({ a: 1 }); +// Arrays are usually not stored contiguously in memory, so this will not return a useful value (which isn't a bug). +estimateDirectMemoryUsageOf(array); +// => 16 +``` diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index dbe0295d11..c077e3b6f0 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -2151,6 +2151,8 @@ declare module "bun" { * }); */ data: T; + + getBufferedAmount(): number; } /** diff --git a/packages/bun-types/jsc.d.ts b/packages/bun-types/jsc.d.ts index 01bf6b46ff..1f61a49d81 100644 --- a/packages/bun-types/jsc.d.ts +++ b/packages/bun-types/jsc.d.ts @@ -214,4 +214,16 @@ declare module "bun:jsc" { * Run JavaScriptCore's sampling profiler */ function startSamplingProfiler(optionalDirectory?: string): void; + + /** + * Non-recursively estimate the memory usage of an object, excluding the memory usage of + * properties or other objects it references. For more accurate per-object + * memory usage, use {@link Bun.generateHeapSnapshot}. + * + * This is a best-effort estimate. It may not be 100% accurate. When it's + * wrong, it may mean the memory is non-contiguous (such as a large array). + * + * Passing a primitive type that isn't heap allocated returns 0. + */ + function estimateDirectMemoryUsageOf(value: object | CallableFunction | bigint | symbol | string): number; } diff --git a/packages/bun-uws/src/WebSocket.h b/packages/bun-uws/src/WebSocket.h index ee17fb8225..3f48b91271 100644 --- a/packages/bun-uws/src/WebSocket.h +++ b/packages/bun-uws/src/WebSocket.h @@ -73,6 +73,10 @@ public: DROPPED }; + size_t memoryCost() { + return getBufferedAmount() + sizeof(WebSocket); + } + /* Sending fragmented messages puts a bit of effort on the user; you must not interleave regular sends * with fragmented sends and you must sendFirstFragment, [sendFragment], then finally sendLastFragment. */ SendStatus sendFirstFragment(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false) { diff --git a/src/bun.js/api/BunObject.classes.ts b/src/bun.js/api/BunObject.classes.ts index 79cb755e8a..6d3e289f82 100644 --- a/src/bun.js/api/BunObject.classes.ts +++ b/src/bun.js/api/BunObject.classes.ts @@ -48,6 +48,7 @@ export default [ finalize: true, hasPendingActivity: true, configurable: false, + memoryCost: true, klass: {}, JSType: "0b11101110", proto: { diff --git a/src/bun.js/api/bun/process.zig b/src/bun.js/api/bun/process.zig index 036a12b800..0c353110da 100644 --- a/src/bun.js/api/bun/process.zig +++ b/src/bun.js/api/bun/process.zig @@ -153,6 +153,10 @@ pub const Process = struct { sync: bool = false, event_loop: JSC.EventLoopHandle, + pub fn memoryCost(_: *const Process) usize { + return @sizeOf(@This()); + } + pub usingnamespace bun.NewRefCounted(Process, deinit); pub fn setExitHandler(this: *Process, handler: anytype) void { diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index 08007ae75b..9971f84d16 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -1394,6 +1394,10 @@ fn NewSocket(comptime ssl: bool) type { return this.has_pending_activity.load(.acquire); } + pub fn memoryCost(this: *This) usize { + return @sizeOf(This) + this.buffered_data_for_node_net.cap; + } + pub fn attachNativeCallback(this: *This, callback: NativeCallbacks) bool { if (this.native_callback != .none) return false; this.native_callback = callback; diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 9dfceca67a..3872f0436d 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -395,6 +395,14 @@ pub const Subprocess = struct { closed: void, buffer: []u8, + pub fn memoryCost(this: *const Readable) usize { + return switch (this.*) { + .pipe => @sizeOf(PipeReader) + this.pipe.memoryCost(), + .buffer => this.buffer.len, + else => 0, + }; + } + pub fn hasPendingActivity(this: *const Readable) bool { return switch (this.*) { .pipe => this.pipe.hasPendingActivity(), @@ -794,6 +802,16 @@ pub const Subprocess = struct { array_buffer: JSC.ArrayBuffer.Strong, detached: void, + pub fn memoryCost(this: *const Source) usize { + // Memory cost of Source and each of the particular fields is covered by @sizeOf(Subprocess). + return switch (this.*) { + .blob => this.blob.memoryCost(), + // ArrayBuffer is owned by GC. + .array_buffer => 0, + .detached => 0, + }; + } + pub fn slice(this: *const Source) []const u8 { return switch (this.*) { .blob => this.blob.slice(), @@ -921,6 +939,10 @@ pub const Subprocess = struct { this.destroy(); } + pub fn memoryCost(this: *const This) usize { + return @sizeOf(@This()) + this.source.memoryCost() + this.writer.memoryCost(); + } + pub fn loop(this: *This) *uws.Loop { return this.event_loop.loop(); } @@ -954,6 +976,10 @@ pub const Subprocess = struct { pub usingnamespace bun.NewRefCounted(PipeReader, PipeReader.deinit); + pub fn memoryCost(this: *const PipeReader) usize { + return this.reader.memoryCost(); + } + pub fn hasPendingActivity(this: *const PipeReader) bool { if (this.state == .pending) return true; @@ -1141,6 +1167,15 @@ pub const Subprocess = struct { inherit: void, ignore: void, + pub fn memoryCost(this: *const Writable) usize { + return switch (this.*) { + .pipe => |pipe| pipe.memoryCost(), + .buffer => |buffer| buffer.memoryCost(), + // TODO: memfd + else => 0, + }; + } + pub fn hasPendingActivity(this: *const Writable) bool { return switch (this.*) { .pipe => false, @@ -1415,6 +1450,14 @@ pub const Subprocess = struct { } }; + pub fn memoryCost(this: *const Subprocess) usize { + return @sizeOf(@This()) + + this.process.memoryCost() + + this.stdin.memoryCost() + + this.stdout.memoryCost() + + this.stderr.memoryCost(); + } + pub fn onProcessExit(this: *Subprocess, process: *Process, status: bun.spawn.Status, rusage: *const Rusage) void { log("onProcessExit()", .{}); const this_jsvalue = this.this_jsvalue; diff --git a/src/bun.js/api/server.classes.ts b/src/bun.js/api/server.classes.ts index 9182fa809e..6b9f205693 100644 --- a/src/bun.js/api/server.classes.ts +++ b/src/bun.js/api/server.classes.ts @@ -93,6 +93,7 @@ export default [ define({ name: "ServerWebSocket", JSType: "0b11101110", + memoryCost: true, proto: { send: { fn: "send", diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 5a37980083..8c968ec319 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -1686,6 +1686,29 @@ pub const AnyRequestContext = struct { pub fn init(request_ctx: anytype) AnyRequestContext { return .{ .tagged_pointer = Pointer.init(request_ctx) }; } + + pub fn memoryCost(self: AnyRequestContext) usize { + if (self.tagged_pointer.isNull()) { + return 0; + } + + switch (self.tagged_pointer.tag()) { + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(HTTPServer.RequestContext))) => { + return self.tagged_pointer.as(HTTPServer.RequestContext).memoryCost(); + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(HTTPSServer.RequestContext))) => { + return self.tagged_pointer.as(HTTPSServer.RequestContext).memoryCost(); + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(DebugHTTPServer.RequestContext))) => { + return self.tagged_pointer.as(DebugHTTPServer.RequestContext).memoryCost(); + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(DebugHTTPSServer.RequestContext))) => { + return self.tagged_pointer.as(DebugHTTPSServer.RequestContext).memoryCost(); + }, + else => @panic("Unexpected AnyRequestContext tag"), + } + } + pub fn get(self: AnyRequestContext, comptime T: type) ?*T { return self.tagged_pointer.get(T); } @@ -1909,6 +1932,11 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp // TODO: support builtin compression const can_sendfile = !ssl_enabled and !Environment.isWindows; + pub fn memoryCost(this: *const RequestContext) usize { + // The Sink and ByteStream aren't owned by this. + return @sizeOf(RequestContext) + this.request_body_buf.capacity + this.response_buf_owned.capacity + this.blob.memoryCost(); + } + pub inline fn isAsync(this: *const RequestContext) bool { return this.defer_deinit_until_callback_completes == null; } @@ -4464,6 +4492,13 @@ pub const ServerWebSocket = struct { pub usingnamespace JSC.Codegen.JSServerWebSocket; pub usingnamespace bun.New(ServerWebSocket); + pub fn memoryCost(this: *const ServerWebSocket) usize { + if (this.flags.closed) { + return @sizeOf(ServerWebSocket); + } + return this.websocket().memoryCost() + @sizeOf(ServerWebSocket); + } + const log = Output.scoped(.WebSocketServer, false); pub fn onOpen(this: *ServerWebSocket, ws: uws.AnyWebSocket) void { diff --git a/src/bun.js/api/sockets.classes.ts b/src/bun.js/api/sockets.classes.ts index 75cdc6b733..7d30de0344 100644 --- a/src/bun.js/api/sockets.classes.ts +++ b/src/bun.js/api/sockets.classes.ts @@ -7,6 +7,7 @@ function generate(ssl) { hasPendingActivity: true, noConstructor: true, configurable: false, + memoryCost: true, proto: { getAuthorizationError: { fn: "getAuthorizationError", diff --git a/src/bun.js/api/streams.classes.ts b/src/bun.js/api/streams.classes.ts index f4419c5db8..140ac646e6 100644 --- a/src/bun.js/api/streams.classes.ts +++ b/src/bun.js/api/streams.classes.ts @@ -7,6 +7,7 @@ function source(name) { noConstructor: true, finalize: true, configurable: false, + memoryCost: true, proto: { drain: { fn: "drainFromJS", diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index ac0f28d6f3..e1d7e0573b 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -727,6 +727,19 @@ JSCommonJSModule* JSCommonJSModule::create( return JSCommonJSModule::create(globalObject, requireMapKey, exportsObject, hasEvaluated, parent); } +size_t JSCommonJSModule::estimatedSize(JSC::JSCell* cell, JSC::VM& vm) +{ + auto* thisObject = jsCast(cell); + size_t additionalSize = 0; + if (!thisObject->sourceCode.isNull() && !thisObject->sourceCode.view().isEmpty()) { + additionalSize += thisObject->sourceCode.view().length(); + if (!thisObject->sourceCode.view().is8Bit()) { + additionalSize *= 2; + } + } + return Base::estimatedSize(cell, vm) + additionalSize; +} + void JSCommonJSModule::destroy(JSC::JSCell* cell) { static_cast(cell)->JSCommonJSModule::~JSCommonJSModule(); @@ -999,9 +1012,14 @@ void JSCommonJSModule::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) if (auto* id = thisObject->m_id.get()) { if (!id->isRope()) { auto label = id->tryGetValue(false); - analyzer.setLabelForCell(cell, label); + analyzer.setLabelForCell(cell, makeString("CommonJS Module: "_s, StringView(label))); + } else { + analyzer.setLabelForCell(cell, "CommonJS Module"_s); } + } else { + analyzer.setLabelForCell(cell, "CommonJS Module"_s); } + Base::analyzeHeap(cell, analyzer); } diff --git a/src/bun.js/bindings/CommonJSModuleRecord.h b/src/bun.js/bindings/CommonJSModuleRecord.h index 70721f0842..e663dd7460 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.h +++ b/src/bun.js/bindings/CommonJSModuleRecord.h @@ -56,6 +56,8 @@ public: bool ignoreESModuleAnnotation { false }; JSC::SourceCode sourceCode = JSC::SourceCode(); + static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm); + void setSourceCode(JSC::SourceCode&& sourceCode); static void destroy(JSC::JSCell*); diff --git a/src/bun.js/bindings/DOMFormData.cpp b/src/bun.js/bindings/DOMFormData.cpp index 456fe5da54..34cd431cb6 100644 --- a/src/bun.js/bindings/DOMFormData.cpp +++ b/src/bun.js/bindings/DOMFormData.cpp @@ -200,4 +200,19 @@ std::optional> DOMFormData return makeKeyValuePair(item.name, item.data); } +size_t DOMFormData::memoryCost() const +{ + size_t cost = m_items.sizeInBytes(); + for (auto& item : m_items) { + cost += item.name.sizeInBytes(); + if (auto value = std::get_if>(&item.data)) { + cost += value->get()->memoryCost(); + } else if (auto value = std::get_if(&item.data)) { + cost += value->sizeInBytes(); + } + } + + return cost; +} + } // namespace WebCore diff --git a/src/bun.js/bindings/DOMFormData.h b/src/bun.js/bindings/DOMFormData.h index 447be4e927..0f0c1518ce 100644 --- a/src/bun.js/bindings/DOMFormData.h +++ b/src/bun.js/bindings/DOMFormData.h @@ -74,6 +74,7 @@ public: Ref clone() const; size_t count() const { return m_items.size(); } + size_t memoryCost() const; String toURLEncodedString(); diff --git a/src/bun.js/bindings/DOMURL.h b/src/bun.js/bindings/DOMURL.h index e0aff84cbc..56db692140 100644 --- a/src/bun.js/bindings/DOMURL.h +++ b/src/bun.js/bindings/DOMURL.h @@ -61,6 +61,11 @@ public: static String createPublicURL(ScriptExecutionContext&, URLRegistrable&); + size_t memoryCost() const + { + return sizeof(DOMURL) + m_url.string().sizeInBytes(); + } + private: static ExceptionOr> create(const String& url, const URL& base); DOMURL(URL&& completeURL); diff --git a/src/bun.js/bindings/URLSearchParams.cpp b/src/bun.js/bindings/URLSearchParams.cpp index 21acb3662c..0b688b8be2 100644 --- a/src/bun.js/bindings/URLSearchParams.cpp +++ b/src/bun.js/bindings/URLSearchParams.cpp @@ -192,4 +192,13 @@ URLSearchParams::Iterator::Iterator(URLSearchParams& params) { } +size_t URLSearchParams::memoryCost() const +{ + size_t cost = sizeof(URLSearchParams); + for (const auto& pair : m_pairs) { + cost += pair.key.sizeInBytes(); + cost += pair.value.sizeInBytes(); + } + return cost; +} } diff --git a/src/bun.js/bindings/URLSearchParams.h b/src/bun.js/bindings/URLSearchParams.h index 65400d3672..a8744053e5 100644 --- a/src/bun.js/bindings/URLSearchParams.h +++ b/src/bun.js/bindings/URLSearchParams.h @@ -56,6 +56,7 @@ public: void updateFromAssociatedURL(); void sort(); size_t size() const { return m_pairs.size(); } + size_t memoryCost() const; class Iterator { public: diff --git a/src/bun.js/bindings/blob.cpp b/src/bun.js/bindings/blob.cpp index 85982f1b8b..2e650ae479 100644 --- a/src/bun.js/bindings/blob.cpp +++ b/src/bun.js/bindings/blob.cpp @@ -26,4 +26,9 @@ JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlo return JSC::JSValue::decode(encoded); } +size_t Blob::memoryCost() const +{ + return sizeof(Blob) + JSBlob::memoryCost(m_impl); +} + } diff --git a/src/bun.js/bindings/blob.h b/src/bun.js/bindings/blob.h index 1ddd851d1e..66eed55cb2 100644 --- a/src/bun.js/bindings/blob.h +++ b/src/bun.js/bindings/blob.h @@ -51,6 +51,8 @@ public: } void* m_impl; + size_t memoryCost() const; + private: Blob(void* impl, String fileName = String()) { diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index f3896c63ef..405c835e56 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -711,7 +711,7 @@ BUN_DECLARE_HOST_FUNCTION(FetchTaskletChunkedRequestSink__write); ZIG_DECL void Bun__WebSocketHTTPClient__cancel(WebSocketHTTPClient* arg0); ZIG_DECL WebSocketHTTPClient* Bun__WebSocketHTTPClient__connect(JSC__JSGlobalObject* arg0, void* arg1, CppWebSocket* arg2, const ZigString* arg3, uint16_t arg4, const ZigString* arg5, const ZigString* arg6, ZigString* arg7, ZigString* arg8, size_t arg9); ZIG_DECL void Bun__WebSocketHTTPClient__register(JSC__JSGlobalObject* arg0, void* arg1, void* arg2); - +ZIG_DECL size_t Bun__WebSocketHTTPClient__memoryCost(WebSocketHTTPClient* arg0); #endif #ifdef __cplusplus @@ -719,7 +719,7 @@ ZIG_DECL void Bun__WebSocketHTTPClient__register(JSC__JSGlobalObject* arg0, void ZIG_DECL void Bun__WebSocketHTTPSClient__cancel(WebSocketHTTPSClient* arg0); ZIG_DECL WebSocketHTTPSClient* Bun__WebSocketHTTPSClient__connect(JSC__JSGlobalObject* arg0, void* arg1, CppWebSocket* arg2, const ZigString* arg3, uint16_t arg4, const ZigString* arg5, const ZigString* arg6, ZigString* arg7, ZigString* arg8, size_t arg9); ZIG_DECL void Bun__WebSocketHTTPSClient__register(JSC__JSGlobalObject* arg0, void* arg1, void* arg2); - +ZIG_DECL size_t Bun__WebSocketHTTPSClient__memoryCost(WebSocketHTTPSClient* arg0); #endif #ifdef __cplusplus @@ -731,6 +731,7 @@ ZIG_DECL void* Bun__WebSocketClient__init(CppWebSocket* arg0, void* arg1, void* ZIG_DECL void Bun__WebSocketClient__register(JSC__JSGlobalObject* arg0, void* arg1, void* arg2); ZIG_DECL void Bun__WebSocketClient__writeBinaryData(WebSocketClient* arg0, const unsigned char* arg1, size_t arg2, unsigned char arg3); ZIG_DECL void Bun__WebSocketClient__writeString(WebSocketClient* arg0, const ZigString* arg1, unsigned char arg2); +ZIG_DECL size_t Bun__WebSocketClient__memoryCost(WebSocketClient* arg0); #endif @@ -743,7 +744,7 @@ ZIG_DECL void* Bun__WebSocketClientTLS__init(CppWebSocket* arg0, void* arg1, voi ZIG_DECL void Bun__WebSocketClientTLS__register(JSC__JSGlobalObject* arg0, void* arg1, void* arg2); ZIG_DECL void Bun__WebSocketClientTLS__writeBinaryData(WebSocketClientTLS* arg0, const unsigned char* arg1, size_t arg2, unsigned char arg3); ZIG_DECL void Bun__WebSocketClientTLS__writeString(WebSocketClientTLS* arg0, const ZigString* arg1, unsigned char arg2); - +ZIG_DECL size_t Bun__WebSocketClientTLS__memoryCost(WebSocketClientTLS* arg0); #endif #ifdef __cplusplus diff --git a/src/bun.js/bindings/webcore/AbortSignal.cpp b/src/bun.js/bindings/webcore/AbortSignal.cpp index b279d8d451..7d22ef7a9b 100644 --- a/src/bun.js/bindings/webcore/AbortSignal.cpp +++ b/src/bun.js/bindings/webcore/AbortSignal.cpp @@ -266,4 +266,9 @@ WebCoreOpaqueRoot root(AbortSignal* signal) return WebCoreOpaqueRoot { signal }; } +size_t AbortSignal::memoryCost() const +{ + return sizeof(AbortSignal) + m_native_callbacks.sizeInBytes() + m_algorithms.sizeInBytes() + m_sourceSignals.capacity() + m_dependentSignals.capacity(); +} + } // namespace WebCore diff --git a/src/bun.js/bindings/webcore/AbortSignal.h b/src/bun.js/bindings/webcore/AbortSignal.h index b603145ce3..92cd30f4fd 100644 --- a/src/bun.js/bindings/webcore/AbortSignal.h +++ b/src/bun.js/bindings/webcore/AbortSignal.h @@ -108,6 +108,8 @@ public: bool hasPendingActivity() const { return pendingActivityCount > 0; } bool isDependent() const { return m_isDependent; } + size_t memoryCost() const; + private: enum class Aborted : bool { No, diff --git a/src/bun.js/bindings/webcore/JSAbortSignal.cpp b/src/bun.js/bindings/webcore/JSAbortSignal.cpp index bc3f2e3426..a8f0031096 100644 --- a/src/bun.js/bindings/webcore/JSAbortSignal.cpp +++ b/src/bun.js/bindings/webcore/JSAbortSignal.cpp @@ -339,6 +339,13 @@ JSC_DEFINE_HOST_FUNCTION(jsAbortSignalPrototypeFunction_throwIfAborted, (JSGloba return IDLOperation::call(*lexicalGlobalObject, *callFrame, "throwIfAborted"); } +size_t JSAbortSignal::estimatedSize(JSC::JSCell* cell, JSC::VM& vm) +{ + auto* thisObject = jsCast(cell); + auto& wrapped = thisObject->wrapped(); + return Base::estimatedSize(cell, vm) + wrapped.memoryCost(); +} + JSC::GCClient::IsoSubspace* JSAbortSignal::subspaceForImpl(JSC::VM& vm) { return WebCore::subspaceForImpl( diff --git a/src/bun.js/bindings/webcore/JSAbortSignal.h b/src/bun.js/bindings/webcore/JSAbortSignal.h index d52af70bb0..5b0600a22f 100644 --- a/src/bun.js/bindings/webcore/JSAbortSignal.h +++ b/src/bun.js/bindings/webcore/JSAbortSignal.h @@ -43,6 +43,8 @@ public: static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); static AbortSignal* toWrapped(JSC::VM&, JSC::JSValue); + static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm); + DECLARE_INFO; static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) diff --git a/src/bun.js/bindings/webcore/JSDOMFormData.cpp b/src/bun.js/bindings/webcore/JSDOMFormData.cpp index 3a1ecab66f..92bb50c8cf 100644 --- a/src/bun.js/bindings/webcore/JSDOMFormData.cpp +++ b/src/bun.js/bindings/webcore/JSDOMFormData.cpp @@ -760,4 +760,11 @@ DOMFormData* JSDOMFormData::toWrapped(JSC::VM&, JSC::JSValue value) return &wrapper->wrapped(); return nullptr; } + +size_t JSDOMFormData::estimatedSize(JSCell* cell, JSC::VM& vm) +{ + auto& wrapped = jsCast(cell)->wrapped(); + return Base::estimatedSize(cell, vm) + wrapped.memoryCost(); +} + } diff --git a/src/bun.js/bindings/webcore/JSDOMFormData.h b/src/bun.js/bindings/webcore/JSDOMFormData.h index 190757f68b..286e820b1e 100644 --- a/src/bun.js/bindings/webcore/JSDOMFormData.h +++ b/src/bun.js/bindings/webcore/JSDOMFormData.h @@ -57,6 +57,7 @@ public: } static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + static size_t estimatedSize(JSCell* cell, JSC::VM& vm); protected: JSDOMFormData(JSC::Structure*, JSDOMGlobalObject&, Ref&&); diff --git a/src/bun.js/bindings/webcore/JSDOMURL.cpp b/src/bun.js/bindings/webcore/JSDOMURL.cpp index f82fcfd972..c190da7c09 100755 --- a/src/bun.js/bindings/webcore/JSDOMURL.cpp +++ b/src/bun.js/bindings/webcore/JSDOMURL.cpp @@ -141,6 +141,13 @@ static const HashTableValue JSDOMURLConstructorTableValues[] = { { "revokeObjectURL"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Bun__revokeObjectURL, 1 } }, }; +size_t JSDOMURL::estimatedSize(JSC::JSCell* cell, JSC::VM& vm) +{ + auto* thisObject = jsCast(cell); + auto& wrapped = thisObject->wrapped(); + return Base::estimatedSize(cell, vm) + wrapped.memoryCost(); +} + template<> EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSDOMURLDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) { auto& vm = lexicalGlobalObject->vm(); diff --git a/src/bun.js/bindings/webcore/JSDOMURL.h b/src/bun.js/bindings/webcore/JSDOMURL.h index 57424e6bdd..54e38cdc4b 100644 --- a/src/bun.js/bindings/webcore/JSDOMURL.h +++ b/src/bun.js/bindings/webcore/JSDOMURL.h @@ -59,6 +59,8 @@ public: static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); DECLARE_VISIT_CHILDREN; + static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm); + static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); protected: diff --git a/src/bun.js/bindings/webcore/JSFetchHeaders.cpp b/src/bun.js/bindings/webcore/JSFetchHeaders.cpp index 814377532c..8a57ca1908 100644 --- a/src/bun.js/bindings/webcore/JSFetchHeaders.cpp +++ b/src/bun.js/bindings/webcore/JSFetchHeaders.cpp @@ -116,6 +116,13 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSFetchHeadersPrototype, JSFetchHeadersProto using JSFetchHeadersDOMConstructor = JSDOMConstructor; +size_t JSFetchHeaders::estimatedSize(JSC::JSCell* cell, JSC::VM& vm) +{ + auto* thisObject = jsCast(cell); + auto& wrapped = thisObject->wrapped(); + return Base::estimatedSize(cell, vm) + wrapped.memoryCost(); +} + template<> JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSFetchHeadersDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) { VM& vm = lexicalGlobalObject->vm(); @@ -335,8 +342,12 @@ void JSFetchHeaders::finishCreation(VM& vm) void JSFetchHeaders::computeMemoryCost() { + size_t previousCost = m_memoryCost; m_memoryCost = wrapped().memoryCost(); - globalObject()->vm().heap.reportExtraMemoryAllocated(this, m_memoryCost); + int64_t diff = static_cast(m_memoryCost) - static_cast(previousCost); + if (diff > 0) { + globalObject()->vm().heap.reportExtraMemoryAllocated(this, static_cast(diff)); + } } JSObject* JSFetchHeaders::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) diff --git a/src/bun.js/bindings/webcore/JSFetchHeaders.h b/src/bun.js/bindings/webcore/JSFetchHeaders.h index 8db47a66d1..d555b12914 100644 --- a/src/bun.js/bindings/webcore/JSFetchHeaders.h +++ b/src/bun.js/bindings/webcore/JSFetchHeaders.h @@ -43,6 +43,7 @@ public: DECLARE_INFO; DECLARE_VISIT_CHILDREN; + static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm); static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) { diff --git a/src/bun.js/bindings/webcore/JSURLSearchParams.cpp b/src/bun.js/bindings/webcore/JSURLSearchParams.cpp index 66e1d13ec7..a938234a4a 100644 --- a/src/bun.js/bindings/webcore/JSURLSearchParams.cpp +++ b/src/bun.js/bindings/webcore/JSURLSearchParams.cpp @@ -656,4 +656,12 @@ URLSearchParams* JSURLSearchParams::toWrapped(JSC::VM& vm, JSC::JSValue value) return &wrapper->wrapped(); return nullptr; } + +size_t JSURLSearchParams::estimatedSize(JSC::JSCell* cell, JSC::VM& vm) +{ + auto* thisObject = jsCast(cell); + auto& wrapped = thisObject->wrapped(); + return Base::estimatedSize(cell, vm) + wrapped.memoryCost(); +} + } diff --git a/src/bun.js/bindings/webcore/JSURLSearchParams.h b/src/bun.js/bindings/webcore/JSURLSearchParams.h index d3cf240c2d..4c4ba34145 100644 --- a/src/bun.js/bindings/webcore/JSURLSearchParams.h +++ b/src/bun.js/bindings/webcore/JSURLSearchParams.h @@ -57,6 +57,7 @@ public: } static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm); protected: JSURLSearchParams(JSC::Structure*, JSDOMGlobalObject&, Ref&&); diff --git a/src/bun.js/bindings/webcore/JSWebSocket.cpp b/src/bun.js/bindings/webcore/JSWebSocket.cpp index c8a7fd5174..eb28767edc 100644 --- a/src/bun.js/bindings/webcore/JSWebSocket.cpp +++ b/src/bun.js/bindings/webcore/JSWebSocket.cpp @@ -896,6 +896,12 @@ JSC::GCClient::IsoSubspace* JSWebSocket::subspaceForImpl(JSC::VM& vm) [](auto& spaces, auto&& space) { spaces.m_subspaceForWebSocket = std::forward(space); }); } +size_t JSWebSocket::estimatedSize(JSCell* cell, JSC::VM& vm) +{ + auto* thisObject = jsCast(cell); + return Base::estimatedSize(cell, vm) + thisObject->wrapped().memoryCost(); +} + void JSWebSocket::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) { auto* thisObject = jsCast(cell); diff --git a/src/bun.js/bindings/webcore/JSWebSocket.h b/src/bun.js/bindings/webcore/JSWebSocket.h index 3a4d13f6b5..29f82e4eec 100644 --- a/src/bun.js/bindings/webcore/JSWebSocket.h +++ b/src/bun.js/bindings/webcore/JSWebSocket.h @@ -58,6 +58,7 @@ public: } static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + static size_t estimatedSize(JSCell*, JSC::VM&); WebSocket& wrapped() const { return static_cast(Base::wrapped()); diff --git a/src/bun.js/bindings/webcore/WebSocket.cpp b/src/bun.js/bindings/webcore/WebSocket.cpp index e44742c079..dc1a24c81c 100644 --- a/src/bun.js/bindings/webcore/WebSocket.cpp +++ b/src/bun.js/bindings/webcore/WebSocket.cpp @@ -285,6 +285,31 @@ ExceptionOr WebSocket::connect(const String& url, const Vector& pr return connect(url, protocols, std::nullopt); } +size_t WebSocket::memoryCost() const + +{ + size_t cost = sizeof(WebSocket); + cost += m_url.string().sizeInBytes(); + cost += m_subprotocol.sizeInBytes(); + cost += m_extensions.sizeInBytes(); + + if (m_connectedWebSocketKind == ConnectedWebSocketKind::Client) { + cost += Bun__WebSocketClient__memoryCost(m_connectedWebSocket.client); + } else if (m_connectedWebSocketKind == ConnectedWebSocketKind::ClientSSL) { + cost += Bun__WebSocketClientTLS__memoryCost(m_connectedWebSocket.clientSSL); + } + + if (m_upgradeClient) { + if (m_isSecure) { + cost += Bun__WebSocketHTTPSClient__memoryCost(m_upgradeClient); + } else { + cost += Bun__WebSocketHTTPClient__memoryCost(m_upgradeClient); + } + } + + return cost; +} + ExceptionOr WebSocket::connect(const String& url, const Vector& protocols, std::optional&& headersInit) { // LOG(Network, "WebSocket %p connect() url='%s'", this, url.utf8().data()); diff --git a/src/bun.js/bindings/webcore/WebSocket.h b/src/bun.js/bindings/webcore/WebSocket.h index 5373a736fe..b9abed7a24 100644 --- a/src/bun.js/bindings/webcore/WebSocket.h +++ b/src/bun.js/bindings/webcore/WebSocket.h @@ -163,6 +163,8 @@ public: updateHasPendingActivity(); } + size_t memoryCost() const; + private: typedef union AnyWebSocket { WebSocketClient* client; diff --git a/src/bun.js/modules/BunJSCModule.h b/src/bun.js/modules/BunJSCModule.h index 353e09fac9..60c5d7d2c1 100644 --- a/src/bun.js/modules/BunJSCModule.h +++ b/src/bun.js/modules/BunJSCModule.h @@ -889,6 +889,19 @@ JSC_DEFINE_HOST_FUNCTION(functionCodeCoverageForFile, basicBlocks.size(), functionStartOffset, ignoreSourceMap); } +JSC_DEFINE_HOST_FUNCTION(functionEstimateDirectMemoryUsageOf, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + JSValue value = callFrame->argument(0); + if (value.isCell()) { + auto& vm = globalObject->vm(); + EnsureStillAliveScope alive = value; + return JSValue::encode(jsDoubleNumber(alive.value().asCell()->estimatedSizeInBytes(vm))); + } + + return JSValue::encode(jsNumber(0)); +} + // clang-format off /* Source for BunJSCModuleTable.lut.h @begin BunJSCModuleTable @@ -918,17 +931,18 @@ JSC_DEFINE_HOST_FUNCTION(functionCodeCoverageForFile, totalCompileTime functionTotalCompileTime Function 0 getProtectedObjects functionGetProtectedObjects Function 0 generateHeapSnapshotForDebugging functionGenerateHeapSnapshotForDebugging Function 0 - profile functionRunProfiler Function 0 + profile functionRunProfiler Function 0 setTimeZone functionSetTimeZone Function 0 serialize functionSerialize Function 0 - deserialize functionDeserialize Function 0 + deserialize functionDeserialize Function 0 + estimateDirectMemoryUsageOf functionEstimateDirectMemoryUsageOf Function 1 @end */ namespace Zig { DEFINE_NATIVE_MODULE(BunJSC) { - INIT_NATIVE_MODULE(34); + INIT_NATIVE_MODULE(35); putNativeFn(Identifier::fromString(vm, "callerSourceOrigin"_s), functionCallerSourceOrigin); putNativeFn(Identifier::fromString(vm, "jscDescribe"_s), functionDescribe); @@ -957,10 +971,11 @@ DEFINE_NATIVE_MODULE(BunJSC) putNativeFn(Identifier::fromString(vm, "getProtectedObjects"_s), functionGetProtectedObjects); putNativeFn(Identifier::fromString(vm, "generateHeapSnapshotForDebugging"_s), functionGenerateHeapSnapshotForDebugging); putNativeFn(Identifier::fromString(vm, "profile"_s), functionRunProfiler); - putNativeFn(Identifier::fromString(vm, "codeCoverageForFile"_s), functionCodeCoverageForFile); + putNativeFn(Identifier::fromString(vm, "codeCoverageForFile"_s), functionCodeCoverageForFile); putNativeFn(Identifier::fromString(vm, "setTimeZone"_s), functionSetTimeZone); putNativeFn(Identifier::fromString(vm, "serialize"_s), functionSerialize); putNativeFn(Identifier::fromString(vm, "deserialize"_s), functionDeserialize); + putNativeFn(Identifier::fromString(vm, "estimateDirectMemoryUsageOf"_s), functionEstimateDirectMemoryUsageOf); // Deprecated putNativeFn(Identifier::fromString(vm, "describe"_s), functionDescribe); diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index 9c1467bf5d..beb6b1f8f6 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -1655,6 +1655,13 @@ pub const Blob = struct { pub usingnamespace bun.New(@This()); + pub fn memoryCost(this: *const Store) usize { + return if (this.hasOneRef()) @sizeOf(@This()) + switch (this.data) { + .bytes => this.data.bytes.len, + .file => 0, + } else 0; + } + pub fn size(this: *const Store) SizeType { return switch (this.data) { .bytes => this.data.bytes.len, @@ -4770,6 +4777,15 @@ pub const AnyBlob = union(enum) { InternalBlob: InternalBlob, WTFStringImpl: bun.WTF.StringImpl, + /// Assumed that AnyBlob itself is covered by the caller. + pub fn memoryCost(this: *const AnyBlob) usize { + return switch (this.*) { + .Blob => |*blob| if (blob.store) |blob_store| blob_store.memoryCost() else 0, + .WTFStringImpl => |str| if (str.refCount() == 1) str.memoryCost() else 0, + .InternalBlob => |*internal_blob| internal_blob.memoryCost(), + }; + } + pub fn hasOneRef(this: *const AnyBlob) bool { if (this.store()) |s| { return s.hasOneRef(); @@ -5122,6 +5138,10 @@ pub const InternalBlob = struct { bytes: std.ArrayList(u8), was_string: bool = false, + pub fn memoryCost(this: *const @This()) usize { + return this.bytes.capacity; + } + pub fn toStringOwned(this: *@This(), globalThis: *JSC.JSGlobalObject) JSValue { const bytes_without_bom = strings.withoutUTF8BOM(this.bytes.items); if (strings.toUTF16Alloc(globalThis.allocator(), bytes_without_bom, false, false) catch &[_]u16{}) |out| { diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig index 8505ee8789..2290def2c9 100644 --- a/src/bun.js/webcore/body.zig +++ b/src/bun.js/webcore/body.zig @@ -414,6 +414,16 @@ pub const Body = struct { }; } + pub fn memoryCost(this: *const Value) usize { + return switch (this.*) { + .InternalBlob => this.InternalBlob.bytes.items.len, + .WTFStringImpl => this.WTFStringImpl.memoryCost(), + .Locked => this.Locked.sizeHint(), + // .InlineBlob => this.InlineBlob.sliceConst().len, + else => 0, + }; + } + pub fn estimatedSize(this: *const Value) usize { return switch (this.*) { .InternalBlob => this.InternalBlob.sliceConst().len, diff --git a/src/bun.js/webcore/request.zig b/src/bun.js/webcore/request.zig index 6d745017ec..45a9f3fec3 100644 --- a/src/bun.js/webcore/request.zig +++ b/src/bun.js/webcore/request.zig @@ -77,6 +77,10 @@ pub const Request = struct { pub const getBlobWithoutCallFrame = RequestMixin.getBlobWithoutCallFrame; pub const WeakRef = bun.WeakPtr(Request, .weak_ptr_data); + pub fn memoryCost(this: *const Request) usize { + return @sizeOf(Request) + this.request_context.memoryCost() + this.url.byteSlice().len + this.body.value.memoryCost(); + } + pub export fn Request__getUWSRequest( this: *Request, ) ?*uws.Request { diff --git a/src/bun.js/webcore/response.classes.ts b/src/bun.js/webcore/response.classes.ts index 157f0abc38..567c029cb4 100644 --- a/src/bun.js/webcore/response.classes.ts +++ b/src/bun.js/webcore/response.classes.ts @@ -10,6 +10,7 @@ export default [ estimatedSize: true, configurable: false, overridesToJS: true, + memoryCost: true, proto: { text: { fn: "getText" }, json: { fn: "getJSON" }, diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index 346296cb34..165190e6be 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -1544,6 +1544,11 @@ pub const ArrayBufferSink = struct { return Sink.init(this); } + pub fn memoryCost(this: *const ArrayBufferSink) usize { + // Since this is a JSSink, the NewJSSink function does @sizeOf(JSSink) which includes @sizeOf(ArrayBufferSink). + return this.bytes.cap; + } + pub const JSSink = NewJSSink(@This(), "ArrayBufferSink"); }; @@ -1637,6 +1642,10 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type { pub fn start(_: *@This()) void {} }; + pub fn memoryCost(this: *ThisSink) callconv(.C) usize { + return @sizeOf(ThisSink) + SinkType.memoryCost(&this.sink); + } + pub fn onClose(ptr: JSValue, reason: JSValue) callconv(.C) void { JSC.markBinding(@src()); @@ -1951,6 +1960,7 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type { @export(jsConstruct, .{ .name = shim.symbolName("construct") }); @export(endWithSink, .{ .name = shim.symbolName("endWithSink") }); @export(updateRef, .{ .name = shim.symbolName("updateRef") }); + @export(memoryCost, .{ .name = shim.symbolName("memoryCost") }); shim.assertJSFunction(.{ write, @@ -2029,6 +2039,14 @@ pub fn HTTPServerWritable(comptime ssl: bool) type { this.signal = signal; } + // Don't include @sizeOf(This) because it's already included in the memoryCost of the sink + pub fn memoryCost(this: *@This()) usize { + // TODO: include Socket send buffer size. We can't here because we + // don't track if it's still accessible. + // Since this is a JSSink, the NewJSSink function does @sizeOf(JSSink) which includes @sizeOf(ArrayBufferSink). + return this.buffer.cap; + } + fn handleWrote(this: *@This(), amount1: usize) void { defer log("handleWrote: {d} offset: {d}, {d}", .{ amount1, this.offset, this.buffer.len }); const amount = @as(Blob.SizeType, @truncate(amount1)); @@ -2869,6 +2887,12 @@ pub const FetchTaskletChunkedRequestSink = struct { _ = this.end(null); return .{ .result = JSC.JSValue.jsNumber(0) }; } + + pub fn memoryCost(this: *const @This()) usize { + // Since this is a JSSink, the NewJSSink function does @sizeOf(JSSink) which includes @sizeOf(ArrayBufferSink). + return this.buffer.memoryCost(); + } + const name = "FetchTaskletChunkedRequestSink"; pub const JSSink = NewJSSink(@This(), name); }; @@ -2889,6 +2913,7 @@ pub fn ReadableStreamSource( comptime deinit_fn: fn (this: *Context) void, comptime setRefUnrefFn: ?fn (this: *Context, enable: bool) void, comptime drainInternalBuffer: ?fn (this: *Context) bun.ByteList, + comptime memoryCostFn: ?fn (this: *const Context) usize, comptime toBufferedValue: ?fn (this: *Context, globalThis: *JSC.JSGlobalObject, action: BufferedReadableStreamAction) bun.JSError!JSC.JSValue, ) type { return struct { @@ -3053,6 +3078,14 @@ pub fn ReadableStreamSource( pub const arrayBufferFromJS = JSReadableStreamSource.arrayBuffer; pub const blobFromJS = JSReadableStreamSource.blob; pub const bytesFromJS = JSReadableStreamSource.bytes; + + pub fn memoryCost(this: *const ReadableStreamSourceType) usize { + if (memoryCostFn) |function| { + return function(&this.context) + @sizeOf(@This()); + } + return @sizeOf(@This()); + } + pub const JSReadableStreamSource = struct { pub fn pull(this: *ReadableStreamSourceType, globalThis: *JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!JSC.JSValue { JSC.markBinding(@src()); @@ -3310,6 +3343,11 @@ pub const FileSink = struct { pub const IOWriter = bun.io.StreamingWriter(@This(), onWrite, onError, onReady, onClose); pub const Poll = IOWriter; + pub fn memoryCost(this: *const FileSink) usize { + // Since this is a JSSink, the NewJSSink function does @sizeOf(JSSink) which includes @sizeOf(FileSink). + return this.writer.memoryCost(); + } + fn Bun__ForceFileSinkToBeSynchronousOnWindows(globalObject: *JSC.JSGlobalObject, jsvalue: JSC.JSValue) callconv(.C) void { comptime bun.assert(Environment.isWindows); @@ -4420,6 +4458,11 @@ pub const FileReader = struct { return this.reader.setRawMode(flag); } + pub fn memoryCost(this: *const FileReader) usize { + // ReadableStreamSource covers @sizeOf(FileReader) + return this.reader.memoryCost(); + } + pub const Source = ReadableStreamSource( @This(), "File", @@ -4429,6 +4472,7 @@ pub const FileReader = struct { deinit, setRefOrUnref, drain, + memoryCost, null, ); }; @@ -4570,6 +4614,14 @@ pub const ByteBlobLoader = struct { return .zero; } + pub fn memoryCost(this: *const ByteBlobLoader) usize { + // ReadableStreamSource covers @sizeOf(FileReader) + if (this.store) |store| { + return store.memoryCost(); + } + return 0; + } + pub const Source = ReadableStreamSource( @This(), "Blob", @@ -4579,6 +4631,7 @@ pub const ByteBlobLoader = struct { deinit, null, drain, + memoryCost, toBufferedValue, ); }; @@ -4985,6 +5038,11 @@ pub const ByteStream = struct { } } + pub fn memoryCost(this: *const @This()) usize { + // ReadableStreamSource covers @sizeOf(ByteStream) + return this.buffer.capacity; + } + pub fn deinit(this: *@This()) void { JSC.markBinding(@src()); if (this.buffer.capacity > 0) this.buffer.clearAndFree(); @@ -5080,6 +5138,7 @@ pub const ByteStream = struct { deinit, null, drain, + memoryCost, toBufferedValue, ); }; diff --git a/src/codegen/class-definitions.ts b/src/codegen/class-definitions.ts index fe5944fce4..ec2f9e8a43 100644 --- a/src/codegen/class-definitions.ts +++ b/src/codegen/class-definitions.ts @@ -59,7 +59,22 @@ export interface ClassDefinition { JSType?: string; noConstructor?: boolean; wantsThis?: boolean; + /** + * Called from any thread. + * + * Used for GC. + */ estimatedSize?: boolean; + /** + * Used in heap snapshots. + * + * If true, the class will have a `memoryCost` method that returns the size of the object in bytes. + * + * Unlike estimatedSize, this is always called on the main thread and not used for GC. + * + * If none is provided, we use the struct size. + */ + memoryCost?: boolean; hasPendingActivity?: boolean; isEventEmitter?: boolean; supportsObjectCreate?: boolean; diff --git a/src/codegen/generate-classes.ts b/src/codegen/generate-classes.ts index bc83c72f45..6f30301b08 100644 --- a/src/codegen/generate-classes.ts +++ b/src/codegen/generate-classes.ts @@ -1206,7 +1206,7 @@ function generateClassHeader(typeName, obj: ClassDefinition) { [...Object.values(klass), ...Object.values(proto)].find(a => !!a.cache) ? "DECLARE_VISIT_CHILDREN;\ntemplate void visitAdditionalChildren(Visitor&);\nDECLARE_VISIT_OUTPUT_CONSTRAINTS;\n" : ""; - const sizeEstimator = obj.estimatedSize ? "static size_t estimatedSize(JSCell* cell, VM& vm);" : ""; + const sizeEstimator = "static size_t estimatedSize(JSCell* cell, VM& vm);"; var weakOwner = ""; var weakInit = ``; @@ -1291,6 +1291,16 @@ function generateClassHeader(typeName, obj: ClassDefinition) { static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(${name}, m_ctx); } + /** + * Estimated size of the object from Zig including the JS wrapper. + */ + static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm); + + /** + * Memory cost of the object from Zig, without necessarily having a JS wrapper alive. + */ + static size_t memoryCost(void* ptr); + void* m_ctx { nullptr }; @@ -1397,6 +1407,8 @@ visitor.reportExtraMemoryVisited(size); DEFINE_VISIT_CHILDREN(${name}); + + template void ${name}::visitAdditionalChildren(Visitor& visitor) { @@ -1473,9 +1485,39 @@ ${name}::~${name}() `; } + if (!obj.estimatedSize && !obj.memoryCost) { + externs += `extern "C" const size_t ${symbolName(typeName, "ZigStructSize")};`; + } else if (obj.memoryCost) { + externs += `extern JSC_CALLCONV size_t ${symbolName(typeName, "memoryCost")}(void* ptr);`; + } + + if (obj.memoryCost) { + output += ` +size_t ${name}::memoryCost(void* ptr) { + return ptr ? ${symbolName(typeName, "memoryCost")}(ptr) : 0; +} +`; + } else if (obj.estimatedSize) { + output += ` +size_t ${name}::memoryCost(void* ptr) { + return ptr ? ${symbolName(typeName, "estimatedSize")}(ptr) : 0; +} + `; + } else { + output += ` +size_t ${name}::memoryCost(void* ptr) { + return ptr ? ${symbolName(typeName, "ZigStructSize")} : 0; +} + `; + } + output += ` - +size_t ${name}::estimatedSize(JSC::JSCell* cell, JSC::VM& vm) { + auto* thisObject = jsCast<${name}*>(cell); + auto* wrapped = thisObject->wrapped(); + return Base::estimatedSize(cell, vm) + ${name}::memoryCost(wrapped); +} void ${name}::destroy(JSCell* cell) { @@ -1539,16 +1581,15 @@ extern JSC_CALLCONV bool JSC_HOST_CALL_ATTRIBUTES ${typeName}__dangerouslySetPtr return true; } - extern "C" const size_t ${typeName}__ptrOffset = ${className(typeName)}::offsetOfWrapped(); void ${name}::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) { auto* thisObject = jsCast<${name}*>(cell); if (void* wrapped = thisObject->wrapped()) { - // if (thisObject->scriptExecutionContext()) - // analyzer.setLabelForCell(cell, makeString("url ", thisObject->scriptExecutionContext()->url().string())); + analyzer.setWrappedObjectForCell(cell, wrapped); } + Base::analyzeHeap(cell, analyzer); } @@ -1624,6 +1665,7 @@ function generateZig( overridesToJS = false, estimatedSize, call = false, + memoryCost, values = [], hasPendingActivity = false, structuredClone = false, @@ -1695,6 +1737,15 @@ const JavaScriptCoreBindings = struct { `; + if (memoryCost) { + exports.set("memoryCost", symbolName(typeName, "memoryCost")); + output += ` + pub fn ${symbolName(typeName, "memoryCost")}(thisValue: *${typeName}) callconv(JSC.conv) usize { + return @call(.always_inline, ${typeName}.memoryCost, .{thisValue}); + } + `; + } + if (estimatedSize) { exports.set("estimatedSize", symbolName(typeName, "estimatedSize")); output += ` @@ -1702,6 +1753,10 @@ const JavaScriptCoreBindings = struct { return @call(.always_inline, ${typeName}.estimatedSize, .{thisValue}); } `; + } else if (!memoryCost && !estimatedSize) { + output += ` + export const ${symbolName(typeName, "ZigStructSize")}: usize = @sizeOf(${typeName}); + `; } if (hasPendingActivity) { @@ -2075,6 +2130,7 @@ const GENERATED_CLASSES_IMPL_HEADER_PRE = ` #include "ZigGeneratedClasses.h" #include "ErrorCode+List.h" #include "ErrorCode.h" +#include #if !OS(WINDOWS) #define JSC_CALLCONV "C" diff --git a/src/codegen/generate-jssink.ts b/src/codegen/generate-jssink.ts index 527ef8caf0..4271cd1212 100644 --- a/src/codegen/generate-jssink.ts +++ b/src/codegen/generate-jssink.ts @@ -105,6 +105,8 @@ function header() { } static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + static size_t estimatedSize(JSCell* cell, JSC::VM& vm); + static size_t memoryCost(void* sinkPtr); void ref(); void unref(); @@ -162,6 +164,8 @@ function header() { DECLARE_VISIT_CHILDREN; static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + static size_t estimatedSize(JSCell* cell, JSC::VM& vm); + static size_t memoryCost(void* sinkPtr); void* m_sinkPtr; mutable WriteBarrier m_onPull; @@ -187,7 +191,7 @@ JSC_DECLARE_CUSTOM_GETTER(function${name}__getter); const outer = ` // AUTO-GENERATED FILE. DO NOT EDIT. -// Generated by 'make generate-sink' +// Generated by generate-jssink.ts // #pragma once @@ -223,10 +227,7 @@ Structure* createJSSinkControllerStructure(JSC::VM& vm, JSC::JSGlobalObject* glo async function implementation() { const head = ` // AUTO-GENERATED FILE. DO NOT EDIT. -// Generated by 'make generate-sink' -// To regenerate this file, run: -// -// make generate-sink +// Generated by 'generate-jssink.ts' // #include "root.h" #include "headers.h" @@ -284,9 +285,7 @@ extern "C" void Bun__onSinkDestroyed(uintptr_t destructor, void* sinkPtr); namespace WebCore { using namespace JSC; - - - +${classes.map(name => `extern "C" size_t ${name}__memoryCost(void* sinkPtr);`).join("\n")} JSC_DEFINE_HOST_FUNCTION(functionStartDirectStream, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame *callFrame)) { @@ -412,6 +411,28 @@ JSC_DEFINE_CUSTOM_GETTER(function${name}__getter, (JSC::JSGlobalObject * lexical return JSC::JSValue::encode(globalObject->${name}()); } +size_t ${className}::estimatedSize(JSCell* cell, JSC::VM& vm) { + return Base::estimatedSize(cell, vm) + ${className}::memoryCost(jsCast<${className}*>(cell)->wrapped()); +} + +size_t ${className}::memoryCost(void* sinkPtr) { + if (!sinkPtr) + return 0; + + return ${name}__memoryCost(sinkPtr); +} + +size_t ${controller}::memoryCost(void* sinkPtr) { + if (!sinkPtr) + return 0; + + return ${name}__memoryCost(sinkPtr); +} + +size_t ${controller}::estimatedSize(JSCell* cell, JSC::VM& vm) { + return Base::estimatedSize(cell, vm) + ${controller}::memoryCost(jsCast<${controller}*>(cell)->wrapped()); +} + JSC_DECLARE_HOST_FUNCTION(${controller}__close); JSC_DEFINE_HOST_FUNCTION(${controller}__close, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame *callFrame)) { diff --git a/src/deps/libuwsockets.cpp b/src/deps/libuwsockets.cpp index b683362431..d3aafb25af 100644 --- a/src/deps/libuwsockets.cpp +++ b/src/deps/libuwsockets.cpp @@ -17,6 +17,9 @@ static inline std::string_view stringViewFromC(const char* message, size_t lengt return std::string_view(); } +using TLSWebSocket = uWS::WebSocket; +using TCPWebSocket = uWS::WebSocket; + extern "C" { @@ -722,12 +725,12 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return *uws->getUserData(); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return *uws->getUserData(); } @@ -735,14 +738,14 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; uws->close(); } else { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; uws->close(); } } @@ -752,13 +755,13 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return (uws_sendstatus_t)uws->send(stringViewFromC(message, length), (uWS::OpCode)(unsigned char)opcode); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return (uws_sendstatus_t)uws->send(stringViewFromC(message, length), (uWS::OpCode)(unsigned char)opcode); } @@ -770,8 +773,8 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return (uws_sendstatus_t)uws->send(stringViewFromC(message, length), (uWS::OpCode)(unsigned char)opcode, compress, fin); @@ -779,8 +782,8 @@ extern "C" else { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return (uws_sendstatus_t)uws->send(stringViewFromC(message, length), (uWS::OpCode)(unsigned char)opcode, compress, fin); @@ -793,13 +796,13 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return (uws_sendstatus_t)uws->sendFragment( stringViewFromC(message, length), compress); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return (uws_sendstatus_t)uws->sendFragment(stringViewFromC(message, length), compress); } @@ -809,13 +812,13 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return (uws_sendstatus_t)uws->sendFirstFragment( stringViewFromC(message, length), uWS::OpCode::BINARY, compress); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return (uws_sendstatus_t)uws->sendFirstFragment( stringViewFromC(message, length), uWS::OpCode::BINARY, compress); } @@ -826,14 +829,14 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return (uws_sendstatus_t)uws->sendFirstFragment( stringViewFromC(message, length), (uWS::OpCode)(unsigned char)opcode, compress); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return (uws_sendstatus_t)uws->sendFirstFragment( stringViewFromC(message, length), (uWS::OpCode)(unsigned char)opcode, compress); @@ -844,13 +847,13 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return (uws_sendstatus_t)uws->sendLastFragment( stringViewFromC(message, length), compress); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return (uws_sendstatus_t)uws->sendLastFragment( stringViewFromC(message, length), compress); } @@ -860,14 +863,14 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; uws->end(code, stringViewFromC(message, length)); } else { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; uws->end(code, stringViewFromC(message, length)); } } @@ -877,15 +880,15 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; uws->cork([handler, user_data]() { handler(user_data); }); } else { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; uws->cork([handler, user_data]() { handler(user_data); }); @@ -896,12 +899,12 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return uws->subscribe(stringViewFromC(topic, length)); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return uws->subscribe(stringViewFromC(topic, length)); } bool uws_ws_unsubscribe(int ssl, uws_websocket_t *ws, const char *topic, @@ -909,12 +912,12 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return uws->unsubscribe(stringViewFromC(topic, length)); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return uws->unsubscribe(stringViewFromC(topic, length)); } @@ -923,12 +926,12 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return uws->isSubscribed(stringViewFromC(topic, length)); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return uws->isSubscribed(stringViewFromC(topic, length)); } void uws_ws_iterate_topics(int ssl, uws_websocket_t *ws, @@ -938,15 +941,15 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; uws->iterateTopics([callback, user_data](auto topic) { callback(topic.data(), topic.length(), user_data); }); } else { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; uws->iterateTopics([callback, user_data](auto topic) { callback(topic.data(), topic.length(), user_data); }); @@ -959,13 +962,13 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return uws->publish(stringViewFromC(topic, topic_length), stringViewFromC(message, message_length)); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return uws->publish(stringViewFromC(topic, topic_length), stringViewFromC(message, message_length)); } @@ -977,14 +980,14 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return uws->publish(stringViewFromC(topic, topic_length), stringViewFromC(message, message_length), (uWS::OpCode)(unsigned char)opcode, compress); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return uws->publish(stringViewFromC(topic, topic_length), stringViewFromC(message, message_length), (uWS::OpCode)(unsigned char)opcode, compress); @@ -994,12 +997,12 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; return uws->getBufferedAmount(); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; return uws->getBufferedAmount(); } @@ -1008,14 +1011,14 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; std::string_view value = uws->getRemoteAddress(); *dest = value.data(); return value.length(); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; std::string_view value = uws->getRemoteAddress(); *dest = value.data(); @@ -1027,15 +1030,15 @@ extern "C" { if (ssl) { - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TLSWebSocket *uws = + (TLSWebSocket *)ws; std::string_view value = uws->getRemoteAddressAsText(); *dest = value.data(); return value.length(); } - uWS::WebSocket *uws = - (uWS::WebSocket *)ws; + TCPWebSocket *uws = + (TCPWebSocket *)ws; std::string_view value = uws->getRemoteAddressAsText(); *dest = value.data(); @@ -1714,6 +1717,14 @@ __attribute__((callback (corker, ctx))) } } + size_t uws_ws_memory_cost(int ssl, uws_websocket_t *ws) { + if (ssl) { + return ((TLSWebSocket*)ws)->memoryCost(); + } else { + return ((TCPWebSocket*)ws)->memoryCost(); + } + } + void us_socket_sendfile_needs_more(us_socket_r s) { s->context->loop->data.last_write_failed = 1; us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); diff --git a/src/deps/uws.zig b/src/deps/uws.zig index 183bbacfb1..044149b731 100644 --- a/src/deps/uws.zig +++ b/src/deps/uws.zig @@ -2884,6 +2884,13 @@ pub const AnyWebSocket = union(enum) { }; } + pub fn memoryCost(this: AnyWebSocket) usize { + return switch (this) { + .ssl => this.ssl.memoryCost(), + .tcp => this.tcp.memoryCost(), + }; + } + pub fn close(this: AnyWebSocket) void { const ssl_flag = @intFromBool(this == .ssl); return uws_ws_close(ssl_flag, this.raw()); @@ -2974,7 +2981,13 @@ pub const AnyWebSocket = union(enum) { } }; -pub const RawWebSocket = opaque {}; +pub const RawWebSocket = opaque { + pub fn memoryCost(this: *RawWebSocket, ssl_flag: i32) usize { + return uws_ws_memory_cost(ssl_flag, this); + } + + extern fn uws_ws_memory_cost(ssl: i32, ws: *RawWebSocket) usize; +}; pub const uws_websocket_handler = ?*const fn (*RawWebSocket) callconv(.C) void; pub const uws_websocket_message_handler = ?*const fn (*RawWebSocket, [*c]const u8, usize, Opcode) callconv(.C) void; @@ -3960,6 +3973,11 @@ pub fn NewApp(comptime ssl: bool) type { pub fn sendWithOptions(this: *WebSocket, message: []const u8, opcode: Opcode, compress: bool, fin: bool) SendStatus { return uws_ws_send_with_options(ssl_flag, this.raw(), message.ptr, message.len, opcode, compress, fin); } + + pub fn memoryCost(this: *WebSocket) usize { + return this.raw().memoryCost(ssl_flag); + } + // pub fn sendFragment(this: *WebSocket, message: []const u8) SendStatus { // return uws_ws_send_fragment(ssl_flag, this.raw(), message: [*c]const u8, length: usize, compress: bool); // } diff --git a/src/http/websocket_http_client.zig b/src/http/websocket_http_client.zig index 806b3ba117..36fbf8d445 100644 --- a/src/http/websocket_http_client.zig +++ b/src/http/websocket_http_client.zig @@ -626,6 +626,13 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { } } + pub fn memoryCost(this: *HTTPClient) callconv(.C) usize { + var cost: usize = @sizeOf(HTTPClient); + cost += this.body.capacity; + cost += this.to_send.len; + return cost; + } + pub fn handleWritable( this: *HTTPClient, socket: Socket, @@ -669,6 +676,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { .connect = connect, .cancel = cancel, .register = register, + .memoryCost = memoryCost, }); comptime { @@ -682,6 +690,9 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { @export(register, .{ .name = Export[2].symbol_name, }); + @export(memoryCost, .{ + .name = Export[3].symbol_name, + }); } } }; @@ -1928,6 +1939,14 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { } } + pub fn memoryCost(this: *WebSocket) callconv(.C) usize { + var cost: usize = @sizeOf(WebSocket); + cost += this.send_buffer.buf.len; + cost += this.receive_buffer.buf.len; + // This is under-estimated a little, as we don't include usockets context. + return cost; + } + pub const Export = shim.exportFunctions(.{ .writeBinaryData = writeBinaryData, .writeString = writeString, @@ -1936,6 +1955,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { .register = register, .init = init, .finalize = finalize, + .memoryCost = memoryCost, }); comptime { @@ -1947,6 +1967,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { @export(register, .{ .name = Export[4].symbol_name }); @export(init, .{ .name = Export[5].symbol_name }); @export(finalize, .{ .name = Export[6].symbol_name }); + @export(memoryCost, .{ .name = Export[7].symbol_name }); } } }; diff --git a/src/io/PipeReader.zig b/src/io/PipeReader.zig index 38394793a5..668f7b55fe 100644 --- a/src/io/PipeReader.zig +++ b/src/io/PipeReader.zig @@ -704,6 +704,10 @@ const PosixBufferedReader = struct { return this.flags.is_done or this.flags.received_eof or this.flags.closed_without_reporting; } + pub fn memoryCost(this: *const PosixBufferedReader) usize { + return @sizeOf(@This()) + this._buffer.capacity; + } + pub fn from(to: *@This(), other: *PosixBufferedReader, parent_: *anyopaque) void { to.* = .{ .handle = other.handle, @@ -972,6 +976,10 @@ pub const WindowsBufferedReader = struct { const WindowsOutputReader = @This(); + pub fn memoryCost(this: *const WindowsOutputReader) usize { + return @sizeOf(@This()) + this._buffer.capacity; + } + const Flags = packed struct { is_done: bool = false, pollable: bool = false, diff --git a/src/io/PipeWriter.zig b/src/io/PipeWriter.zig index fd41ae637c..622fda1527 100644 --- a/src/io/PipeWriter.zig +++ b/src/io/PipeWriter.zig @@ -199,6 +199,10 @@ pub fn PosixBufferedWriter( closed_without_reporting: bool = false, close_fd: bool = true, + pub fn memoryCost(_: *const @This()) usize { + return @sizeOf(@This()); + } + const PosixWriter = @This(); pub const auto_poll = if (@hasDecl(Parent, "auto_poll")) Parent.auto_poll else true; @@ -393,6 +397,10 @@ pub fn PosixStreamingWriter( // TODO: chunk_size: usize = 0, + pub fn memoryCost(this: *const @This()) usize { + return @sizeOf(@This()) + this.buffer.capacity; + } + pub fn getPoll(this: *@This()) ?*Async.FilePoll { return this.handle.getPoll(); } @@ -909,6 +917,10 @@ pub fn WindowsBufferedWriter( } } + pub fn memoryCost(this: *const WindowsWriter) usize { + return @sizeOf(@This()) + this.write_buffer.len; + } + pub fn startWithCurrentPipe(this: *WindowsWriter) bun.JSC.Maybe(void) { bun.assert(this.source != null); this.is_done = false; @@ -1025,6 +1037,10 @@ pub const StreamBuffer = struct { this.list.clearRetainingCapacity(); } + pub fn memoryCost(this: *const StreamBuffer) usize { + return this.list.capacity; + } + pub fn size(this: *const StreamBuffer) usize { return this.list.items.len - this.cursor; } @@ -1153,6 +1169,10 @@ pub fn WindowsStreamingWriter( pub usingnamespace BaseWindowsPipeWriter(WindowsWriter, Parent); + pub fn memoryCost(this: *const WindowsWriter) usize { + return @sizeOf(@This()) + this.current_payload.memoryCost() + this.outgoing.memoryCost(); + } + fn onCloseSource(this: *WindowsWriter) void { this.source = null; if (this.closed_without_reporting) { diff --git a/src/string.zig b/src/string.zig index 054fe37e51..e4497381d1 100644 --- a/src/string.zig +++ b/src/string.zig @@ -47,6 +47,10 @@ pub const WTFStringImplStruct = extern struct { return this.m_refCount / s_refCountIncrement; } + pub fn memoryCost(this: WTFStringImpl) usize { + return this.byteLength(); + } + pub fn isStatic(this: WTFStringImpl) bool { return this.m_refCount & s_refCountIncrement != 0; } diff --git a/test/js/bun/util/heap-snapshot.test.ts b/test/js/bun/util/heap-snapshot.test.ts new file mode 100644 index 0000000000..c37b7fab01 --- /dev/null +++ b/test/js/bun/util/heap-snapshot.test.ts @@ -0,0 +1,187 @@ +import { describe, it, expect } from "bun:test"; +import { parseHeapSnapshot, summarizeByType } from "./heap"; +import { estimateDirectMemoryUsageOf } from "bun:jsc"; + +describe("Native types report their size correctly", () => { + it("FormData", () => { + var formData = new FormData(); + globalThis.formData = formData; + let original = estimateDirectMemoryUsageOf(formData); + formData.append("a", Buffer.alloc(1024 * 1024 * 8, "abc").toString()); + const afterBuffer = estimateDirectMemoryUsageOf(formData); + expect(afterBuffer).toBeGreaterThan(original + 1024 * 1024 * 8); + formData.append("a", new Blob([Buffer.alloc(1024 * 1024 * 2, "yooa")])); + const afterBlob = estimateDirectMemoryUsageOf(formData); + expect(afterBlob).toBeGreaterThan(afterBuffer + 1024 * 1024 * 2); + formData.append("a", new Blob([Buffer.alloc(1024 * 1024 * 2, "yooa")])); + const afterBlob2 = estimateDirectMemoryUsageOf(formData); + expect(afterBlob2).toBeGreaterThan(afterBlob + 1024 * 1024 * 2); + + const snapshot = Bun.generateHeapSnapshot(); + const parsed = parseHeapSnapshot(snapshot); + const summariesList = Array.from(summarizeByType(parsed)); + const summariesMap = new Map(summariesList.map(summary => [summary.name, summary])); + + expect(summariesMap.get("FormData")?.size).toBeGreaterThan( + // Test that FormData includes the size of the strings and the blobs + 1024 * 1024 * 8 + 1024 * 1024 * 2 + 1024 * 1024 * 2, + ); + + delete globalThis.formData; + }); + + it("Request", () => { + var request = new Request("https://example.com", { + body: Buffer.alloc(1024 * 1024 * 2, "yoo"), + }); + globalThis.request = request; + + const snapshot = Bun.generateHeapSnapshot(); + const parsed = parseHeapSnapshot(snapshot); + const summariesList = Array.from(summarizeByType(parsed)); + const summariesMap = new Map(summariesList.map(summary => [summary.name, summary])); + + expect(summariesMap.get("Request")?.size).toBeGreaterThan(1024 * 1024 * 2); + expect(summariesMap.get("Request")?.size).toBeLessThan(1024 * 1024 * 4); + + delete globalThis.request; + }); + + it("Response", () => { + var response = new Response(Buffer.alloc(1024 * 1024 * 4, "yoo"), { + headers: { + "Content-Type": "text/plain", + }, + }); + globalThis.response = response; + + const snapshot = Bun.generateHeapSnapshot(); + const parsed = parseHeapSnapshot(snapshot); + const summariesList = Array.from(summarizeByType(parsed)); + const summariesMap = new Map(summariesList.map(summary => [summary.name, summary])); + + expect(summariesMap.get("Response")?.size).toBeGreaterThan(1024 * 1024 * 4); + + delete globalThis.response; + }); + + it("URL", () => { + const searchParams = new URLSearchParams(); + for (let i = 0; i < 1000; i++) { + searchParams.set(`a${i}`, `b${i}`); + } + + var url = new URL("https://example.com"); + globalThis.url = url; + url.search = searchParams.toString(); + + const snapshot = Bun.generateHeapSnapshot(); + const parsed = parseHeapSnapshot(snapshot); + const summariesList = Array.from(summarizeByType(parsed)); + const summariesMap = new Map(summariesList.map(summary => [summary.name, summary])); + + expect(summariesMap.get("URL")?.size).toBeGreaterThan(searchParams.toString().length); + + delete globalThis.url; + }); + + it("URLSearchParams", () => { + const searchParams = new URLSearchParams(); + globalThis.searchParams = searchParams; + const original = estimateDirectMemoryUsageOf(searchParams); + for (let i = 0; i < 1000; i++) { + searchParams.set(`a${i}`, `b${i}`); + } + const after = estimateDirectMemoryUsageOf(searchParams); + expect(after).toBeGreaterThan(original + 1000 * 2); + + const snapshot = Bun.generateHeapSnapshot(); + const parsed = parseHeapSnapshot(snapshot); + const summariesList = Array.from(summarizeByType(parsed)); + const summariesMap = new Map(summariesList.map(summary => [summary.name, summary])); + + expect(summariesMap.get("URLSearchParams")?.size).toBeGreaterThan( + // toString() is greater because of the "?" and "&" + [...searchParams.keys(), ...searchParams.values()].join("").length, + ); + + delete globalThis.searchParams; + }); + + it("Headers", () => { + const headers = new Headers(); + const original = estimateDirectMemoryUsageOf(headers); + for (let i = 0; i < 1000; i++) { + headers.set(`a${i}`, `b${i}`); + } + const after = estimateDirectMemoryUsageOf(headers); + expect(after).toBeGreaterThan(original + 1000 * 2); + + globalThis.headers = headers; + + const snapshot = Bun.generateHeapSnapshot(); + const parsed = parseHeapSnapshot(snapshot); + const summariesList = Array.from(summarizeByType(parsed)); + const summariesMap = new Map(summariesList.map(summary => [summary.name, summary])); + + // Test that Headers includes the size of the strings + expect(summariesMap.get("Headers")?.size).toBeGreaterThan([...headers.keys(), ...headers.values()].join("").length); + + delete globalThis.headers; + }); + + it("WebSocket + ServerWebSocket + Request", async () => { + using server = Bun.serve({ + port: 0, + websocket: { + open(ws) {}, + drain(ws) {}, + message(ws, message) { + const before = estimateDirectMemoryUsageOf(ws); + ws.send(message); + const after = estimateDirectMemoryUsageOf(ws); + const bufferedAmount = ws.getBufferedAmount(); + if (bufferedAmount > 0) { + expect(after).toBeGreaterThan(before + bufferedAmount); + } + }, + }, + + fetch(req, server) { + const before = estimateDirectMemoryUsageOf(req); + server.upgrade(req); + const after = estimateDirectMemoryUsageOf(req); + + // We detach the request context from the request object on upgrade. + expect(after).toBeLessThan(before); + + return new Response("hello"); + }, + }); + const ws = new WebSocket(server.url); + const original = estimateDirectMemoryUsageOf(ws); + globalThis.ws = ws; + + const { promise, resolve } = Promise.withResolvers(); + ws.onopen = () => { + // Send more than we can possibly send in a single message + ws.send(Buffer.alloc(1024 * 128, "hello")); + }; + ws.onmessage = event => { + resolve(event.data); + }; + await promise; + + const after = estimateDirectMemoryUsageOf(ws); + expect(after).toBeGreaterThan(original + 1024 * 128); + + const snapshot = Bun.generateHeapSnapshot(); + const parsed = parseHeapSnapshot(snapshot); + const summariesList = Array.from(summarizeByType(parsed)); + const summariesMap = new Map(summariesList.map(summary => [summary.name, summary])); + + expect(summariesMap.get("WebSocket")?.size).toBeGreaterThan(1024 * 128); + + delete globalThis.ws; + }); +}); diff --git a/test/js/bun/util/heap.ts b/test/js/bun/util/heap.ts new file mode 100644 index 0000000000..dd696dc6bb --- /dev/null +++ b/test/js/bun/util/heap.ts @@ -0,0 +1,244 @@ +//! This is a decently effecient heap profiler reader. + +export interface HeapSnapshotData { + nodes: Float64Array; + edges: Float64Array; + nodeClassNames: string[]; + edgeNames: string[]; + edgeTypes: string[]; + type: "Inspector" | "GCDebugging"; +} + +const enum NodeLayout { + ID = 0, + SIZE = 1, + CLASS_NAME_IDX = 2, + FLAGS = 3, + LABEL_IDX = 4, + CELL_ADDR = 5, + WRAPPED_ADDR = 6, + STRIDE_GCDEBUGGING = 7, + STRIDE_INSPECTOR = 4, +} + +const enum EdgeLayout { + FROM_NODE = 0, + TO_NODE = 1, + TYPE = 2, + NAME_OR_INDEX = 3, + STRIDE = 4, +} + +const enum TypeStatsLayout { + NAME = 0, + SIZE = 1, + COUNT = 2, + RETAINED_SIZE = 3, + STRIDE = 4, +} + +export class TypeStats { + constructor(private stats: Array) {} + + [Symbol.iterator]() { + const stats = this.stats; + let i = 0; + var iterator: IterableIterator<{ + name: string; + size: number; + count: number; + retainedSize: number; + }> = { + [Symbol.iterator]() { + return iterator; + }, + next() { + if (i >= stats.length) { + return { done: true, value: undefined }; + } + const name = stats[i++] as string; + const size = stats[i++] as number; + const count = stats[i++] as number; + const retainedSize = stats[i++] as number; + return { + done: false, + value: { name, size, count, retainedSize }, + }; + }, + }; + return iterator; + } +} + +export function parseHeapSnapshot(data: { + nodes: number[]; + edges: number[]; + nodeClassNames: string[]; + edgeNames: string[]; + edgeTypes: string[]; + type: "Inspector" | "GCDebugging"; +}): HeapSnapshotData { + return { + nodes: new Float64Array(data.nodes), + edges: new Float64Array(data.edges), + nodeClassNames: data.nodeClassNames, + edgeNames: data.edgeNames, + edgeTypes: data.edgeTypes, + type: data.type, + }; +} + +function getNodeStride(data: HeapSnapshotData): number { + return data.type === "GCDebugging" ? NodeLayout.STRIDE_GCDEBUGGING : NodeLayout.STRIDE_INSPECTOR; +} + +export function summarizeByType(data: HeapSnapshotData): TypeStats { + const nodeStride = getNodeStride(data); + const statsArray = new Array(data.nodeClassNames.length * TypeStatsLayout.STRIDE); + + // Initialize the stats array + for (let i = 0, nameIdx = 0; nameIdx < data.nodeClassNames.length; nameIdx++) { + statsArray[i++] = data.nodeClassNames[nameIdx]; + statsArray[i++] = 0; // size + statsArray[i++] = 0; // count + statsArray[i++] = 0; // retained size + } + + // Calculate retained sizes + const retainedSizes = computeRetainedSizes(data); + + // Accumulate stats + for (let i = 0, nodeIndex = 0, nodes = data.nodes; i < nodes.length; i += nodeStride, nodeIndex++) { + const classNameIdx = nodes[i + NodeLayout.CLASS_NAME_IDX]; + const size = nodes[i + NodeLayout.SIZE]; + + const statsOffset = classNameIdx * TypeStatsLayout.STRIDE; + statsArray[statsOffset + 1] += size; // Add to size + statsArray[statsOffset + 2] += 1; // Increment count + statsArray[statsOffset + 3] += retainedSizes[nodeIndex]; // Add retained size + } + + return new TypeStats(statsArray); +} + +// TODO: this is wrong. +function computeRetainedSizes(data: HeapSnapshotData): Float64Array { + const nodeStride = getNodeStride(data); + const nodeCount = Math.floor(data.nodes.length / nodeStride); + + // Initialize arrays + const retainedSizes = new Float64Array(nodeCount); + const processedNodes = new Uint8Array(nodeCount); + const incomingEdgeCount = new Uint32Array(nodeCount); + const isRoot = new Uint8Array(nodeCount); + + // Initialize with shallow sizes + for (let i = 0; i < nodeCount; i++) { + const offset = i * nodeStride; + retainedSizes[i] = data.nodes[offset + NodeLayout.SIZE] || 0; + } + + // Mark node 0 as root + isRoot[0] = 1; + + // Build outgoing edges list and count incoming edges + const outgoingEdges = new Array(nodeCount); + for (let i = 0; i < nodeCount; i++) { + outgoingEdges[i] = []; + } + + // First pass - count incoming edges + for (let i = 0; i < data.edges.length; i += EdgeLayout.STRIDE) { + const fromNode = data.edges[i + EdgeLayout.FROM_NODE]; + const toNode = data.edges[i + EdgeLayout.TO_NODE]; + + if (fromNode >= 0 && fromNode < nodeCount && toNode >= 0 && toNode < nodeCount && fromNode !== toNode) { + incomingEdgeCount[toNode]++; + outgoingEdges[fromNode].push(toNode); + } + } + + // Find roots - nodes with no incoming edges + for (let i = 1; i < nodeCount; i++) { + if (incomingEdgeCount[i] === 0) { + isRoot[i] = 1; + } + } + + function computeRetainedSize(nodeIndex: number): number { + if (processedNodes[nodeIndex]) return retainedSizes[nodeIndex]; + processedNodes[nodeIndex] = 1; + + let size = retainedSizes[nodeIndex]; + + // If we're a root, include everything we retain + if (isRoot[nodeIndex]) { + const outgoing = outgoingEdges[nodeIndex]; + for (let i = 0; i < outgoing.length; i++) { + const childIndex = outgoing[i]; + if (childIndex !== nodeIndex) { + size += computeRetainedSize(childIndex); + } + } + } else { + // For non-roots, only include uniquely retained children + const outgoing = outgoingEdges[nodeIndex]; + for (let i = 0; i < outgoing.length; i++) { + const childIndex = outgoing[i]; + if (childIndex !== nodeIndex && incomingEdgeCount[childIndex] === 1) { + size += computeRetainedSize(childIndex); + } + } + } + + retainedSizes[nodeIndex] = size; + return size; + } + + // Process roots first + for (let i = 0; i < nodeCount; i++) { + if (isRoot[i]) { + computeRetainedSize(i); + } + } + + // Process remaining nodes + for (let i = 0; i < nodeCount; i++) { + if (!processedNodes[i]) { + computeRetainedSize(i); + } + } + + return retainedSizes; +} + +if (import.meta.main) { + let json = JSON.parse(require("fs").readFileSync(process.argv[2], "utf-8")); + if (json?.snapshot) { + json = json.snapshot; + } + + const snapshot = parseHeapSnapshot(json); + + const classNames = summarizeByType(snapshot); + const numberFormatter = new Intl.NumberFormat(); + const formatBytes = (bytes: number) => { + if (bytes < 1024) { + return `${bytes} bytes`; + } + if (bytes < 1024 * 1024) { + return `${(bytes / 1024).toFixed(2)} KB`; + } + + return `${(bytes / 1024 / 1024).toFixed(2)} MB`; + }; + + let results = Array.from(classNames).sort((a, b) => b.retainedSize - a.retainedSize); + for (const { name, size, count, retainedSize } of results) { + console.log( + `${name}: ${numberFormatter.format(count)} instances, ${formatBytes( + size, + )} size, ${formatBytes(retainedSize)} retained`, + ); + } +} From 32c1fdf205d3b8e6e93ff264418b076a8d70f579 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 16 Dec 2024 20:18:04 -0800 Subject: [PATCH 029/125] Rename `estimateDirectMemoryUsageOf` to `estimateShallowMemoryUsageOf` --- docs/api/utils.md | 14 ++++++------ packages/bun-types/jsc.d.ts | 2 +- src/bun.js/modules/BunJSCModule.h | 4 ++-- test/js/bun/util/heap-snapshot.test.ts | 30 +++++++++++++------------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/api/utils.md b/docs/api/utils.md index c7743c2d43..8c96472f01 100644 --- a/docs/api/utils.md +++ b/docs/api/utils.md @@ -772,27 +772,27 @@ console.log(obj); // => { foo: "bar" } Internally, [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) and [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) serialize and deserialize the same way. This exposes the underlying [HTML Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) to JavaScript as an ArrayBuffer. -## `estimateDirectMemoryUsageOf` in `bun:jsc` +## `estimateShallowMemoryUsageOf` in `bun:jsc` -The `estimateDirectMemoryUsageOf` function returns a best-effort estimate of the memory usage of an object in bytes, excluding the memory usage of properties or other objects it references. For accurate per-object memory usage, use `Bun.generateHeapSnapshot`. +The `estimateShallowMemoryUsageOf` function returns a best-effort estimate of the memory usage of an object in bytes, excluding the memory usage of properties or other objects it references. For accurate per-object memory usage, use `Bun.generateHeapSnapshot`. ```js -import { estimateDirectMemoryUsageOf } from "bun:jsc"; +import { estimateShallowMemoryUsageOf } from "bun:jsc"; const obj = { foo: "bar" }; -const usage = estimateDirectMemoryUsageOf(obj); +const usage = estimateShallowMemoryUsageOf(obj); console.log(usage); // => 16 const buffer = Buffer.alloc(1024 * 1024); -estimateDirectMemoryUsageOf(buffer); +estimateShallowMemoryUsageOf(buffer); // => 1048624 const req = new Request("https://bun.sh"); -estimateDirectMemoryUsageOf(req); +estimateShallowMemoryUsageOf(req); // => 167 const array = Array(1024).fill({ a: 1 }); // Arrays are usually not stored contiguously in memory, so this will not return a useful value (which isn't a bug). -estimateDirectMemoryUsageOf(array); +estimateShallowMemoryUsageOf(array); // => 16 ``` diff --git a/packages/bun-types/jsc.d.ts b/packages/bun-types/jsc.d.ts index 1f61a49d81..2a07534586 100644 --- a/packages/bun-types/jsc.d.ts +++ b/packages/bun-types/jsc.d.ts @@ -225,5 +225,5 @@ declare module "bun:jsc" { * * Passing a primitive type that isn't heap allocated returns 0. */ - function estimateDirectMemoryUsageOf(value: object | CallableFunction | bigint | symbol | string): number; + function estimateShallowMemoryUsageOf(value: object | CallableFunction | bigint | symbol | string): number; } diff --git a/src/bun.js/modules/BunJSCModule.h b/src/bun.js/modules/BunJSCModule.h index 60c5d7d2c1..55926dde59 100644 --- a/src/bun.js/modules/BunJSCModule.h +++ b/src/bun.js/modules/BunJSCModule.h @@ -935,7 +935,7 @@ JSC_DEFINE_HOST_FUNCTION(functionEstimateDirectMemoryUsageOf, (JSGlobalObject * setTimeZone functionSetTimeZone Function 0 serialize functionSerialize Function 0 deserialize functionDeserialize Function 0 - estimateDirectMemoryUsageOf functionEstimateDirectMemoryUsageOf Function 1 + estimateShallowMemoryUsageOf functionEstimateDirectMemoryUsageOf Function 1 @end */ @@ -975,7 +975,7 @@ DEFINE_NATIVE_MODULE(BunJSC) putNativeFn(Identifier::fromString(vm, "setTimeZone"_s), functionSetTimeZone); putNativeFn(Identifier::fromString(vm, "serialize"_s), functionSerialize); putNativeFn(Identifier::fromString(vm, "deserialize"_s), functionDeserialize); - putNativeFn(Identifier::fromString(vm, "estimateDirectMemoryUsageOf"_s), functionEstimateDirectMemoryUsageOf); + putNativeFn(Identifier::fromString(vm, "estimateShallowMemoryUsageOf"_s), functionEstimateDirectMemoryUsageOf); // Deprecated putNativeFn(Identifier::fromString(vm, "describe"_s), functionDescribe); diff --git a/test/js/bun/util/heap-snapshot.test.ts b/test/js/bun/util/heap-snapshot.test.ts index c37b7fab01..2bd5aaa995 100644 --- a/test/js/bun/util/heap-snapshot.test.ts +++ b/test/js/bun/util/heap-snapshot.test.ts @@ -1,20 +1,20 @@ import { describe, it, expect } from "bun:test"; import { parseHeapSnapshot, summarizeByType } from "./heap"; -import { estimateDirectMemoryUsageOf } from "bun:jsc"; +import { estimateShallowMemoryUsageOf } from "bun:jsc"; describe("Native types report their size correctly", () => { it("FormData", () => { var formData = new FormData(); globalThis.formData = formData; - let original = estimateDirectMemoryUsageOf(formData); + let original = estimateShallowMemoryUsageOf(formData); formData.append("a", Buffer.alloc(1024 * 1024 * 8, "abc").toString()); - const afterBuffer = estimateDirectMemoryUsageOf(formData); + const afterBuffer = estimateShallowMemoryUsageOf(formData); expect(afterBuffer).toBeGreaterThan(original + 1024 * 1024 * 8); formData.append("a", new Blob([Buffer.alloc(1024 * 1024 * 2, "yooa")])); - const afterBlob = estimateDirectMemoryUsageOf(formData); + const afterBlob = estimateShallowMemoryUsageOf(formData); expect(afterBlob).toBeGreaterThan(afterBuffer + 1024 * 1024 * 2); formData.append("a", new Blob([Buffer.alloc(1024 * 1024 * 2, "yooa")])); - const afterBlob2 = estimateDirectMemoryUsageOf(formData); + const afterBlob2 = estimateShallowMemoryUsageOf(formData); expect(afterBlob2).toBeGreaterThan(afterBlob + 1024 * 1024 * 2); const snapshot = Bun.generateHeapSnapshot(); @@ -88,11 +88,11 @@ describe("Native types report their size correctly", () => { it("URLSearchParams", () => { const searchParams = new URLSearchParams(); globalThis.searchParams = searchParams; - const original = estimateDirectMemoryUsageOf(searchParams); + const original = estimateShallowMemoryUsageOf(searchParams); for (let i = 0; i < 1000; i++) { searchParams.set(`a${i}`, `b${i}`); } - const after = estimateDirectMemoryUsageOf(searchParams); + const after = estimateShallowMemoryUsageOf(searchParams); expect(after).toBeGreaterThan(original + 1000 * 2); const snapshot = Bun.generateHeapSnapshot(); @@ -110,11 +110,11 @@ describe("Native types report their size correctly", () => { it("Headers", () => { const headers = new Headers(); - const original = estimateDirectMemoryUsageOf(headers); + const original = estimateShallowMemoryUsageOf(headers); for (let i = 0; i < 1000; i++) { headers.set(`a${i}`, `b${i}`); } - const after = estimateDirectMemoryUsageOf(headers); + const after = estimateShallowMemoryUsageOf(headers); expect(after).toBeGreaterThan(original + 1000 * 2); globalThis.headers = headers; @@ -137,9 +137,9 @@ describe("Native types report their size correctly", () => { open(ws) {}, drain(ws) {}, message(ws, message) { - const before = estimateDirectMemoryUsageOf(ws); + const before = estimateShallowMemoryUsageOf(ws); ws.send(message); - const after = estimateDirectMemoryUsageOf(ws); + const after = estimateShallowMemoryUsageOf(ws); const bufferedAmount = ws.getBufferedAmount(); if (bufferedAmount > 0) { expect(after).toBeGreaterThan(before + bufferedAmount); @@ -148,9 +148,9 @@ describe("Native types report their size correctly", () => { }, fetch(req, server) { - const before = estimateDirectMemoryUsageOf(req); + const before = estimateShallowMemoryUsageOf(req); server.upgrade(req); - const after = estimateDirectMemoryUsageOf(req); + const after = estimateShallowMemoryUsageOf(req); // We detach the request context from the request object on upgrade. expect(after).toBeLessThan(before); @@ -159,7 +159,7 @@ describe("Native types report their size correctly", () => { }, }); const ws = new WebSocket(server.url); - const original = estimateDirectMemoryUsageOf(ws); + const original = estimateShallowMemoryUsageOf(ws); globalThis.ws = ws; const { promise, resolve } = Promise.withResolvers(); @@ -172,7 +172,7 @@ describe("Native types report their size correctly", () => { }; await promise; - const after = estimateDirectMemoryUsageOf(ws); + const after = estimateShallowMemoryUsageOf(ws); expect(after).toBeGreaterThan(original + 1024 * 128); const snapshot = Bun.generateHeapSnapshot(); From a3090fc204aa5455994faada52fdc7df88f0091e Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 16 Dec 2024 20:33:09 -0800 Subject: [PATCH 030/125] CI: cancel previous canary build --- .buildkite/ci.mjs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.buildkite/ci.mjs b/.buildkite/ci.mjs index 9f39a72a3d..2038005a68 100755 --- a/.buildkite/ci.mjs +++ b/.buildkite/ci.mjs @@ -1115,10 +1115,18 @@ async function getPipeline(options = {}) { steps[i] = undefined; } - return { + const pipeline = { priority, steps: [...steps.filter(step => typeof step !== "undefined"), ...Array.from(stepsByGroup.values())], }; + + // If you push two builds to main, cancel the previous build. + if (isMainBranch() && !isBuildManual() && options.canary) { + pipeline.concurrency_group = "canary"; + pipeline.concurrency = "cancel-all"; + } + + return pipeline; } async function main() { From 9d63ee0edfce462a985e1acdaf0b476707336756 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 16 Dec 2024 20:33:56 -0800 Subject: [PATCH 031/125] CI: test concurrency group --- .buildkite/ci.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/.buildkite/ci.mjs b/.buildkite/ci.mjs index 2038005a68..10ce828d9c 100755 --- a/.buildkite/ci.mjs +++ b/.buildkite/ci.mjs @@ -1121,6 +1121,7 @@ async function getPipeline(options = {}) { }; // If you push two builds to main, cancel the previous build. + // This is to reduce wasteful CI runs that slow down in-flight PRs. if (isMainBranch() && !isBuildManual() && options.canary) { pipeline.concurrency_group = "canary"; pipeline.concurrency = "cancel-all"; From 9d3b461a25d2a67fb7459d15606544d39c619230 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 16 Dec 2024 20:38:05 -0800 Subject: [PATCH 032/125] CI: Remove unnecessary config --- .buildkite/ci.mjs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.buildkite/ci.mjs b/.buildkite/ci.mjs index 10ce828d9c..9f39a72a3d 100755 --- a/.buildkite/ci.mjs +++ b/.buildkite/ci.mjs @@ -1115,19 +1115,10 @@ async function getPipeline(options = {}) { steps[i] = undefined; } - const pipeline = { + return { priority, steps: [...steps.filter(step => typeof step !== "undefined"), ...Array.from(stepsByGroup.values())], }; - - // If you push two builds to main, cancel the previous build. - // This is to reduce wasteful CI runs that slow down in-flight PRs. - if (isMainBranch() && !isBuildManual() && options.canary) { - pipeline.concurrency_group = "canary"; - pipeline.concurrency = "cancel-all"; - } - - return pipeline; } async function main() { From 77acfa23a77388058d0d552a8bff03e1b56600e6 Mon Sep 17 00:00:00 2001 From: dave caruso Date: Mon, 16 Dec 2024 22:22:54 -0800 Subject: [PATCH 033/125] pass all upstream node:os tests, all supported node:async_hooks tests (#15802) --- build.zig | 34 +- docs/project/bindgen.md | 34 +- .../bindings/BindgenCustomEnforceRange.h | 112 ++ src/bun.js/bindings/ErrorCode.cpp | 12 +- src/bun.js/bindings/ErrorCode.h | 10 +- src/bun.js/bindings/ErrorCode.ts | 10 +- src/bun.js/bindings/bindings.cpp | 55 +- src/bun.js/bindings/bindings.zig | 250 +-- src/bun.js/bindings/c-bindings.cpp | 14 +- src/bun.js/javascript.zig | 2 +- src/bun.js/node/node_os.bind.ts | 94 + src/bun.js/node/node_os.zig | 1567 ++++++++--------- src/bun.js/node/types.zig | 2 +- src/bun.js/test/expect.zig | 26 +- src/bundler/bundle_v2.zig | 2 +- src/c-headers-for-zig.h | 21 + src/c.zig | 37 +- src/codegen/bindgen-lib-internal.ts | 201 ++- src/codegen/bindgen-lib.ts | 136 +- src/codegen/bindgen.ts | 376 +++- src/darwin_c.zig | 3 - src/deps/libuv.zig | 2 +- src/js/node/async_hooks.ts | 43 +- src/js/node/os.ts | 53 +- src/js/private.d.ts | 3 + src/sys.zig | 5 +- test/js/node/os/os.test.js | 19 + ...t-async-hooks-asyncresource-constructor.js | 41 + .../parallel/test-async-hooks-constructor.js | 21 + .../parallel/test-async-wrap-constructor.js | 21 + test/js/node/test/parallel/test-os-eol.js | 24 + .../test/parallel/test-os-process-priority.js | 145 ++ .../test-os-userinfo-handles-getter-errors.js | 19 + test/js/node/test/parallel/test-os.js | 281 +++ 34 files changed, 2537 insertions(+), 1138 deletions(-) create mode 100644 src/bun.js/bindings/BindgenCustomEnforceRange.h create mode 100644 src/bun.js/node/node_os.bind.ts create mode 100644 src/c-headers-for-zig.h create mode 100644 test/js/node/test/parallel/test-async-hooks-asyncresource-constructor.js create mode 100644 test/js/node/test/parallel/test-async-hooks-constructor.js create mode 100644 test/js/node/test/parallel/test-async-wrap-constructor.js create mode 100644 test/js/node/test/parallel/test-os-eol.js create mode 100644 test/js/node/test/parallel/test-os-process-priority.js create mode 100644 test/js/node/test/parallel/test-os-userinfo-handles-getter-errors.js create mode 100644 test/js/node/test/parallel/test-os.js diff --git a/build.zig b/build.zig index 9a1e3b25a7..0fc377326f 100644 --- a/build.zig +++ b/build.zig @@ -328,6 +328,12 @@ pub fn build(b: *Build) !void { }); } + // zig build translate-c-headers + { + const step = b.step("translate-c", "Copy generated translated-c-headers.zig to zig-out"); + step.dependOn(&b.addInstallFile(getTranslateC(b, b.host, .Debug).getOutput(), "translated-c-headers.zig").step); + } + // zig build enum-extractor { // const step = b.step("enum-extractor", "Extract enum definitions (invoked by a code generator)"); @@ -380,6 +386,25 @@ pub fn addMultiCheck( } } +fn getTranslateC(b: *Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *Step.TranslateC { + const translate_c = b.addTranslateC(.{ + .root_source_file = b.path("src/c-headers-for-zig.h"), + .target = target, + .optimize = optimize, + .link_libc = true, + }); + inline for ([_](struct { []const u8, bool }){ + .{ "WINDOWS", translate_c.target.result.os.tag == .windows }, + .{ "POSIX", translate_c.target.result.os.tag != .windows }, + .{ "LINUX", translate_c.target.result.os.tag == .linux }, + .{ "DARWIN", translate_c.target.result.os.tag.isDarwin() }, + }) |entry| { + const str, const value = entry; + translate_c.defineCMacroRaw(b.fmt("{s}={d}", .{ str, @intFromBool(value) })); + } + return translate_c; +} + pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile { const obj = b.addObject(.{ .name = if (opts.optimize == .Debug) "bun-debug" else "bun", @@ -428,13 +453,8 @@ pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile { addInternalPackages(b, obj, opts); obj.root_module.addImport("build_options", opts.buildOptionsModule(b)); - const translate_plugin_api = b.addTranslateC(.{ - .root_source_file = b.path("./packages/bun-native-bundler-plugin-api/bundler_plugin.h"), - .target = opts.target, - .optimize = opts.optimize, - .link_libc = true, - }); - obj.root_module.addImport("bun-native-bundler-plugin-api", translate_plugin_api.createModule()); + const translate_c = getTranslateC(b, opts.target, opts.optimize); + obj.root_module.addImport("translated-c-headers", translate_c.createModule()); return obj; } diff --git a/docs/project/bindgen.md b/docs/project/bindgen.md index 3144d7f57f..83ee48d63a 100644 --- a/docs/project/bindgen.md +++ b/docs/project/bindgen.md @@ -61,7 +61,10 @@ This function declaration is equivalent to: declare function add(a: number, b: number = 1): number; ``` -The code generator will provide `bun.gen.math.jsAdd`, which is the native function implementation. To pass to JavaScript, use `bun.gen.math.createAddCallback(global)` +The code generator will provide `bun.gen.math.jsAdd`, which is the native +function implementation. To pass to JavaScript, use +`bun.gen.math.createAddCallback(global)`. JS files in `src/js/` may use +`$bindgenFn("math.bind.ts", "add")` to get a handle to the implementation. ## Strings @@ -104,7 +107,7 @@ export const action = fn({ In Zig, each variant gets a number, based on the order the schema defines. -``` +```zig fn action1(a: i32) i32 { return a; } @@ -180,9 +183,9 @@ export const add = fn({ // enforce in i32 range a: t.i32.enforceRange(), // clamp to u16 range - c: t.u16, + b: t.u16, // enforce in arbitrary range, with a default if not provided - b: t.i32.enforceRange(0, 1000).default(5), + c: t.i32.enforceRange(0, 1000).default(5), // clamp to arbitrary range, or null d: t.u16.clamp(0, 10).optional, }, @@ -190,6 +193,29 @@ export const add = fn({ }); ``` +Various Node.js validator functions such as `validateInteger`, `validateNumber`, and more are available. Use these when implementing Node.js APIs, so the error messages match 1:1 what Node would do. + +Unlike `enforceRange`, which is taken from WebIDL, `validate*` functions are much more strict on the input they accept. For example, Node's numerical validator check `typeof value === 'number'`, while WebIDL uses `ToNumber` for lossy conversion. + +```ts +import { t, fn } from "bindgen"; + +export const add = fn({ + args: { + global: t.globalObject, + // throw if not given a number + a: t.f64.validateNumber(), + // valid in i32 range + a: t.i32.validateInt32(), + // f64 within safe integer range + b: t.f64.validateInteger(), + // f64 in given range + c: t.f64.validateNumber(-10000, 10000), + }, + ret: t.i32, +}); +``` + ## Callbacks TODO diff --git a/src/bun.js/bindings/BindgenCustomEnforceRange.h b/src/bun.js/bindings/BindgenCustomEnforceRange.h new file mode 100644 index 0000000000..a207b4e67a --- /dev/null +++ b/src/bun.js/bindings/BindgenCustomEnforceRange.h @@ -0,0 +1,112 @@ +#pragma once +#include "root.h" +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" +#include "ErrorCode.h" + +namespace Bun { + +enum class BindgenCustomEnforceRangeKind { + Node, + Web, +}; + +// This type implements conversion for: +// - t.*.validateInteger() +// - t.*.enforceRange(a, b) when A, B is not the integer's ABI size. +// - t.i32.validateInt32() +// - t.u32.validateUInt32() +template< + typename NumericType, + NumericType Min, + NumericType Max, + BindgenCustomEnforceRangeKind Kind> +struct BindgenCustomEnforceRange : WebCore::IDLType { +}; + +} + +static String rangeErrorString(double value, double min, double max) +{ + return makeString("Value "_s, value, " is outside the range ["_s, min, ", "_s, max, ']'); +} + +namespace WebCore { + +template< + typename NumericType, + NumericType Min, + NumericType Max, + Bun::BindgenCustomEnforceRangeKind Kind> +struct Converter> + : DefaultConverter> { + template + static inline NumericType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, ExceptionThrower&& exceptionThrower = ExceptionThrower()) + { + auto scope = DECLARE_THROW_SCOPE(lexicalGlobalObject.vm()); + ASSERT(!scope.exception()); + double unrestricted; + if constexpr (Kind == Bun::BindgenCustomEnforceRangeKind::Node) { + // In Node.js, `validateNumber`, `validateInt32`, `validateUint32`, + // and `validateInteger` all start with the following + // + // if (typeof value !== 'number') + // throw new ERR_INVALID_ARG_TYPE(name, 'number', value); + // + if (!value.isNumber()) { + Bun::ERR::INVALID_ARG_TYPE(scope, &lexicalGlobalObject, exceptionThrower(), "number"_s, value); + return 0; + } + unrestricted = value.asNumber(); + ASSERT(!scope.exception()); + + // Node also validates that integer types are integers + if constexpr (std::is_integral_v) { + if (unrestricted != std::round(unrestricted)) { + // ERR_OUT_OF_RANGE "an integer" + Bun::ERR::OUT_OF_RANGE(scope, &lexicalGlobalObject, exceptionThrower(), "an integer"_s, value); + return 0; + } + } else { + // When a range is specified (what this template is implementing), + // Node also throws on NaN being out of range + if (std::isnan(unrestricted)) { + // ERR_OUT_OF_RANGE `>= ${min} && <= ${max}` + Bun::ERR::OUT_OF_RANGE(scope, &lexicalGlobalObject, exceptionThrower(), Min, Max, value); + return 0; + } + } + } else { + // WebIDL uses toNumber before applying range restrictions. This + // allows something like `true` to pass for `t.f64.enforceRange(-10, 10)`, + // but this behavior does not appear Node's validators. + unrestricted = value.toNumber(&lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, 0); + + if constexpr (std::is_integral_v) { + if (std::isnan(unrestricted) || std::isinf(unrestricted)) { + throwTypeError(&lexicalGlobalObject, scope, rangeErrorString(unrestricted, Min, Max)); + return 0; + } + + // IDL uses trunc to convert the double to an integer. + unrestricted = trunc(unrestricted); + } + } + + bool inRange = unrestricted >= Min && unrestricted <= Max; + if (!inRange) { + if constexpr (Kind == Bun::BindgenCustomEnforceRangeKind::Node) { + Bun::ERR::OUT_OF_RANGE(scope, &lexicalGlobalObject, exceptionThrower(), Min, Max, value); + } else { + // WebKit range exception + throwTypeError(&lexicalGlobalObject, scope, rangeErrorString(unrestricted, Min, Max)); + } + return 0; + } + + return static_cast(unrestricted); + } +}; + +} diff --git a/src/bun.js/bindings/ErrorCode.cpp b/src/bun.js/bindings/ErrorCode.cpp index 4f2d6eb32f..20f6c0639c 100644 --- a/src/bun.js/bindings/ErrorCode.cpp +++ b/src/bun.js/bindings/ErrorCode.cpp @@ -302,9 +302,9 @@ WTF::String ERR_OUT_OF_RANGE(JSC::ThrowScope& scope, JSC::JSGlobalObject* global namespace ERR { -JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, WTF::ASCIILiteral arg_name, WTF::ASCIILiteral expected_type, JSC::JSValue val_actual_value) +JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, const WTF::String& expected_type, JSC::JSValue val_actual_value) { - auto arg_kind = String(arg_name).startsWith("options."_s) ? "property"_s : "argument"_s; + auto arg_kind = arg_name.startsWith("options."_s) ? "property"_s : "argument"_s; auto ty_first_char = expected_type[0]; auto ty_kind = ty_first_char >= 'A' && ty_first_char <= 'Z' ? "an instance of"_s : "of type"_s; @@ -315,7 +315,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message)); return {}; } -JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, WTF::ASCIILiteral expected_type, JSC::JSValue val_actual_value) +JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, const WTF::String& expected_type, JSC::JSValue val_actual_value) { auto arg_name = val_arg_name.toWTFString(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); @@ -332,7 +332,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO return {}; } -JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, size_t lower, size_t upper, JSC::JSValue actual) +JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, double lower, double upper, JSC::JSValue actual) { auto lowerStr = jsNumber(lower).toWTFString(globalObject); auto upperStr = jsNumber(upper).toWTFString(globalObject); @@ -343,7 +343,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message)); return {}; } -JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, size_t lower, size_t upper, JSC::JSValue actual) +JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, double lower, double upper, JSC::JSValue actual) { auto arg_name = arg_name_val.toWTFString(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); @@ -356,7 +356,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message)); return {}; } -JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, size_t bound_num, Bound bound, JSC::JSValue actual) +JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, double bound_num, Bound bound, JSC::JSValue actual) { auto arg_name = arg_name_val.toWTFString(globalObject); RETURN_IF_EXCEPTION(throwScope, {}); diff --git a/src/bun.js/bindings/ErrorCode.h b/src/bun.js/bindings/ErrorCode.h index e4a64cff12..a3f4f8a67e 100644 --- a/src/bun.js/bindings/ErrorCode.h +++ b/src/bun.js/bindings/ErrorCode.h @@ -75,11 +75,11 @@ enum Bound { namespace ERR { -JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, WTF::ASCIILiteral arg_name, WTF::ASCIILiteral expected_type, JSC::JSValue val_actual_value); -JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name, WTF::ASCIILiteral expected_type, JSC::JSValue val_actual_value); -JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, size_t lower, size_t upper, JSC::JSValue actual); -JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name, size_t lower, size_t upper, JSC::JSValue actual); -JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, size_t bound_num, Bound bound, JSC::JSValue actual); +JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, const WTF::String& expected_type, JSC::JSValue val_actual_value); +JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name, const WTF::String& expected_type, JSC::JSValue val_actual_value); +JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, double lower, double upper, JSC::JSValue actual); +JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name, double lower, double upper, JSC::JSValue actual); +JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, double bound_num, Bound bound, JSC::JSValue actual); JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, const WTF::String& msg, JSC::JSValue actual); JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name_val, const WTF::String& msg, JSC::JSValue actual); JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, WTF::ASCIILiteral name, JSC::JSValue value, const WTF::String& reason = "is invalid"_s); diff --git a/src/bun.js/bindings/ErrorCode.ts b/src/bun.js/bindings/ErrorCode.ts index 1bf4c70f14..b9ed12271f 100644 --- a/src/bun.js/bindings/ErrorCode.ts +++ b/src/bun.js/bindings/ErrorCode.ts @@ -59,10 +59,11 @@ export default [ // Console ["ERR_CONSOLE_WRITABLE_STREAM", TypeError, "TypeError"], - //NET + // NET ["ERR_SOCKET_CLOSED_BEFORE_CONNECTION", Error], ["ERR_SOCKET_CLOSED", Error], - //HTTP2 + + // HTTP2 ["ERR_INVALID_HTTP_TOKEN", TypeError], ["ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED", TypeError], ["ERR_HTTP2_SEND_FILE", Error], @@ -87,4 +88,9 @@ export default [ ["ERR_HTTP2_SOCKET_UNBOUND", Error], ["ERR_HTTP2_ERROR", Error], ["ERR_HTTP2_OUT_OF_STREAMS", Error], + + // AsyncHooks + ["ERR_ASYNC_TYPE", TypeError], + ["ERR_INVALID_ASYNC_ID", RangeError], + ["ERR_ASYNC_CALLBACK", TypeError], ] as ErrorCodeMapping; diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 1d6d421503..b370262e00 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -1896,7 +1896,6 @@ JSC__JSValue SystemError__toErrorInstance(const SystemError* arg0, result->putDirect(vm, vm.propertyNames->name, code, JSC::PropertyAttribute::DontEnum | 0); } else { - result->putDirect( vm, vm.propertyNames->name, JSC::JSValue(jsString(vm, String("SystemError"_s))), @@ -1930,6 +1929,60 @@ JSC__JSValue SystemError__toErrorInstance(const SystemError* arg0, return JSC::JSValue::encode(JSC::JSValue(result)); } +JSC__JSValue SystemError__toErrorInstanceWithInfoObject(const SystemError* arg0, + JSC__JSGlobalObject* globalObject) +{ + ASSERT_NO_PENDING_EXCEPTION(globalObject); + SystemError err = *arg0; + + JSC::VM& vm = globalObject->vm(); + + auto scope = DECLARE_THROW_SCOPE(vm); + + auto codeString = err.code.toWTFString(); + auto syscallString = err.syscall.toWTFString(); + auto messageString = err.message.toWTFString(); + + JSC::JSValue message = JSC::jsString(vm, makeString("A system error occurred: "_s, syscallString, " returned "_s, codeString, " ("_s, messageString, ")"_s)); + + JSC::JSValue options = JSC::jsUndefined(); + JSC::JSObject* result = JSC::ErrorInstance::create(globalObject, JSC::ErrorInstance::createStructure(vm, globalObject, globalObject->errorPrototype()), message, options); + JSC::JSObject* info = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 0); + + auto clientData = WebCore::clientData(vm); + + result->putDirect( + vm, vm.propertyNames->name, + JSC::JSValue(jsString(vm, String("SystemError"_s))), + JSC::PropertyAttribute::DontEnum | 0); + result->putDirect( + vm, clientData->builtinNames().codePublicName(), + JSC::JSValue(jsString(vm, String("ERR_SYSTEM_ERROR"_s))), + JSC::PropertyAttribute::DontEnum | 0); + + info->putDirect(vm, clientData->builtinNames().codePublicName(), jsString(vm, codeString), JSC::PropertyAttribute::DontDelete | 0); + + result->putDirect(vm, JSC::Identifier::fromString(vm, "info"_s), info, JSC::PropertyAttribute::DontDelete | 0); + + auto syscallJsString = jsString(vm, syscallString); + result->putDirect(vm, clientData->builtinNames().syscallPublicName(), syscallJsString, + JSC::PropertyAttribute::DontDelete | 0); + info->putDirect(vm, clientData->builtinNames().syscallPublicName(), syscallJsString, + JSC::PropertyAttribute::DontDelete | 0); + + info->putDirect(vm, clientData->builtinNames().codePublicName(), jsString(vm, codeString), + JSC::PropertyAttribute::DontDelete | 0); + info->putDirect(vm, vm.propertyNames->message, jsString(vm, messageString), + JSC::PropertyAttribute::DontDelete | 0); + + info->putDirect(vm, clientData->builtinNames().errnoPublicName(), jsNumber(err.errno_), + JSC::PropertyAttribute::DontDelete | 0); + result->putDirect(vm, clientData->builtinNames().errnoPublicName(), JSC::JSValue(err.errno_), + JSC::PropertyAttribute::DontDelete | 0); + + RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::JSValue(result))); +} + JSC__JSValue JSC__JSObject__create(JSC__JSGlobalObject* globalObject, size_t initialCapacity, void* arg2, void (*ArgFn3)(void* arg0, JSC__JSObject* arg1, JSC__JSGlobalObject* arg2)) diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index ea29db478c..e79bf9799f 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -74,7 +74,8 @@ pub const JSObject = extern struct { JSValue.createEmptyObjectWithNullPrototype(global) else JSValue.createEmptyObject(global, comptime info.fields.len); - bun.debugAssert(val.isObject()); + if (bun.Environment.isDebug) + bun.assert(val.isObject()); break :obj val.uncheckedPtrCast(JSObject); }; @@ -1729,10 +1730,6 @@ pub const SystemError = extern struct { return @enumFromInt(this.errno * -1); } - pub fn toAnyhowError(this: SystemError) bun.anyhow.Error { - return bun.anyhow.Error.newSys(this); - } - pub fn deref(this: *const SystemError) void { this.path.deref(); this.code.deref(); @@ -1758,6 +1755,37 @@ pub const SystemError = extern struct { return shim.cppFn("toErrorInstance", .{ this, global }); } + /// This constructs the ERR_SYSTEM_ERROR error object, which has an `info` + /// property containing the details of the system error: + /// + /// SystemError [ERR_SYSTEM_ERROR]: A system error occurred: {syscall} returned {errno} ({message}) + /// { + /// name: "ERR_SYSTEM_ERROR", + /// info: { + /// errno: -{errno}, + /// code: {code}, // string + /// message: {message}, // string + /// syscall: {syscall}, // string + /// }, + /// errno: -{errno}, + /// syscall: {syscall}, + /// } + /// + /// Before using this function, consider if the Node.js API it is + /// implementing follows this convention. It is exclusively used + /// to match the error code that `node:os` throws. + pub fn toErrorInstanceWithInfoObject(this: *const SystemError, global: *JSGlobalObject) JSValue { + defer { + this.path.deref(); + this.code.deref(); + this.message.deref(); + this.syscall.deref(); + } + + return SystemError__toErrorInstanceWithInfoObject(this, global); + } + extern fn SystemError__toErrorInstanceWithInfoObject(*const SystemError, *JSC.JSGlobalObject) JSValue; + pub fn format(self: SystemError, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { if (!self.path.isEmpty()) { // TODO: remove this hardcoding @@ -1999,6 +2027,7 @@ pub const JSPromiseRejectionOperation = enum(u32) { Handle = 1, }; +// TODO(@paperdave): delete and inline these functions pub fn NewGlobalObject(comptime Type: type) type { return struct { const importNotImpl = "Import not implemented"; @@ -5881,14 +5910,11 @@ pub const JSValue = enum(i64) { } pub fn asInt32(this: JSValue) i32 { - // TODO: add this assertion. currently, there is a mistake in - // argumentCount that mistakenly uses a JSValue instead of a c_int. This - // mistake performs the correct conversion instructions for it's use - // case but is bad code practice to misuse JSValue casts. - // - // if (bun.Environment.allow_assert) { - // bun.assert(this.isInt32()); - // } + // TODO: promote assertion to allow_assert. That has not been done because + // the assertion was commented out until 2024-12-12 + if (bun.Environment.isDebug) { + bun.assert(this.isInt32()); + } return FFI.JSVALUE_TO_INT32(.{ .asJSValue = this }); } @@ -6573,67 +6599,112 @@ pub const CatchScope = extern struct { }; }; -// TODO: callframe cleanup -// - remove all references into sizegen.zig since it is no longer run and may become out of date -// - remove all functions to retrieve arguments, replace with -// - arguments(*CallFrame) []const JSValue (when you want a full slice) -// - argumentsAsArray(*CallFrame, comptime len) [len]JSValue (common case due to destructuring) -// - argument(*CallFrame, i: usize) JSValue (return undefined if not present) -// - argumentCount(*CallFrame) usize -// -// argumentsPtr() -> arguments().ptr -// arguments(n).ptr[k] -> argumentsAsArray(n)[k] -// arguments(n).slice() -> arguments() -// arguments(n).mut() -> `var args = argumentsAsArray(n); &args` -// argumentsCount() -> argumentCount() (to match JSC) -// argument(n) -> arguments().ptr[n] +/// Call Frame for JavaScript -> Native function calls. In Bun, it is +/// preferred to use the bindings generator instead of directly decoding +/// arguments. See `docs/project/bindgen.md` pub const CallFrame = opaque { - /// The value is generated in `make sizegen` - /// The value is 6. - /// On ARM64_32, the value is something else but it really doesn't matter for our case - /// However, I don't want this to subtly break amidst future upgrades to JavaScriptCore - const alignment = Sizes.Bun_CallFrame__align; - - pub const name = "JSC::CallFrame"; - - inline fn asUnsafeJSValueArray(self: *const CallFrame) [*]const JSC.JSValue { - return @as([*]align(alignment) const JSC.JSValue, @ptrCast(@alignCast(self))); + /// A slice of all passed arguments to this function call. + pub fn arguments(self: *const CallFrame) []const JSValue { + return self.asUnsafeJSValueArray()[offset_first_argument..][0..self.argumentsCount()]; } - pub fn format(frame: *CallFrame, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { - const args = frame.argumentsPtr()[0..frame.argumentsCount()]; - - for (args[0..@min(args.len, 4)], 0..) |arg, i| { - if (i != 0) { - try writer.writeAll(", "); - } - switch (arg) { - .zero => try writer.writeAll(""), - .undefined => try writer.writeAll("undefined"), - .null => try writer.writeAll("null"), - .true => try writer.writeAll("true"), - .false => try writer.writeAll("false"), - else => { - if (arg.isNumber()) { - try writer.writeAll("number"); - } else { - try writer.writeAll(@tagName(arg.jsType())); - } - }, - } - } - - if (args.len > 4) { - try writer.print(", ... {d} more", .{args.len - 4}); - } + /// Usage: `const arg1, const arg2 = call_frame.argumentsAsArray(2);` + pub fn argumentsAsArray(call_frame: *const CallFrame, comptime count: usize) [count]JSValue { + const slice = call_frame.arguments(); + var value: [count]JSValue = .{.undefined} ** count; + const n = @min(call_frame.argumentsCount(), count); + @memcpy(value[0..n], slice[0..n]); + return value; } - pub fn argumentsPtr(self: *const CallFrame) [*]const JSC.JSValue { - return self.asUnsafeJSValueArray()[Sizes.Bun_CallFrame__firstArgument..]; + /// This function protects out-of-bounds access by returning `JSValue.undefined` + pub fn argument(self: *const CallFrame, i: usize) JSC.JSValue { + return if (self.argumentsCount() > i) self.arguments()[i] else .undefined; } + pub fn argumentsCount(self: *const CallFrame) u32 { + return self.argumentCountIncludingThis() - 1; + } + + /// When this CallFrame belongs to a constructor, this value is not the `this` + /// value, but instead the value of `new.target`. + pub fn this(self: *const CallFrame) JSC.JSValue { + return self.asUnsafeJSValueArray()[offset_this_argument]; + } + + /// `JSValue` for the current function being called. pub fn callee(self: *const CallFrame) JSC.JSValue { - return self.asUnsafeJSValueArray()[Sizes.Bun_CallFrame__callee]; + return self.asUnsafeJSValueArray()[offset_callee]; + } + + /// From JavaScriptCore/interpreter/CallFrame.h + /// + /// | ...... | | + /// +----------------------------+ | + /// | argN | v lower address + /// +----------------------------+ + /// | arg1 | + /// +----------------------------+ + /// | arg0 | + /// +----------------------------+ + /// | this | + /// +----------------------------+ + /// | argumentCountIncludingThis | + /// +----------------------------+ + /// | callee | + /// +----------------------------+ + /// | codeBlock | + /// +----------------------------+ + /// | return-address | + /// +----------------------------+ + /// | callerFrame | + /// +----------------------------+ <- callee's cfr is pointing this address + /// | local0 | + /// +----------------------------+ + /// | local1 | + /// +----------------------------+ + /// | localN | + /// +----------------------------+ + /// | ...... | + /// + /// The proper return type of this should be []Register, but + inline fn asUnsafeJSValueArray(self: *const CallFrame) [*]const JSC.JSValue { + return @ptrCast(@alignCast(self)); + } + + // These constants are from JSC::CallFrameSlot in JavaScriptCore/interpreter/CallFrame.h + const offset_code_block = 2; + const offset_callee = offset_code_block + 1; + const offset_argument_count_including_this = offset_callee + 1; + const offset_this_argument = offset_argument_count_including_this + 1; + const offset_first_argument = offset_this_argument + 1; + + /// This function is manually ported from JSC's equivalent function in C++ + /// See JavaScriptCore/interpreter/CallFrame.h + fn argumentCountIncludingThis(self: *const CallFrame) u32 { + // Register defined in JavaScriptCore/interpreter/Register.h + const Register = extern union { + value: JSValue, // EncodedJSValue + call_frame: *CallFrame, + code_block: *anyopaque, // CodeBlock* + /// EncodedValueDescriptor defined in JavaScriptCore/runtime/JSCJSValue.h + encoded_value: extern union { + ptr: JSValue, // JSCell* + as_bits: extern struct { + payload: i32, + tag: i32, + }, + }, + number: f64, // double + integer: i64, // integer + }; + const registers: [*]const Register = @alignCast(@ptrCast(self)); + // argumentCountIncludingThis takes the register at the defined offset, then + // calls 'ALWAYS_INLINE int32_t Register::unboxedInt32() const', + // which in turn calls 'ALWAYS_INLINE int32_t Register::payload() const' + // which accesses `.encodedValue.asBits.payload` + // JSC stores and works with value as signed, but it is always 1 or more. + return @intCast(registers[offset_argument_count_including_this].encoded_value.as_bits.payload); } fn Arguments(comptime max: usize) type { @@ -6667,54 +6738,35 @@ pub const CallFrame = opaque { }; } - pub fn arguments(self: *const CallFrame) []const JSValue { - // this presumably isn't allowed given that it doesn't exist - return self.argumentsPtr()[0..self.argumentsCount()]; - } + /// Do not use this function. Migration path: + /// arguments(n).ptr[k] -> argumentsAsArray(n)[k] + /// arguments(n).slice() -> arguments() + /// arguments(n).mut() -> `var args = argumentsAsArray(n); &args` pub fn arguments_old(self: *const CallFrame, comptime max: usize) Arguments(max) { - const len = self.argumentsCount(); - const ptr = self.argumentsPtr(); - return switch (@as(u4, @min(len, max))) { + const slice = self.arguments(); + comptime bun.assert(max <= 10); + return switch (@as(u4, @min(slice.len, max))) { 0 => .{ .ptr = undefined, .len = 0 }, - inline 1...10 => |count| Arguments(max).init(comptime @min(count, max), ptr), + inline 1...10 => |count| Arguments(max).init(comptime @min(count, max), slice.ptr), else => unreachable, }; } + /// Do not use this function. Migration path: + /// argumentsAsArray(n) pub fn argumentsUndef(self: *const CallFrame, comptime max: usize) Arguments(max) { - const len = self.argumentsCount(); - const ptr = self.argumentsPtr(); - return switch (@as(u4, @min(len, max))) { + const slice = self.arguments(); + comptime bun.assert(max <= 9); + return switch (@as(u4, @min(slice.len, max))) { 0 => .{ .ptr = .{.undefined} ** max, .len = 0 }, - inline 1...9 => |count| Arguments(max).initUndef(@min(count, max), ptr), + inline 1...9 => |count| Arguments(max).initUndef(@min(count, max), slice.ptr), else => unreachable, }; } - pub inline fn argument(self: *const CallFrame, i: usize) JSC.JSValue { - return self.argumentsPtr()[i]; - } - - pub fn this(self: *const CallFrame) JSC.JSValue { - return self.asUnsafeJSValueArray()[Sizes.Bun_CallFrame__thisArgument]; - } - - pub fn argumentsCount(self: *const CallFrame) usize { - return @as(usize, @intCast(self.asUnsafeJSValueArray()[Sizes.Bun_CallFrame__argumentCountIncludingThis].asInt32() - 1)); - } - extern fn Bun__CallFrame__isFromBunMain(*const CallFrame, *const VM) bool; pub const isFromBunMain = Bun__CallFrame__isFromBunMain; - /// Usage: `const arg1, const arg2 = call_frame.argumentsAsArray(2);` - pub fn argumentsAsArray(call_frame: *const CallFrame, comptime count: usize) [count]JSValue { - var value: [count]JSValue = .{.undefined} ** count; - for (0..@min(call_frame.argumentsCount(), count)) |i| { - value[i] = call_frame.argument(i); - } - return value; - } - extern fn Bun__CallFrame__getCallerSrcLoc(*const CallFrame, *JSGlobalObject, *bun.String, *c_uint, *c_uint) void; pub const CallerSrcLoc = struct { str: bun.String, diff --git a/src/bun.js/bindings/c-bindings.cpp b/src/bun.js/bindings/c-bindings.cpp index 38f74c731f..8268b1cab2 100644 --- a/src/bun.js/bindings/c-bindings.cpp +++ b/src/bun.js/bindings/c-bindings.cpp @@ -41,19 +41,25 @@ extern "C" void bun_warn_avx_missing(const char* url) } #endif -extern "C" int32_t get_process_priority(uint32_t pid) +// Error condition is encoded as max int32_t. +// The only error in this function is ESRCH (no process found) +extern "C" int32_t get_process_priority(int32_t pid) { #if OS(WINDOWS) int priority = 0; if (uv_os_getpriority(pid, &priority)) - return 0; + return std::numeric_limits::max(); return priority; #else - return getpriority(PRIO_PROCESS, pid); + errno = 0; + int priority = getpriority(PRIO_PROCESS, pid); + if (priority == -1 && errno != 0) + return std::numeric_limits::max(); + return priority; #endif // OS(WINDOWS) } -extern "C" int32_t set_process_priority(uint32_t pid, int32_t priority) +extern "C" int32_t set_process_priority(int32_t pid, int32_t priority) { #if OS(WINDOWS) return uv_os_setpriority(pid, priority); diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 283739d987..e12bfc4873 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -3981,7 +3981,7 @@ pub const VirtualMachine = struct { if (show.system_code) { if (show.syscall) { - try writer.writeAll(" "); + try writer.writeAll(" "); } else if (show.errno) { try writer.writeAll(" "); } diff --git a/src/bun.js/node/node_os.bind.ts b/src/bun.js/node/node_os.bind.ts new file mode 100644 index 0000000000..db3082c4b7 --- /dev/null +++ b/src/bun.js/node/node_os.bind.ts @@ -0,0 +1,94 @@ +// Internal bindings for node:os +// The entrypoint for node:os is `src/js/node/os.ts` +import { fn, t } from "bindgen"; + +export const cpus = fn({ + args: { + global: t.globalObject, + }, + ret: t.any, +}); +export const freemem = fn({ + args: {}, + ret: t.u64, +}); +export const getPriority = fn({ + args: { + global: t.globalObject, + pid: t.i32.validateInt32().default(0).nonNull, + }, + ret: t.i32, +}); +export const homedir = fn({ + args: { + global: t.globalObject, + }, + ret: t.DOMString, +}); +export const hostname = fn({ + args: { + global: t.globalObject, + }, + ret: t.any, +}); +export const loadavg = fn({ + args: { + global: t.globalObject, + }, + ret: t.any, +}); +export const networkInterfaces = fn({ + args: { + global: t.globalObject, + }, + ret: t.any, +}); +export const release = fn({ + args: {}, + ret: t.DOMString, +}); +export const totalmem = fn({ + args: {}, + ret: t.u64, +}); +export const uptime = fn({ + args: { + global: t.globalObject, + }, + ret: t.f64, +}); +export const UserInfoOptions = t.dictionary({ + encoding: t.DOMString.default(""), +}); +export const userInfo = fn({ + args: { + global: t.globalObject, + options: UserInfoOptions.default({}), + }, + ret: t.any, +}); +export const version = fn({ + args: {}, + ret: t.DOMString, +}); +const PRI_MIN = -20; +const PRI_MAX = 19; +export const setPriority = fn({ + variants: [ + { + args: { + global: t.globalObject, + pid: t.i32.validateInt32(), + priority: t.i32.validateInt32(PRI_MIN, PRI_MAX), + }, + ret: t.undefined, + }, + { + args: { + global: t.globalObject, + priority: t.i32.validateInt32(PRI_MIN, PRI_MAX), + }, + ret: t.undefined, + }, + ], +}); diff --git a/src/bun.js/node/node_os.zig b/src/bun.js/node/node_os.zig index ef2dfab3f1..fc60648fee 100644 --- a/src/bun.js/node/node_os.zig +++ b/src/bun.js/node/node_os.zig @@ -7,856 +7,825 @@ const strings = bun.strings; const JSC = bun.JSC; const Environment = bun.Environment; const Global = bun.Global; -const is_bindgen: bool = std.meta.globalOption("bindgen", bool) orelse false; - const libuv = bun.windows.libuv; -pub const OS = struct { - pub fn create(globalObject: *JSC.JSGlobalObject) JSC.JSValue { - const module = JSC.JSValue.createEmptyObject(globalObject, 16); +const gen = bun.gen.node_os; - module.put(globalObject, JSC.ZigString.static("cpus"), JSC.NewFunction(globalObject, JSC.ZigString.static("cpus"), 0, cpus, false)); - module.put(globalObject, JSC.ZigString.static("freemem"), JSC.NewFunction(globalObject, JSC.ZigString.static("freemem"), 0, freemem, false)); - module.put(globalObject, JSC.ZigString.static("getPriority"), JSC.NewFunction(globalObject, JSC.ZigString.static("getPriority"), 1, getPriority, false)); - module.put(globalObject, JSC.ZigString.static("homedir"), JSC.NewFunction(globalObject, JSC.ZigString.static("homedir"), 0, homedir, false)); - module.put(globalObject, JSC.ZigString.static("hostname"), JSC.NewFunction(globalObject, JSC.ZigString.static("hostname"), 0, hostname, false)); - module.put(globalObject, JSC.ZigString.static("loadavg"), JSC.NewFunction(globalObject, JSC.ZigString.static("loadavg"), 0, loadavg, false)); - module.put(globalObject, JSC.ZigString.static("machine"), JSC.NewFunction(globalObject, JSC.ZigString.static("machine"), 0, machine, false)); - module.put(globalObject, JSC.ZigString.static("networkInterfaces"), JSC.NewFunction(globalObject, JSC.ZigString.static("networkInterfaces"), 0, networkInterfaces, false)); - module.put(globalObject, JSC.ZigString.static("release"), JSC.NewFunction(globalObject, JSC.ZigString.static("release"), 0, release, false)); - module.put(globalObject, JSC.ZigString.static("setPriority"), JSC.NewFunction(globalObject, JSC.ZigString.static("setPriority"), 2, setPriority, false)); - module.put(globalObject, JSC.ZigString.static("totalmem"), JSC.NewFunction(globalObject, JSC.ZigString.static("totalmem"), 0, totalmem, false)); - module.put(globalObject, JSC.ZigString.static("type"), JSC.NewFunction(globalObject, JSC.ZigString.static("type"), 0, OS.type, false)); - module.put(globalObject, JSC.ZigString.static("uptime"), JSC.NewFunction(globalObject, JSC.ZigString.static("uptime"), 0, uptime, false)); - module.put(globalObject, JSC.ZigString.static("userInfo"), JSC.NewFunction(globalObject, JSC.ZigString.static("userInfo"), 0, userInfo, false)); - module.put(globalObject, JSC.ZigString.static("version"), JSC.NewFunction(globalObject, JSC.ZigString.static("version"), 0, version, false)); - module.put(globalObject, JSC.ZigString.static("machine"), JSC.NewFunction(globalObject, JSC.ZigString.static("machine"), 0, machine, false)); +pub fn createNodeOsBinding(global: *JSC.JSGlobalObject) JSC.JSValue { + return JSC.JSObject.create(.{ + .cpus = gen.createCpusCallback(global), + .freemem = gen.createFreememCallback(global), + .getPriority = gen.createGetPriorityCallback(global), + .homedir = gen.createHomedirCallback(global), + .hostname = gen.createHostnameCallback(global), + .loadavg = gen.createLoadavgCallback(global), + .networkInterfaces = gen.createNetworkInterfacesCallback(global), + .release = gen.createReleaseCallback(global), + .totalmem = gen.createTotalmemCallback(global), + .uptime = gen.createUptimeCallback(global), + .userInfo = gen.createUserInfoCallback(global), + .version = gen.createVersionCallback(global), + .setPriority = gen.createSetPriorityCallback(global), + }, global).toJS(); +} - return module; +const CPUTimes = struct { + user: u64 = 0, + nice: u64 = 0, + sys: u64 = 0, + idle: u64 = 0, + irq: u64 = 0, + + pub fn toValue(self: CPUTimes, globalThis: *JSC.JSGlobalObject) JSC.JSValue { + const fields = comptime std.meta.fieldNames(CPUTimes); + const ret = JSC.JSValue.createEmptyObject(globalThis, fields.len); + inline for (fields) |fieldName| { + ret.put(globalThis, JSC.ZigString.static(fieldName), JSC.JSValue.jsNumberFromUint64(@field(self, fieldName))); + } + return ret; + } +}; + +pub fn cpus(global: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { + const cpusImpl = switch (Environment.os) { + .linux => cpusImplLinux, + .mac => cpusImplDarwin, + .windows => cpusImplWindows, + else => @compileError("Unsupported OS"), + }; + + return cpusImpl(global) catch { + const err = JSC.SystemError{ + .message = bun.String.static("Failed to get CPU information"), + .code = bun.String.static(@tagName(JSC.Node.ErrorCode.ERR_SYSTEM_ERROR)), + }; + return global.throwValue(err.toErrorInstance(global)); + }; +} + +fn cpusImplLinux(globalThis: *JSC.JSGlobalObject) !JSC.JSValue { + // Create the return array + const values = JSC.JSValue.createEmptyArray(globalThis, 0); + var num_cpus: u32 = 0; + + var stack_fallback = std.heap.stackFallback(1024 * 8, bun.default_allocator); + var file_buf = std.ArrayList(u8).init(stack_fallback.get()); + defer file_buf.deinit(); + + // Read /proc/stat to get number of CPUs and times + { + const file = try std.fs.openFileAbsolute("/proc/stat", .{}); + defer file.close(); + + const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); + defer file_buf.clearRetainingCapacity(); + const contents = file_buf.items[0..read]; + + var line_iter = std.mem.tokenizeScalar(u8, contents, '\n'); + + // Skip the first line (aggregate of all CPUs) + _ = line_iter.next(); + + // Read each CPU line + while (line_iter.next()) |line| { + // CPU lines are formatted as `cpu0 user nice sys idle iowait irq softirq` + var toks = std.mem.tokenize(u8, line, " \t"); + const cpu_name = toks.next(); + if (cpu_name == null or !std.mem.startsWith(u8, cpu_name.?, "cpu")) break; // done with CPUs + + //NOTE: libuv assumes this is fixed on Linux, not sure that's actually the case + const scale = 10; + + var times = CPUTimes{}; + times.user = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); + times.nice = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); + times.sys = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); + times.idle = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); + _ = try (toks.next() orelse error.eol); // skip iowait + times.irq = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); + + // Actually create the JS object representing the CPU + const cpu = JSC.JSValue.createEmptyObject(globalThis, 3); + cpu.put(globalThis, JSC.ZigString.static("times"), times.toValue(globalThis)); + values.putIndex(globalThis, num_cpus, cpu); + + num_cpus += 1; + } } - const CPUTimes = struct { - user: u64 = 0, - nice: u64 = 0, - sys: u64 = 0, - idle: u64 = 0, - irq: u64 = 0, + // Read /proc/cpuinfo to get model information (optional) + if (std.fs.openFileAbsolute("/proc/cpuinfo", .{})) |file| { + defer file.close(); - pub fn toValue(self: CPUTimes, globalThis: *JSC.JSGlobalObject) JSC.JSValue { - const fields = comptime std.meta.fieldNames(CPUTimes); - const ret = JSC.JSValue.createEmptyObject(globalThis, fields.len); - inline for (fields) |fieldName| { - ret.put(globalThis, JSC.ZigString.static(fieldName), JSC.JSValue.jsNumberFromUint64(@field(self, fieldName))); + const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); + defer file_buf.clearRetainingCapacity(); + const contents = file_buf.items[0..read]; + + var line_iter = std.mem.tokenizeScalar(u8, contents, '\n'); + + const key_processor = "processor\t: "; + const key_model_name = "model name\t: "; + + var cpu_index: u32 = 0; + var has_model_name = true; + while (line_iter.next()) |line| { + if (strings.hasPrefixComptime(line, key_processor)) { + if (!has_model_name) { + const cpu = JSC.JSObject.getIndex(values, globalThis, cpu_index); + cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.static("unknown").withEncoding().toJS(globalThis)); + } + // If this line starts a new processor, parse the index from the line + const digits = std.mem.trim(u8, line[key_processor.len..], " \t\n"); + cpu_index = try std.fmt.parseInt(u32, digits, 10); + if (cpu_index >= num_cpus) return error.too_may_cpus; + has_model_name = false; + } else if (strings.hasPrefixComptime(line, key_model_name)) { + // If this is the model name, extract it and store on the current cpu + const model_name = line[key_model_name.len..]; + const cpu = JSC.JSObject.getIndex(values, globalThis, cpu_index); + cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.init(model_name).withEncoding().toJS(globalThis)); + has_model_name = true; } - return ret; + } + if (!has_model_name) { + const cpu = JSC.JSObject.getIndex(values, globalThis, cpu_index); + cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.static("unknown").withEncoding().toJS(globalThis)); + } + } else |_| { + // Initialize model name to "unknown" + var it = values.arrayIterator(globalThis); + while (it.next()) |cpu| { + cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.static("unknown").withEncoding().toJS(globalThis)); + } + } + + // Read /sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq to get current frequency (optional) + for (0..num_cpus) |cpu_index| { + const cpu = JSC.JSObject.getIndex(values, globalThis, @truncate(cpu_index)); + + var path_buf: [128]u8 = undefined; + const path = try std.fmt.bufPrint(&path_buf, "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq", .{cpu_index}); + if (std.fs.openFileAbsolute(path, .{})) |file| { + defer file.close(); + + const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); + defer file_buf.clearRetainingCapacity(); + const contents = file_buf.items[0..read]; + + const digits = std.mem.trim(u8, contents, " \n"); + const speed = (std.fmt.parseInt(u64, digits, 10) catch 0) / 1000; + + cpu.put(globalThis, JSC.ZigString.static("speed"), JSC.JSValue.jsNumber(speed)); + } else |_| { + // Initialize CPU speed to 0 + cpu.put(globalThis, JSC.ZigString.static("speed"), JSC.JSValue.jsNumber(0)); + } + } + + return values; +} + +extern fn bun_sysconf__SC_CLK_TCK() isize; +fn cpusImplDarwin(globalThis: *JSC.JSGlobalObject) !JSC.JSValue { + const local_bindings = @import("../../darwin_c.zig"); + const c = std.c; + + // Fetch the CPU info structure + var num_cpus: c.natural_t = 0; + var info: [*]local_bindings.processor_cpu_load_info = undefined; + var info_size: std.c.mach_msg_type_number_t = 0; + if (local_bindings.host_processor_info(std.c.mach_host_self(), local_bindings.PROCESSOR_CPU_LOAD_INFO, &num_cpus, @as(*local_bindings.processor_info_array_t, @ptrCast(&info)), &info_size) != .SUCCESS) { + return error.no_processor_info; + } + defer _ = std.c.vm_deallocate(std.c.mach_task_self(), @intFromPtr(info), info_size); + + // Ensure we got the amount of data we expected to guard against buffer overruns + if (info_size != C.PROCESSOR_CPU_LOAD_INFO_COUNT * num_cpus) { + return error.broken_process_info; + } + + // Get CPU model name + var model_name_buf: [512]u8 = undefined; + var len: usize = model_name_buf.len; + // Try brand_string first and if it fails try hw.model + if (!(std.c.sysctlbyname("machdep.cpu.brand_string", &model_name_buf, &len, null, 0) == 0 or + std.c.sysctlbyname("hw.model", &model_name_buf, &len, null, 0) == 0)) + { + return error.no_processor_info; + } + // NOTE: sysctlbyname doesn't update len if it was large enough, so we + // still have to find the null terminator. All cpus can share the same + // model name. + const model_name = JSC.ZigString.init(std.mem.sliceTo(&model_name_buf, 0)).withEncoding().toJS(globalThis); + + // Get CPU speed + var speed: u64 = 0; + len = @sizeOf(@TypeOf(speed)); + _ = std.c.sysctlbyname("hw.cpufrequency", &speed, &len, null, 0); + if (speed == 0) { + // Suggested by Node implementation: + // If sysctl hw.cputype == CPU_TYPE_ARM64, the correct value is unavailable + // from Apple, but we can hard-code it here to a plausible value. + speed = 2_400_000_000; + } + + // Get the multiplier; this is the number of ms/tick + const ticks: i64 = bun_sysconf__SC_CLK_TCK(); + const multiplier = 1000 / @as(u64, @intCast(ticks)); + + // Set up each CPU value in the return + const values = JSC.JSValue.createEmptyArray(globalThis, @as(u32, @intCast(num_cpus))); + var cpu_index: u32 = 0; + while (cpu_index < num_cpus) : (cpu_index += 1) { + const times = CPUTimes{ + .user = info[cpu_index].cpu_ticks[0] * multiplier, + .nice = info[cpu_index].cpu_ticks[3] * multiplier, + .sys = info[cpu_index].cpu_ticks[1] * multiplier, + .idle = info[cpu_index].cpu_ticks[2] * multiplier, + .irq = 0, // not available + }; + + const cpu = JSC.JSValue.createEmptyObject(globalThis, 3); + cpu.put(globalThis, JSC.ZigString.static("speed"), JSC.JSValue.jsNumber(speed / 1_000_000)); + cpu.put(globalThis, JSC.ZigString.static("model"), model_name); + cpu.put(globalThis, JSC.ZigString.static("times"), times.toValue(globalThis)); + + values.putIndex(globalThis, cpu_index, cpu); + } + return values; +} + +pub fn cpusImplWindows(globalThis: *JSC.JSGlobalObject) !JSC.JSValue { + var cpu_infos: [*]libuv.uv_cpu_info_t = undefined; + var count: c_int = undefined; + const err = libuv.uv_cpu_info(&cpu_infos, &count); + if (err != 0) { + return error.NoProcessorInfo; + } + defer libuv.uv_free_cpu_info(cpu_infos, count); + + const values = JSC.JSValue.createEmptyArray(globalThis, @intCast(count)); + + for (cpu_infos[0..@intCast(count)], 0..@intCast(count)) |cpu_info, i| { + const times = CPUTimes{ + .user = cpu_info.cpu_times.user, + .nice = cpu_info.cpu_times.nice, + .sys = cpu_info.cpu_times.sys, + .idle = cpu_info.cpu_times.idle, + .irq = cpu_info.cpu_times.irq, + }; + + const cpu = JSC.JSValue.createEmptyObject(globalThis, 3); + cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.init(bun.span(cpu_info.model)).withEncoding().toJS(globalThis)); + cpu.put(globalThis, JSC.ZigString.static("speed"), JSC.JSValue.jsNumber(cpu_info.speed)); + cpu.put(globalThis, JSC.ZigString.static("times"), times.toValue(globalThis)); + + values.putIndex(globalThis, @intCast(i), cpu); + } + + return values; +} + +pub fn freemem() u64 { + return C.getFreeMemory(); +} + +pub fn getPriority(global: *JSC.JSGlobalObject, pid: i32) bun.JSError!i32 { + return C.getProcessPriority(pid) orelse { + const err = JSC.SystemError{ + .message = bun.String.static("no such process"), + .code = bun.String.static("ESRCH"), + .errno = comptime switch (bun.Environment.os) { + else => -@as(c_int, @intFromEnum(std.posix.E.SRCH)), + .windows => libuv.UV_ESRCH, + }, + .syscall = bun.String.static("uv_os_getpriority"), + }; + return global.throwValue(err.toErrorInstanceWithInfoObject(global)); + }; +} + +pub fn homedir(global: *JSC.JSGlobalObject) !bun.String { + // In Node.js, this is a wrapper around uv_os_homedir. + if (Environment.isWindows) { + var out: bun.PathBuffer = undefined; + var size: usize = out.len; + if (libuv.uv_os_homedir(&out, &size).toError(.uv_os_homedir)) |err| { + return global.throwValue(err.toJSC(global)); + } + return bun.String.createUTF8(out[0..size]); + } else { + + // The posix implementation of uv_os_homedir first checks the HOME + // environment variable, then falls back to reading the passwd entry. + if (bun.getenvZ("HOME")) |home| { + if (home.len > 0) + return bun.String.init(home); + } + + // From libuv: + // > Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it + // > is frequently 1024 or 4096, so we can just use that directly. The pwent + // > will not usually be large. + // Instead of always using an allocation, first try a stack allocation + // of 4096, then fallback to heap. + var stack_string_bytes: [4096]u8 = undefined; + var string_bytes: []u8 = &stack_string_bytes; + defer if (string_bytes.ptr != &stack_string_bytes) + bun.default_allocator.free(string_bytes); + + var pw: bun.C.passwd = undefined; + var result: ?*bun.C.passwd = null; + + const ret = while (true) { + const ret = bun.C.getpwuid_r( + bun.C.geteuid(), + &pw, + string_bytes.ptr, + string_bytes.len, + &result, + ); + + if (ret == @intFromEnum(bun.C.E.INTR)) + continue; + + // If the system call wants more memory, double it. + if (ret == @intFromEnum(bun.C.E.RANGE)) { + const len = string_bytes.len; + bun.default_allocator.free(string_bytes); + string_bytes = ""; + string_bytes = try bun.default_allocator.alloc(u8, len * 2); + continue; + } + + break ret; + }; + + if (ret != 0) { + return global.throwValue(bun.sys.Error.fromCode( + @enumFromInt(ret), + .uv_os_homedir, + ).toJSC(global)); + } + + if (result == null) { + // in uv__getpwuid_r, null result throws UV_ENOENT. + return global.throwValue(bun.sys.Error.fromCode( + .NOENT, + .uv_os_homedir, + ).toJSC(global)); + } + + return if (pw.pw_dir) |dir| + bun.String.createUTF8(bun.span(dir)) + else + bun.String.empty; + } +} + +pub fn hostname(global: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { + if (Environment.isWindows) { + var name_buffer: [129:0]u16 = undefined; + if (bun.windows.GetHostNameW(&name_buffer, name_buffer.len) == 0) { + const str = bun.String.createUTF16(bun.sliceTo(&name_buffer, 0)); + defer str.deref(); + return str.toJS(global); + } + + var result: std.os.windows.ws2_32.WSADATA = undefined; + if (std.os.windows.ws2_32.WSAStartup(0x202, &result) == 0) { + if (bun.windows.GetHostNameW(&name_buffer, name_buffer.len) == 0) { + var y = bun.String.createUTF16(bun.sliceTo(&name_buffer, 0)); + defer y.deref(); + return y.toJS(global); + } + } + + return JSC.ZigString.init("unknown").withEncoding().toJS(global); + } else { + var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; + return JSC.ZigString.init(std.posix.gethostname(&name_buffer) catch "unknown").withEncoding().toJS(global); + } +} + +pub fn loadavg(global: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { + const result = C.getSystemLoadavg(); + return JSC.JSArray.create(global, &.{ + JSC.JSValue.jsNumber(result[0]), + JSC.JSValue.jsNumber(result[1]), + JSC.JSValue.jsNumber(result[2]), + }); +} + +pub const networkInterfaces = switch (Environment.os) { + .linux, .mac => networkInterfacesPosix, + .windows => networkInterfacesWindows, + else => @compileError("Unsupported OS"), +}; + +fn networkInterfacesPosix(globalThis: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { + // getifaddrs sets a pointer to a linked list + var interface_start: ?*C.ifaddrs = null; + const rc = C.getifaddrs(&interface_start); + if (rc != 0) { + const err = JSC.SystemError{ + .message = bun.String.static("A system error occurred: getifaddrs returned an error"), + .code = bun.String.static("ERR_SYSTEM_ERROR"), + .errno = @intFromEnum(std.posix.errno(rc)), + .syscall = bun.String.static("getifaddrs"), + }; + + return globalThis.throwValue(err.toErrorInstance(globalThis)); + } + defer C.freeifaddrs(interface_start); + + const helpers = struct { + // We'll skip interfaces that aren't actually available + pub fn skip(iface: *C.ifaddrs) bool { + // Skip interfaces that aren't actually available + if (iface.ifa_flags & C.IFF_RUNNING == 0) return true; + if (iface.ifa_flags & C.IFF_UP == 0) return true; + if (iface.ifa_addr == null) return true; + + return false; + } + + // We won't actually return link-layer interfaces but we need them for + // extracting the MAC address + pub fn isLinkLayer(iface: *C.ifaddrs) bool { + if (iface.ifa_addr == null) return false; + return if (comptime Environment.isLinux) + return iface.ifa_addr.*.sa_family == std.posix.AF.PACKET + else if (comptime Environment.isMac) + return iface.ifa_addr.?.*.family == std.posix.AF.LINK + else + unreachable; + } + + pub fn isLoopback(iface: *C.ifaddrs) bool { + return iface.ifa_flags & C.IFF_LOOPBACK == C.IFF_LOOPBACK; } }; - pub fn cpus(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - return switch (Environment.os) { - .linux => cpusImplLinux(globalThis), - .mac => cpusImplDarwin(globalThis), - .windows => cpusImplWindows(globalThis), - else => @compileError("unsupported OS"), - } catch { - const err = JSC.SystemError{ - .message = bun.String.static("Failed to get cpu information"), - .code = bun.String.static(@tagName(JSC.Node.ErrorCode.ERR_SYSTEM_ERROR)), - }; - - return globalThis.throwValue(err.toErrorInstance(globalThis)); - }; + // The list currently contains entries for link-layer interfaces + // and the IPv4, IPv6 interfaces. We only want to return the latter two + // but need the link-layer entries to determine MAC address. + // So, on our first pass through the linked list we'll count the number of + // INET interfaces only. + var num_inet_interfaces: usize = 0; + var it = interface_start; + while (it) |iface| : (it = iface.ifa_next) { + if (helpers.skip(iface) or helpers.isLinkLayer(iface)) continue; + num_inet_interfaces += 1; } - fn cpusImplLinux(globalThis: *JSC.JSGlobalObject) !JSC.JSValue { - // Create the return array - const values = JSC.JSValue.createEmptyArray(globalThis, 0); - var num_cpus: u32 = 0; + var ret = JSC.JSValue.createEmptyObject(globalThis, 8); - var stack_fallback = std.heap.stackFallback(1024 * 8, bun.default_allocator); - var file_buf = std.ArrayList(u8).init(stack_fallback.get()); - defer file_buf.deinit(); + // Second pass through, populate each interface object + it = interface_start; + while (it) |iface| : (it = iface.ifa_next) { + if (helpers.skip(iface) or helpers.isLinkLayer(iface)) continue; - // Read /proc/stat to get number of CPUs and times - if (std.fs.openFileAbsolute("/proc/stat", .{})) |file| { - defer file.close(); + const interface_name = std.mem.sliceTo(iface.ifa_name, 0); + const addr = std.net.Address.initPosix(@alignCast(@as(*std.posix.sockaddr, @ptrCast(iface.ifa_addr)))); + const netmask = std.net.Address.initPosix(@alignCast(@as(*std.posix.sockaddr, @ptrCast(iface.ifa_netmask)))); - const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); - defer file_buf.clearRetainingCapacity(); - const contents = file_buf.items[0..read]; + var interface = JSC.JSValue.createEmptyObject(globalThis, 7); - var line_iter = std.mem.tokenizeScalar(u8, contents, '\n'); - - // Skip the first line (aggregate of all CPUs) - _ = line_iter.next(); - - // Read each CPU line - while (line_iter.next()) |line| { - // CPU lines are formatted as `cpu0 user nice sys idle iowait irq softirq` - var toks = std.mem.tokenize(u8, line, " \t"); - const cpu_name = toks.next(); - if (cpu_name == null or !std.mem.startsWith(u8, cpu_name.?, "cpu")) break; // done with CPUs - - //NOTE: libuv assumes this is fixed on Linux, not sure that's actually the case - const scale = 10; - - var times = CPUTimes{}; - times.user = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); - times.nice = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); - times.sys = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); - times.idle = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); - _ = try (toks.next() orelse error.eol); // skip iowait - times.irq = scale * try std.fmt.parseInt(u64, toks.next() orelse return error.eol, 10); - - // Actually create the JS object representing the CPU - const cpu = JSC.JSValue.createEmptyObject(globalThis, 3); - cpu.put(globalThis, JSC.ZigString.static("times"), times.toValue(globalThis)); - values.putIndex(globalThis, num_cpus, cpu); - - num_cpus += 1; - } - } else |_| { - return error.no_proc_stat; - } - - // Read /proc/cpuinfo to get model information (optional) - if (std.fs.openFileAbsolute("/proc/cpuinfo", .{})) |file| { - defer file.close(); - - const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); - defer file_buf.clearRetainingCapacity(); - const contents = file_buf.items[0..read]; - - var line_iter = std.mem.tokenizeScalar(u8, contents, '\n'); - - const key_processor = "processor\t: "; - const key_model_name = "model name\t: "; - - var cpu_index: u32 = 0; - var has_model_name = true; - while (line_iter.next()) |line| { - if (strings.hasPrefixComptime(line, key_processor)) { - if (!has_model_name) { - const cpu = JSC.JSObject.getIndex(values, globalThis, cpu_index); - cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.static("unknown").withEncoding().toJS(globalThis)); - } - // If this line starts a new processor, parse the index from the line - const digits = std.mem.trim(u8, line[key_processor.len..], " \t\n"); - cpu_index = try std.fmt.parseInt(u32, digits, 10); - if (cpu_index >= num_cpus) return error.too_may_cpus; - has_model_name = false; - } else if (strings.hasPrefixComptime(line, key_model_name)) { - // If this is the model name, extract it and store on the current cpu - const model_name = line[key_model_name.len..]; - const cpu = JSC.JSObject.getIndex(values, globalThis, cpu_index); - cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.init(model_name).withEncoding().toJS(globalThis)); - has_model_name = true; - } - } - if (!has_model_name) { - const cpu = JSC.JSObject.getIndex(values, globalThis, cpu_index); - cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.static("unknown").withEncoding().toJS(globalThis)); - } - } else |_| { - // Initialize model name to "unknown" - var it = values.arrayIterator(globalThis); - while (it.next()) |cpu| { - cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.static("unknown").withEncoding().toJS(globalThis)); - } - } - - // Read /sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq to get current frequency (optional) - for (0..num_cpus) |cpu_index| { - const cpu = JSC.JSObject.getIndex(values, globalThis, @truncate(cpu_index)); - - var path_buf: [128]u8 = undefined; - const path = try std.fmt.bufPrint(&path_buf, "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq", .{cpu_index}); - if (std.fs.openFileAbsolute(path, .{})) |file| { - defer file.close(); - - const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap(); - defer file_buf.clearRetainingCapacity(); - const contents = file_buf.items[0..read]; - - const digits = std.mem.trim(u8, contents, " \n"); - const speed = (std.fmt.parseInt(u64, digits, 10) catch 0) / 1000; - - cpu.put(globalThis, JSC.ZigString.static("speed"), JSC.JSValue.jsNumber(speed)); - } else |_| { - // Initialize CPU speed to 0 - cpu.put(globalThis, JSC.ZigString.static("speed"), JSC.JSValue.jsNumber(0)); - } - } - - return values; - } - - extern fn bun_sysconf__SC_CLK_TCK() isize; - fn cpusImplDarwin(globalThis: *JSC.JSGlobalObject) !JSC.JSValue { - const local_bindings = @import("../../darwin_c.zig"); - const c = std.c; - - // Fetch the CPU info structure - var num_cpus: c.natural_t = 0; - var info: [*]local_bindings.processor_cpu_load_info = undefined; - var info_size: std.c.mach_msg_type_number_t = 0; - if (local_bindings.host_processor_info(std.c.mach_host_self(), local_bindings.PROCESSOR_CPU_LOAD_INFO, &num_cpus, @as(*local_bindings.processor_info_array_t, @ptrCast(&info)), &info_size) != .SUCCESS) { - return error.no_processor_info; - } - defer _ = std.c.vm_deallocate(std.c.mach_task_self(), @intFromPtr(info), info_size); - - // Ensure we got the amount of data we expected to guard against buffer overruns - if (info_size != C.PROCESSOR_CPU_LOAD_INFO_COUNT * num_cpus) { - return error.broken_process_info; - } - - // Get CPU model name - var model_name_buf: [512]u8 = undefined; - var len: usize = model_name_buf.len; - // Try brand_string first and if it fails try hw.model - if (!(std.c.sysctlbyname("machdep.cpu.brand_string", &model_name_buf, &len, null, 0) == 0 or - std.c.sysctlbyname("hw.model", &model_name_buf, &len, null, 0) == 0)) + // address The assigned IPv4 or IPv6 address + // cidr The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. { - return error.no_processor_info; - } - //NOTE: sysctlbyname doesn't update len if it was large enough, so we - // still have to find the null terminator. All cpus can share the same - // model name. - const model_name = JSC.ZigString.init(std.mem.sliceTo(&model_name_buf, 0)).withEncoding().toJS(globalThis); - - // Get CPU speed - var speed: u64 = 0; - len = @sizeOf(@TypeOf(speed)); - _ = std.c.sysctlbyname("hw.cpufrequency", &speed, &len, null, 0); - if (speed == 0) { - // Suggested by Node implementation: - // If sysctl hw.cputype == CPU_TYPE_ARM64, the correct value is unavailable - // from Apple, but we can hard-code it here to a plausible value. - speed = 2_400_000_000; - } - - // Get the multiplier; this is the number of ms/tick - const ticks: i64 = bun_sysconf__SC_CLK_TCK(); - const multiplier = 1000 / @as(u64, @intCast(ticks)); - - // Set up each CPU value in the return - const values = JSC.JSValue.createEmptyArray(globalThis, @as(u32, @intCast(num_cpus))); - var cpu_index: u32 = 0; - while (cpu_index < num_cpus) : (cpu_index += 1) { - const times = CPUTimes{ - .user = info[cpu_index].cpu_ticks[0] * multiplier, - .nice = info[cpu_index].cpu_ticks[3] * multiplier, - .sys = info[cpu_index].cpu_ticks[1] * multiplier, - .idle = info[cpu_index].cpu_ticks[2] * multiplier, - .irq = 0, // not available + // Compute the CIDR suffix; returns null if the netmask cannot + // be converted to a CIDR suffix + const maybe_suffix: ?u8 = switch (addr.any.family) { + std.posix.AF.INET => netmaskToCIDRSuffix(netmask.in.sa.addr), + std.posix.AF.INET6 => netmaskToCIDRSuffix(@as(u128, @bitCast(netmask.in6.sa.addr))), + else => null, }; - const cpu = JSC.JSValue.createEmptyObject(globalThis, 3); - cpu.put(globalThis, JSC.ZigString.static("speed"), JSC.JSValue.jsNumber(speed / 1_000_000)); - cpu.put(globalThis, JSC.ZigString.static("model"), model_name); - cpu.put(globalThis, JSC.ZigString.static("times"), times.toValue(globalThis)); - - values.putIndex(globalThis, cpu_index, cpu); - } - return values; - } - - pub fn cpusImplWindows(globalThis: *JSC.JSGlobalObject) !JSC.JSValue { - var cpu_infos: [*]libuv.uv_cpu_info_t = undefined; - var count: c_int = undefined; - const err = libuv.uv_cpu_info(&cpu_infos, &count); - if (err != 0) { - return error.no_processor_info; - } - defer libuv.uv_free_cpu_info(cpu_infos, count); - - const values = JSC.JSValue.createEmptyArray(globalThis, 0); - - for (cpu_infos[0..@intCast(count)], 0..@intCast(count)) |cpu_info, i| { - const times = CPUTimes{ - .user = cpu_info.cpu_times.user, - .nice = cpu_info.cpu_times.nice, - .sys = cpu_info.cpu_times.sys, - .idle = cpu_info.cpu_times.idle, - .irq = cpu_info.cpu_times.irq, - }; - - const cpu = JSC.JSValue.createEmptyObject(globalThis, 3); - cpu.put(globalThis, JSC.ZigString.static("model"), JSC.ZigString.init(bun.span(cpu_info.model)).withEncoding().toJS(globalThis)); - cpu.put(globalThis, JSC.ZigString.static("speed"), JSC.JSValue.jsNumber(cpu_info.speed)); - cpu.put(globalThis, JSC.ZigString.static("times"), times.toValue(globalThis)); - - values.putIndex(globalThis, @intCast(i), cpu); - } - - return values; - } - - pub fn endianness(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - return JSC.ZigString.init("LE").withEncoding().toJS(globalThis); - } - - pub fn freemem(_: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - return JSC.JSValue.jsNumberFromUint64(C.getFreeMemory()); - } - - pub fn getPriority(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - var args_ = callframe.arguments_old(1); - const arguments: []const JSC.JSValue = args_.ptr[0..args_.len]; - - if (arguments.len > 0 and !arguments[0].isNumber()) { - return globalThis.ERR_INVALID_ARG_TYPE("getPriority() expects a number", .{}).throw(); - } - - const pid = if (arguments.len > 0) arguments[0].asInt32() else 0; - - const priority = C.getProcessPriority(pid); - if (priority == -1) { - //const info = JSC.JSValue.createEmptyObject(globalThis, 4); - //info.put(globalThis, JSC.ZigString.static("errno"), JSC.JSValue.jsNumberFromInt32(-3)); - //info.put(globalThis, JSC.ZigString.static("code"), JSC.ZigString.init("ESRCH").withEncoding().toValueGC(globalThis)); - //info.put(globalThis, JSC.ZigString.static("message"), JSC.ZigString.init("no such process").withEncoding().toValueGC(globalThis)); - //info.put(globalThis, JSC.ZigString.static("syscall"), JSC.ZigString.init("uv_os_getpriority").withEncoding().toValueGC(globalThis)); - - const err = JSC.SystemError{ - .message = bun.String.static("A system error occurred: uv_os_getpriority returned ESRCH (no such process)"), - .code = bun.String.static("ERR_SYSTEM_ERROR"), - //.info = info, - .errno = -3, - .syscall = bun.String.static("uv_os_getpriority"), - }; - - return globalThis.throwValue(err.toErrorInstance(globalThis)); - } - - return JSC.JSValue.jsNumberFromInt32(priority); - } - - pub fn homedir(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - const dir: []const u8 = brk: { - if (comptime Environment.isWindows) { - if (bun.getenvZ("USERPROFILE")) |env| - break :brk bun.asByteSlice(env); - } else { - if (bun.getenvZ("HOME")) |env| - break :brk bun.asByteSlice(env); + // Format the address and then, if valid, the CIDR suffix; both + // the address and cidr values can be slices into this same buffer + // e.g. addr_str = "192.168.88.254", cidr_str = "192.168.88.254/24" + var buf: [64]u8 = undefined; + const addr_str = bun.fmt.formatIp(addr, &buf) catch unreachable; + var cidr = JSC.JSValue.null; + if (maybe_suffix) |suffix| { + //NOTE addr_str might not start at buf[0] due to slicing in formatIp + const start = @intFromPtr(addr_str.ptr) - @intFromPtr(&buf[0]); + // Start writing the suffix immediately after the address + const suffix_str = std.fmt.bufPrint(buf[start + addr_str.len ..], "/{}", .{suffix}) catch unreachable; + // The full cidr value is the address + the suffix + const cidr_str = buf[start .. start + addr_str.len + suffix_str.len]; + cidr = JSC.ZigString.init(cidr_str).withEncoding().toJS(globalThis); } - break :brk "unknown"; - }; - - return JSC.ZigString.init(dir).withEncoding().toJS(globalThis); - } - - pub fn hostname(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - if (comptime Environment.isWindows) { - var name_buffer: [129:0]u16 = undefined; - if (bun.windows.GetHostNameW(&name_buffer, name_buffer.len) == 0) { - const str = bun.String.createUTF16(bun.sliceTo(&name_buffer, 0)); - defer str.deref(); - return str.toJS(globalThis); - } - - var result: std.os.windows.ws2_32.WSADATA = undefined; - if (std.os.windows.ws2_32.WSAStartup(0x202, &result) == 0) { - if (bun.windows.GetHostNameW(&name_buffer, name_buffer.len) == 0) { - const str = bun.String.createUTF16(bun.sliceTo(&name_buffer, 0)); - defer str.deref(); - return str.toJS(globalThis); - } - } - - return JSC.ZigString.init("unknown").withEncoding().toJS(globalThis); + interface.put(globalThis, JSC.ZigString.static("address"), JSC.ZigString.init(addr_str).withEncoding().toJS(globalThis)); + interface.put(globalThis, JSC.ZigString.static("cidr"), cidr); } - var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; - - return JSC.ZigString.init(std.posix.gethostname(&name_buffer) catch "unknown").withEncoding().toJS(globalThis); - } - - pub fn loadavg(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - const result = C.getSystemLoadavg(); - return JSC.JSArray.create(globalThis, &.{ - JSC.JSValue.jsNumber(result[0]), - JSC.JSValue.jsNumber(result[1]), - JSC.JSValue.jsNumber(result[2]), - }); - } - - pub fn networkInterfaces(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - return switch (Environment.os) { - .windows => networkInterfacesWindows(globalThis), - else => networkInterfacesPosix(globalThis), - }; - } - - fn networkInterfacesPosix(globalThis: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { - // getifaddrs sets a pointer to a linked list - var interface_start: ?*C.ifaddrs = null; - const rc = C.getifaddrs(&interface_start); - if (rc != 0) { - const err = JSC.SystemError{ - .message = bun.String.static("A system error occurred: getifaddrs returned an error"), - .code = bun.String.static("ERR_SYSTEM_ERROR"), - .errno = @intFromEnum(std.posix.errno(rc)), - .syscall = bun.String.static("getifaddrs"), - }; - - return globalThis.throwValue(err.toErrorInstance(globalThis)); - } - defer C.freeifaddrs(interface_start); - - const helpers = struct { - // We'll skip interfaces that aren't actually available - pub fn skip(iface: *C.ifaddrs) bool { - // Skip interfaces that aren't actually available - if (iface.ifa_flags & C.IFF_RUNNING == 0) return true; - if (iface.ifa_flags & C.IFF_UP == 0) return true; - if (iface.ifa_addr == null) return true; - - return false; - } - - // We won't actually return link-layer interfaces but we need them for - // extracting the MAC address - pub fn isLinkLayer(iface: *C.ifaddrs) bool { - if (iface.ifa_addr == null) return false; - return if (comptime Environment.isLinux) - return iface.ifa_addr.*.sa_family == std.posix.AF.PACKET - else if (comptime Environment.isMac) - return iface.ifa_addr.?.*.family == std.posix.AF.LINK - else - unreachable; - } - - pub fn isLoopback(iface: *C.ifaddrs) bool { - return iface.ifa_flags & C.IFF_LOOPBACK == C.IFF_LOOPBACK; - } - }; - - // The list currently contains entries for link-layer interfaces - // and the IPv4, IPv6 interfaces. We only want to return the latter two - // but need the link-layer entries to determine MAC address. - // So, on our first pass through the linked list we'll count the number of - // INET interfaces only. - var num_inet_interfaces: usize = 0; - var it = interface_start; - while (it) |iface| : (it = iface.ifa_next) { - if (helpers.skip(iface) or helpers.isLinkLayer(iface)) continue; - num_inet_interfaces += 1; + // netmask The IPv4 or IPv6 network mask + { + var buf: [64]u8 = undefined; + const str = bun.fmt.formatIp(netmask, &buf) catch unreachable; + interface.put(globalThis, JSC.ZigString.static("netmask"), JSC.ZigString.init(str).withEncoding().toJS(globalThis)); } - var ret = JSC.JSValue.createEmptyObject(globalThis, 8); + // family Either IPv4 or IPv6 + interface.put(globalThis, JSC.ZigString.static("family"), (switch (addr.any.family) { + std.posix.AF.INET => JSC.ZigString.static("IPv4"), + std.posix.AF.INET6 => JSC.ZigString.static("IPv6"), + else => JSC.ZigString.static("unknown"), + }).toJS(globalThis)); - // Second pass through, populate each interface object - it = interface_start; - while (it) |iface| : (it = iface.ifa_next) { - if (helpers.skip(iface) or helpers.isLinkLayer(iface)) continue; + // mac The MAC address of the network interface + { + // We need to search for the link-layer interface whose name matches this one + var ll_it = interface_start; + const maybe_ll_addr = while (ll_it) |ll_iface| : (ll_it = ll_iface.ifa_next) { + if (helpers.skip(ll_iface) or !helpers.isLinkLayer(ll_iface)) continue; - const interface_name = std.mem.sliceTo(iface.ifa_name, 0); - const addr = std.net.Address.initPosix(@alignCast(@as(*std.posix.sockaddr, @ptrCast(iface.ifa_addr)))); - const netmask = std.net.Address.initPosix(@alignCast(@as(*std.posix.sockaddr, @ptrCast(iface.ifa_netmask)))); + const ll_name = bun.sliceTo(ll_iface.ifa_name, 0); + if (!strings.hasPrefix(ll_name, interface_name)) continue; + if (ll_name.len > interface_name.len and ll_name[interface_name.len] != ':') continue; - var interface = JSC.JSValue.createEmptyObject(globalThis, 7); - - // address The assigned IPv4 or IPv6 address - // cidr The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. - { - // Compute the CIDR suffix; returns null if the netmask cannot - // be converted to a CIDR suffix - const maybe_suffix: ?u8 = switch (addr.any.family) { - std.posix.AF.INET => netmaskToCIDRSuffix(netmask.in.sa.addr), - std.posix.AF.INET6 => netmaskToCIDRSuffix(@as(u128, @bitCast(netmask.in6.sa.addr))), - else => null, - }; - - // Format the address and then, if valid, the CIDR suffix; both - // the address and cidr values can be slices into this same buffer - // e.g. addr_str = "192.168.88.254", cidr_str = "192.168.88.254/24" - var buf: [64]u8 = undefined; - const addr_str = bun.fmt.formatIp(addr, &buf) catch unreachable; - var cidr = JSC.JSValue.null; - if (maybe_suffix) |suffix| { - //NOTE addr_str might not start at buf[0] due to slicing in formatIp - const start = @intFromPtr(addr_str.ptr) - @intFromPtr(&buf[0]); - // Start writing the suffix immediately after the address - const suffix_str = std.fmt.bufPrint(buf[start + addr_str.len ..], "/{}", .{suffix}) catch unreachable; - // The full cidr value is the address + the suffix - const cidr_str = buf[start .. start + addr_str.len + suffix_str.len]; - cidr = JSC.ZigString.init(cidr_str).withEncoding().toJS(globalThis); - } - - interface.put(globalThis, JSC.ZigString.static("address"), JSC.ZigString.init(addr_str).withEncoding().toJS(globalThis)); - interface.put(globalThis, JSC.ZigString.static("cidr"), cidr); - } - - // netmask The IPv4 or IPv6 network mask - { - var buf: [64]u8 = undefined; - const str = bun.fmt.formatIp(netmask, &buf) catch unreachable; - interface.put(globalThis, JSC.ZigString.static("netmask"), JSC.ZigString.init(str).withEncoding().toJS(globalThis)); - } - - // family Either IPv4 or IPv6 - interface.put(globalThis, JSC.ZigString.static("family"), (switch (addr.any.family) { - std.posix.AF.INET => JSC.ZigString.static("IPv4"), - std.posix.AF.INET6 => JSC.ZigString.static("IPv6"), - else => JSC.ZigString.static("unknown"), - }).toJS(globalThis)); - - // mac The MAC address of the network interface - { - // We need to search for the link-layer interface whose name matches this one - var ll_it = interface_start; - const maybe_ll_addr = while (ll_it) |ll_iface| : (ll_it = ll_iface.ifa_next) { - if (helpers.skip(ll_iface) or !helpers.isLinkLayer(ll_iface)) continue; - - const ll_name = bun.sliceTo(ll_iface.ifa_name, 0); - if (!strings.hasPrefix(ll_name, interface_name)) continue; - if (ll_name.len > interface_name.len and ll_name[interface_name.len] != ':') continue; - - // This is the correct link-layer interface entry for the current interface, - // cast to a link-layer socket address - if (comptime Environment.isLinux) { - break @as(?*std.posix.sockaddr.ll, @ptrCast(@alignCast(ll_iface.ifa_addr))); - } else if (comptime Environment.isMac) { - break @as(?*C.sockaddr_dl, @ptrCast(@alignCast(ll_iface.ifa_addr))); - } else { - @compileError("unreachable"); - } - } else null; - - if (maybe_ll_addr) |ll_addr| { - // Encode its link-layer address. We need 2*6 bytes for the - // hex characters and 5 for the colon separators - var mac_buf: [17]u8 = undefined; - const addr_data = if (comptime Environment.isLinux) ll_addr.addr else if (comptime Environment.isMac) ll_addr.sdl_data[ll_addr.sdl_nlen..] else @compileError("unreachable"); - if (addr_data.len < 6) { - const mac = "00:00:00:00:00:00"; - interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toJS(globalThis)); - } else { - const mac = std.fmt.bufPrint(&mac_buf, "{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}", .{ - addr_data[0], addr_data[1], addr_data[2], - addr_data[3], addr_data[4], addr_data[5], - }) catch unreachable; - interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toJS(globalThis)); - } + // This is the correct link-layer interface entry for the current interface, + // cast to a link-layer socket address + if (comptime Environment.isLinux) { + break @as(?*std.posix.sockaddr.ll, @ptrCast(@alignCast(ll_iface.ifa_addr))); + } else if (comptime Environment.isMac) { + break @as(?*C.sockaddr_dl, @ptrCast(@alignCast(ll_iface.ifa_addr))); } else { + @compileError("unreachable"); + } + } else null; + + if (maybe_ll_addr) |ll_addr| { + // Encode its link-layer address. We need 2*6 bytes for the + // hex characters and 5 for the colon separators + var mac_buf: [17]u8 = undefined; + const addr_data = if (comptime Environment.isLinux) ll_addr.addr else if (comptime Environment.isMac) ll_addr.sdl_data[ll_addr.sdl_nlen..] else @compileError("unreachable"); + if (addr_data.len < 6) { const mac = "00:00:00:00:00:00"; interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toJS(globalThis)); + } else { + const mac = std.fmt.bufPrint(&mac_buf, "{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}", .{ + addr_data[0], addr_data[1], addr_data[2], + addr_data[3], addr_data[4], addr_data[5], + }) catch unreachable; + interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toJS(globalThis)); } - } - - // internal true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false - interface.put(globalThis, JSC.ZigString.static("internal"), JSC.JSValue.jsBoolean(helpers.isLoopback(iface))); - - // scopeid The numeric IPv6 scope ID (only specified when family is IPv6) - if (addr.any.family == std.posix.AF.INET6) { - interface.put(globalThis, JSC.ZigString.static("scope_id"), JSC.JSValue.jsNumber(addr.in6.sa.scope_id)); - } - - // Does this entry already exist? - if (ret.get_unsafe(globalThis, interface_name)) |array| { - // Add this interface entry to the existing array - const next_index = @as(u32, @intCast(array.getLength(globalThis))); - array.putIndex(globalThis, next_index, interface); } else { - // Add it as an array with this interface as an element - const member_name = JSC.ZigString.init(interface_name); - var array = JSC.JSValue.createEmptyArray(globalThis, 1); - array.putIndex(globalThis, 0, interface); - ret.put(globalThis, &member_name, array); - } - } - - return ret; - } - - fn networkInterfacesWindows(globalThis: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { - var ifaces: [*]libuv.uv_interface_address_t = undefined; - var count: c_int = undefined; - const err = libuv.uv_interface_addresses(&ifaces, &count); - if (err != 0) { - const sys_err = JSC.SystemError{ - .message = bun.String.static("uv_interface_addresses failed"), - .code = bun.String.static("ERR_SYSTEM_ERROR"), - //.info = info, - .errno = err, - .syscall = bun.String.static("uv_interface_addresses"), - }; - return globalThis.throwValue(sys_err.toErrorInstance(globalThis)); - } - defer libuv.uv_free_interface_addresses(ifaces, count); - - var ret = JSC.JSValue.createEmptyObject(globalThis, 8); - - // 65 comes from: https://stackoverflow.com/questions/39443413/why-is-inet6-addrstrlen-defined-as-46-in-c - var ip_buf: [65]u8 = undefined; - var mac_buf: [17]u8 = undefined; - - for (ifaces[0..@intCast(count)]) |iface| { - var interface = JSC.JSValue.createEmptyObject(globalThis, 7); - - // address The assigned IPv4 or IPv6 address - // cidr The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. - var cidr = JSC.JSValue.null; - { - // Compute the CIDR suffix; returns null if the netmask cannot - // be converted to a CIDR suffix - const maybe_suffix: ?u8 = switch (iface.address.address4.family) { - std.posix.AF.INET => netmaskToCIDRSuffix(iface.netmask.netmask4.addr), - std.posix.AF.INET6 => netmaskToCIDRSuffix(@as(u128, @bitCast(iface.netmask.netmask6.addr))), - else => null, - }; - - // Format the address and then, if valid, the CIDR suffix; both - // the address and cidr values can be slices into this same buffer - // e.g. addr_str = "192.168.88.254", cidr_str = "192.168.88.254/24" - const addr_str = bun.fmt.formatIp( - // std.net.Address will do ptrCast depending on the family so this is ok - std.net.Address.initPosix(@ptrCast(&iface.address.address4)), - &ip_buf, - ) catch unreachable; - if (maybe_suffix) |suffix| { - //NOTE addr_str might not start at buf[0] due to slicing in formatIp - const start = @intFromPtr(addr_str.ptr) - @intFromPtr(&ip_buf[0]); - // Start writing the suffix immediately after the address - const suffix_str = std.fmt.bufPrint(ip_buf[start + addr_str.len ..], "/{}", .{suffix}) catch unreachable; - // The full cidr value is the address + the suffix - const cidr_str = ip_buf[start .. start + addr_str.len + suffix_str.len]; - cidr = JSC.ZigString.init(cidr_str).withEncoding().toJS(globalThis); - } - - interface.put(globalThis, JSC.ZigString.static("address"), JSC.ZigString.init(addr_str).withEncoding().toJS(globalThis)); - } - - // netmask - { - const str = bun.fmt.formatIp( - // std.net.Address will do ptrCast depending on the family so this is ok - std.net.Address.initPosix(@ptrCast(&iface.netmask.netmask4)), - &ip_buf, - ) catch unreachable; - interface.put(globalThis, JSC.ZigString.static("netmask"), JSC.ZigString.init(str).withEncoding().toJS(globalThis)); - } - // family - interface.put(globalThis, JSC.ZigString.static("family"), (switch (iface.address.address4.family) { - std.posix.AF.INET => JSC.ZigString.static("IPv4"), - std.posix.AF.INET6 => JSC.ZigString.static("IPv6"), - else => JSC.ZigString.static("unknown"), - }).toJS(globalThis)); - - // mac - { - const phys = iface.phys_addr; - const mac = std.fmt.bufPrint(&mac_buf, "{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}", .{ - phys[0], phys[1], phys[2], phys[3], phys[4], phys[5], - }) catch unreachable; + const mac = "00:00:00:00:00:00"; interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toJS(globalThis)); } - - // internal - { - interface.put(globalThis, JSC.ZigString.static("internal"), JSC.JSValue.jsBoolean(iface.is_internal != 0)); - } - - // cidr. this is here to keep ordering consistent with the node implementation - interface.put(globalThis, JSC.ZigString.static("cidr"), cidr); - - // scopeid - if (iface.address.address4.family == std.posix.AF.INET6) { - interface.put(globalThis, JSC.ZigString.static("scopeid"), JSC.JSValue.jsNumber(iface.address.address6.scope_id)); - } - - // Does this entry already exist? - const interface_name = bun.span(iface.name); - if (ret.get_unsafe(globalThis, interface_name)) |array| { - // Add this interface entry to the existing array - const next_index = @as(u32, @intCast(array.getLength(globalThis))); - array.putIndex(globalThis, next_index, interface); - } else { - // Add it as an array with this interface as an element - const member_name = JSC.ZigString.init(interface_name); - var array = JSC.JSValue.createEmptyArray(globalThis, 1); - array.putIndex(globalThis, 0, interface); - ret.put(globalThis, &member_name, array); - } } - return ret; - } + // internal true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false + interface.put(globalThis, JSC.ZigString.static("internal"), JSC.JSValue.jsBoolean(helpers.isLoopback(iface))); - pub fn platform(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - return JSC.ZigString.init(Global.os_name).withEncoding().toJS(globalThis); - } - - pub fn release(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; - return JSC.ZigString.init(C.getRelease(&name_buffer)).withEncoding().toJS(globalThis); - } - - pub fn setPriority(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - var args_ = callframe.arguments_old(2); - var arguments: []const JSC.JSValue = args_.ptr[0..args_.len]; - - if (arguments.len == 0) { - const err = JSC.toTypeError( - .ERR_INVALID_ARG_TYPE, - "The \"priority\" argument must be of type number. Received undefined", - .{}, - globalThis, - ); - return globalThis.throwValue(err); + // scopeid The numeric IPv6 scope ID (only specified when family is IPv6) + if (addr.any.family == std.posix.AF.INET6) { + interface.put(globalThis, JSC.ZigString.static("scope_id"), JSC.JSValue.jsNumber(addr.in6.sa.scope_id)); } - const pid = if (arguments.len == 2) arguments[0].coerce(i32, globalThis) else 0; - const priority = if (arguments.len == 2) arguments[1].coerce(i32, globalThis) else arguments[0].coerce(i32, globalThis); - - if (priority < -20 or priority > 19) { - const err = JSC.toTypeError( - .ERR_OUT_OF_RANGE, - "The value of \"priority\" is out of range. It must be >= -20 && <= 19", - .{}, - globalThis, - ); - return globalThis.throwValue(err); - } - - const errcode = C.setProcessPriority(pid, priority); - switch (errcode) { - .SRCH => { - const err = JSC.SystemError{ - .message = bun.String.static("A system error occurred: uv_os_setpriority returned ESRCH (no such process)"), - .code = bun.String.static(@tagName(.ERR_SYSTEM_ERROR)), - //.info = info, - .errno = -3, - .syscall = bun.String.static("uv_os_setpriority"), - }; - - return globalThis.throwValue(err.toErrorInstance(globalThis)); - }, - .ACCES => { - const err = JSC.SystemError{ - .message = bun.String.static("A system error occurred: uv_os_setpriority returned EACCESS (permission denied)"), - .code = bun.String.static(@tagName(.ERR_SYSTEM_ERROR)), - //.info = info, - .errno = -13, - .syscall = bun.String.static("uv_os_setpriority"), - }; - - return globalThis.throwValue(err.toErrorInstance(globalThis)); - }, - else => {}, - } - - return .undefined; - } - - pub fn totalmem(_: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - return JSC.JSValue.jsNumberFromUint64(C.getTotalMemory()); - } - - pub fn @"type"(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - - if (comptime Environment.isWindows) - return bun.String.static("Windows_NT").toJS(globalThis) - else if (comptime Environment.isMac) - return bun.String.static("Darwin").toJS(globalThis) - else if (comptime Environment.isLinux) - return bun.String.static("Linux").toJS(globalThis); - - return JSC.ZigString.init(Global.os_name).withEncoding().toJS(globalThis); - } - - pub fn uptime(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - if (Environment.isWindows) { - var uptime_value: f64 = undefined; - const err = libuv.uv_uptime(&uptime_value); - if (err != 0) { - const sys_err = JSC.SystemError{ - .message = bun.String.static("failed to get system uptime"), - .code = bun.String.static("ERR_SYSTEM_ERROR"), - .errno = err, - .syscall = bun.String.static("uv_uptime"), - }; - return globalThis.throwValue(sys_err.toErrorInstance(globalThis)); - } - return JSC.JSValue.jsNumber(uptime_value); - } - - return JSC.JSValue.jsNumberFromUint64(C.getSystemUptime()); - } - - pub fn userInfo(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { - const result = JSC.JSValue.createEmptyObject(globalThis, 5); - - result.put(globalThis, JSC.ZigString.static("homedir"), try homedir(globalThis, callframe)); - - if (comptime Environment.isWindows) { - result.put(globalThis, JSC.ZigString.static("username"), JSC.ZigString.init(bun.getenvZ("USERNAME") orelse "unknown").withEncoding().toJS(globalThis)); - result.put(globalThis, JSC.ZigString.static("uid"), JSC.JSValue.jsNumber(-1)); - result.put(globalThis, JSC.ZigString.static("gid"), JSC.JSValue.jsNumber(-1)); - result.put(globalThis, JSC.ZigString.static("shell"), JSC.JSValue.jsNull()); + // Does this entry already exist? + if (ret.get_unsafe(globalThis, interface_name)) |array| { + // Add this interface entry to the existing array + const next_index = @as(u32, @intCast(array.getLength(globalThis))); + array.putIndex(globalThis, next_index, interface); } else { - const username = bun.getenvZ("USER") orelse "unknown"; + // Add it as an array with this interface as an element + const member_name = JSC.ZigString.init(interface_name); + var array = JSC.JSValue.createEmptyArray(globalThis, 1); + array.putIndex(globalThis, 0, interface); + ret.put(globalThis, &member_name, array); + } + } - result.put(globalThis, JSC.ZigString.static("username"), JSC.ZigString.init(username).withEncoding().toJS(globalThis)); - result.put(globalThis, JSC.ZigString.static("shell"), JSC.ZigString.init(bun.getenvZ("SHELL") orelse "unknown").withEncoding().toJS(globalThis)); + return ret; +} - result.put(globalThis, JSC.ZigString.static("uid"), JSC.JSValue.jsNumber(C.getuid())); - result.put(globalThis, JSC.ZigString.static("gid"), JSC.JSValue.jsNumber(C.getgid())); +fn networkInterfacesWindows(globalThis: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { + var ifaces: [*]libuv.uv_interface_address_t = undefined; + var count: c_int = undefined; + const err = libuv.uv_interface_addresses(&ifaces, &count); + if (err != 0) { + const sys_err = JSC.SystemError{ + .message = bun.String.static("uv_interface_addresses failed"), + .code = bun.String.static("ERR_SYSTEM_ERROR"), + //.info = info, + .errno = err, + .syscall = bun.String.static("uv_interface_addresses"), + }; + return globalThis.throwValue(sys_err.toErrorInstance(globalThis)); + } + defer libuv.uv_free_interface_addresses(ifaces, count); + + var ret = JSC.JSValue.createEmptyObject(globalThis, 8); + + // 65 comes from: https://stackoverflow.com/questions/39443413/why-is-inet6-addrstrlen-defined-as-46-in-c + var ip_buf: [65]u8 = undefined; + var mac_buf: [17]u8 = undefined; + + for (ifaces[0..@intCast(count)]) |iface| { + var interface = JSC.JSValue.createEmptyObject(globalThis, 7); + + // address The assigned IPv4 or IPv6 address + // cidr The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. + var cidr = JSC.JSValue.null; + { + // Compute the CIDR suffix; returns null if the netmask cannot + // be converted to a CIDR suffix + const maybe_suffix: ?u8 = switch (iface.address.address4.family) { + std.posix.AF.INET => netmaskToCIDRSuffix(iface.netmask.netmask4.addr), + std.posix.AF.INET6 => netmaskToCIDRSuffix(@as(u128, @bitCast(iface.netmask.netmask6.addr))), + else => null, + }; + + // Format the address and then, if valid, the CIDR suffix; both + // the address and cidr values can be slices into this same buffer + // e.g. addr_str = "192.168.88.254", cidr_str = "192.168.88.254/24" + const addr_str = bun.fmt.formatIp( + // std.net.Address will do ptrCast depending on the family so this is ok + std.net.Address.initPosix(@ptrCast(&iface.address.address4)), + &ip_buf, + ) catch unreachable; + if (maybe_suffix) |suffix| { + //NOTE addr_str might not start at buf[0] due to slicing in formatIp + const start = @intFromPtr(addr_str.ptr) - @intFromPtr(&ip_buf[0]); + // Start writing the suffix immediately after the address + const suffix_str = std.fmt.bufPrint(ip_buf[start + addr_str.len ..], "/{}", .{suffix}) catch unreachable; + // The full cidr value is the address + the suffix + const cidr_str = ip_buf[start .. start + addr_str.len + suffix_str.len]; + cidr = JSC.ZigString.init(cidr_str).withEncoding().toJS(globalThis); + } + + interface.put(globalThis, JSC.ZigString.static("address"), JSC.ZigString.init(addr_str).withEncoding().toJS(globalThis)); } - return result; + // netmask + { + const str = bun.fmt.formatIp( + // std.net.Address will do ptrCast depending on the family so this is ok + std.net.Address.initPosix(@ptrCast(&iface.netmask.netmask4)), + &ip_buf, + ) catch unreachable; + interface.put(globalThis, JSC.ZigString.static("netmask"), JSC.ZigString.init(str).withEncoding().toJS(globalThis)); + } + // family + interface.put(globalThis, JSC.ZigString.static("family"), (switch (iface.address.address4.family) { + std.posix.AF.INET => JSC.ZigString.static("IPv4"), + std.posix.AF.INET6 => JSC.ZigString.static("IPv6"), + else => JSC.ZigString.static("unknown"), + }).toJS(globalThis)); + + // mac + { + const phys = iface.phys_addr; + const mac = std.fmt.bufPrint(&mac_buf, "{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}:{x:0>2}", .{ + phys[0], phys[1], phys[2], phys[3], phys[4], phys[5], + }) catch unreachable; + interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toJS(globalThis)); + } + + // internal + { + interface.put(globalThis, JSC.ZigString.static("internal"), JSC.JSValue.jsBoolean(iface.is_internal != 0)); + } + + // cidr. this is here to keep ordering consistent with the node implementation + interface.put(globalThis, JSC.ZigString.static("cidr"), cidr); + + // scopeid + if (iface.address.address4.family == std.posix.AF.INET6) { + interface.put(globalThis, JSC.ZigString.static("scopeid"), JSC.JSValue.jsNumber(iface.address.address6.scope_id)); + } + + // Does this entry already exist? + const interface_name = bun.span(iface.name); + if (ret.get_unsafe(globalThis, interface_name)) |array| { + // Add this interface entry to the existing array + const next_index = @as(u32, @intCast(array.getLength(globalThis))); + array.putIndex(globalThis, next_index, interface); + } else { + // Add it as an array with this interface as an element + const member_name = JSC.ZigString.init(interface_name); + var array = JSC.JSValue.createEmptyArray(globalThis, 1); + array.putIndex(globalThis, 0, interface); + ret.put(globalThis, &member_name, array); + } } - pub fn version(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; - return JSC.ZigString.init(C.getVersion(&name_buffer)).withEncoding().toJS(globalThis); + return ret; +} + +pub fn release() bun.String { + var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; + return bun.String.createUTF8(C.getRelease(&name_buffer)); +} + +pub fn setPriority1(global: *JSC.JSGlobalObject, pid: i32, priority: i32) !void { + const errcode = C.setProcessPriority(pid, priority); + switch (errcode) { + .SRCH => { + const err = JSC.SystemError{ + .message = bun.String.static("no such process"), + .code = bun.String.static("ESRCH"), + .errno = comptime switch (bun.Environment.os) { + else => -@as(c_int, @intFromEnum(std.posix.E.SRCH)), + .windows => libuv.UV_ESRCH, + }, + .syscall = bun.String.static("uv_os_getpriority"), + }; + return global.throwValue(err.toErrorInstanceWithInfoObject(global)); + }, + .ACCES => { + const err = JSC.SystemError{ + .message = bun.String.static("permission denied"), + .code = bun.String.static("EACCES"), + .errno = comptime switch (bun.Environment.os) { + else => -@as(c_int, @intFromEnum(std.posix.E.ACCES)), + .windows => libuv.UV_EACCES, + }, + .syscall = bun.String.static("uv_os_getpriority"), + }; + return global.throwValue(err.toErrorInstanceWithInfoObject(global)); + }, + .PERM => { + const err = JSC.SystemError{ + .message = bun.String.static("operation not permitted"), + .code = bun.String.static("EPERM"), + .errno = comptime switch (bun.Environment.os) { + else => -@as(c_int, @intFromEnum(std.posix.E.SRCH)), + .windows => libuv.UV_ESRCH, + }, + .syscall = bun.String.static("uv_os_getpriority"), + }; + return global.throwValue(err.toErrorInstanceWithInfoObject(global)); + }, + else => { + // no other error codes can be emitted + }, + } +} + +pub fn setPriority2(global: *JSC.JSGlobalObject, priority: i32) !void { + return setPriority1(global, 0, priority); +} + +pub fn totalmem() u64 { + return C.getTotalMemory(); +} + +pub fn uptime(global: *JSC.JSGlobalObject) bun.JSError!f64 { + if (Environment.isWindows) { + var uptime_value: f64 = undefined; + const err = libuv.uv_uptime(&uptime_value); + if (err != 0) { + const sys_err = JSC.SystemError{ + .message = bun.String.static("failed to get system uptime"), + .code = bun.String.static("ERR_SYSTEM_ERROR"), + .errno = err, + .syscall = bun.String.static("uv_uptime"), + }; + return global.throwValue(sys_err.toErrorInstance(global)); + } + return uptime_value; } - inline fn getMachineName() [:0]const u8 { - return switch (@import("builtin").target.cpu.arch) { - .arm => "arm", - .aarch64 => "arm64", - .mips => "mips", - .mips64 => "mips64", - .powerpc64 => "ppc64", - .powerpc64le => "ppc64le", - .s390x => "s390x", - .x86 => "i386", - .x86_64 => "x86_64", - else => "unknown", - }; + return @floatFromInt(C.getSystemUptime()); +} + +pub fn userInfo(globalThis: *JSC.JSGlobalObject, options: gen.UserInfoOptions) bun.JSError!JSC.JSValue { + _ = options; // TODO: + + const result = JSC.JSValue.createEmptyObject(globalThis, 5); + + const home = try homedir(globalThis); + defer home.deref(); + + result.put(globalThis, JSC.ZigString.static("homedir"), home.toJS(globalThis)); + + if (comptime Environment.isWindows) { + result.put(globalThis, JSC.ZigString.static("username"), JSC.ZigString.init(bun.getenvZ("USERNAME") orelse "unknown").withEncoding().toJS(globalThis)); + result.put(globalThis, JSC.ZigString.static("uid"), JSC.JSValue.jsNumber(-1)); + result.put(globalThis, JSC.ZigString.static("gid"), JSC.JSValue.jsNumber(-1)); + result.put(globalThis, JSC.ZigString.static("shell"), JSC.JSValue.jsNull()); + } else { + const username = bun.getenvZ("USER") orelse "unknown"; + + result.put(globalThis, JSC.ZigString.static("username"), JSC.ZigString.init(username).withEncoding().toJS(globalThis)); + result.put(globalThis, JSC.ZigString.static("shell"), JSC.ZigString.init(bun.getenvZ("SHELL") orelse "unknown").withEncoding().toJS(globalThis)); + result.put(globalThis, JSC.ZigString.static("uid"), JSC.JSValue.jsNumber(C.getuid())); + result.put(globalThis, JSC.ZigString.static("gid"), JSC.JSValue.jsNumber(C.getgid())); } - pub fn machine(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JSError!JSC.JSValue { - JSC.markBinding(@src()); - return JSC.ZigString.static(comptime getMachineName()).toJS(globalThis); - } -}; + return result; +} + +pub fn version() bun.JSError!bun.String { + var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; + return bun.String.createUTF8(C.getVersion(&name_buffer)); +} /// Given a netmask returns a CIDR suffix. Returns null if the mask is not valid. /// `@TypeOf(mask)` must be one of u32 (IPv4) or u128 (IPv6) diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index c664c48954..5a2730770e 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -1726,7 +1726,7 @@ pub fn StatType(comptime Big: bool) type { } // dev, mode, nlink, uid, gid, rdev, blksize, ino, size, blocks, atimeMs, mtimeMs, ctimeMs, birthtimeMs - var args = callFrame.argumentsPtr()[0..@min(callFrame.argumentsCount(), 14)]; + var args = callFrame.arguments(); const atime_ms: f64 = if (args.len > 10 and args[10].isNumber()) args[10].asNumber() else 0; const mtime_ms: f64 = if (args.len > 11 and args[11].isNumber()) args[11].asNumber() else 0; diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index e09000c7b0..d16b4e4be9 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -4161,7 +4161,7 @@ pub const Expect = struct { JSC.markBinding(@src()); const thisValue = callframe.this(); - const arguments = callframe.argumentsPtr()[0..callframe.argumentsCount()]; + const arguments = callframe.arguments(); defer this.postMatch(globalThis); const value: JSValue = try this.getValue(globalThis, thisValue, "toHaveBeenCalledWith", "expected"); @@ -4220,7 +4220,7 @@ pub const Expect = struct { JSC.markBinding(@src()); const thisValue = callframe.this(); - const arguments = callframe.argumentsPtr()[0..callframe.argumentsCount()]; + const arguments = callframe.arguments(); defer this.postMatch(globalThis); const value: JSValue = try this.getValue(globalThis, thisValue, "toHaveBeenLastCalledWith", "expected"); @@ -4278,7 +4278,7 @@ pub const Expect = struct { JSC.markBinding(@src()); const thisValue = callframe.this(); - const arguments = callframe.argumentsPtr()[0..callframe.argumentsCount()]; + const arguments = callframe.arguments(); defer this.postMatch(globalThis); const value: JSValue = try this.getValue(globalThis, thisValue, "toHaveBeenNthCalledWith", "expected"); @@ -4721,12 +4721,11 @@ pub const Expect = struct { incrementExpectCallCounter(); // prepare the args array - const args_ptr = callFrame.argumentsPtr(); - const args_count = callFrame.argumentsCount(); + const args = callFrame.arguments(); var allocator = std.heap.stackFallback(8 * @sizeOf(JSValue), globalThis.allocator()); - var matcher_args = try std.ArrayList(JSValue).initCapacity(allocator.get(), args_count + 1); + var matcher_args = try std.ArrayList(JSValue).initCapacity(allocator.get(), args.len + 1); matcher_args.appendAssumeCapacity(value); - for (0..args_count) |i| matcher_args.appendAssumeCapacity(args_ptr[i]); + for (args) |arg| matcher_args.appendAssumeCapacity(arg); _ = try executeCustomMatcher(globalThis, matcher_name, matcher_fn, matcher_args.items, expect.flags, false); @@ -5202,14 +5201,13 @@ pub const ExpectCustomAsymmetricMatcher = struct { ExpectCustomAsymmetricMatcher.matcherFnSetCached(instance_jsvalue, globalThis, matcher_fn); // capture the args as a JS array saved in the instance, so the matcher can be executed later on with them - const args_ptr = callFrame.argumentsPtr(); - const args_count: usize = callFrame.argumentsCount(); - var args = JSValue.createEmptyArray(globalThis, args_count); - for (0..args_count) |i| { - args.putIndex(globalThis, @truncate(i), args_ptr[i]); + const args = callFrame.arguments(); + const array = JSValue.createEmptyArray(globalThis, args.len); + for (args, 0..) |arg, i| { + array.putIndex(globalThis, @truncate(i), arg); } - args.ensureStillAlive(); - ExpectCustomAsymmetricMatcher.capturedArgsSetCached(instance_jsvalue, globalThis, args); + ExpectCustomAsymmetricMatcher.capturedArgsSetCached(instance_jsvalue, globalThis, array); + array.ensureStillAlive(); // return the same instance, now fully initialized including the captured args (previously it was incomplete) return instance_jsvalue; diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index c03935eecb..b708cc6810 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -3909,7 +3909,7 @@ pub const ParseTask = struct { result: ?*OnBeforeParseResult = null, - const headers = @import("bun-native-bundler-plugin-api"); + const headers = bun.C.translated; comptime { bun.assert(@sizeOf(OnBeforeParseArguments) == @sizeOf(headers.OnBeforeParseArguments)); diff --git a/src/c-headers-for-zig.h b/src/c-headers-for-zig.h new file mode 100644 index 0000000000..42c03aca64 --- /dev/null +++ b/src/c-headers-for-zig.h @@ -0,0 +1,21 @@ +// This file is run through translate-c and exposed to Zig code +// under the namespace bun.C.translated. Prefer adding includes +// to this file instead of manually porting struct definitions +// into Zig code. By using automatic translation, differences +// in platforms can be avoided. +// +// When Zig is translating this file, it will define these macros: +// - WINDOWS +// - DARWIN +// - LINUX +// - POSIX + +// OnBeforeParseResult, etc... +#include "../packages/bun-native-bundler-plugin-api/bundler_plugin.h" + +#if POSIX +// passwd, getpwuid_r +#include "pwd.h" +// geteuid +#include +#endif diff --git a/src/c.zig b/src/c.zig index e0b8238fca..4b70e7c3fc 100644 --- a/src/c.zig +++ b/src/c.zig @@ -2,6 +2,8 @@ const std = @import("std"); const bun = @import("root").bun; const Environment = @import("./env.zig"); +pub const translated = @import("translated-c-headers"); + const PlatformSpecific = switch (Environment.os) { .mac => @import("./darwin_c.zig"), .linux => @import("./linux_c.zig"), @@ -44,7 +46,7 @@ pub extern "c" fn strchr(str: [*]const u8, char: u8) ?[*]const u8; pub fn lstat_absolute(path: [:0]const u8) !Stat { if (builtin.os.tag == .windows) { - @compileError("Not implemented yet, conside using bun.sys.lstat()"); + @compileError("Not implemented yet, consider using bun.sys.lstat()"); } var st = zeroes(libc_stat); @@ -341,8 +343,8 @@ pub fn getSelfExeSharedLibPaths(allocator: std.mem.Allocator) error{OutOfMemory} /// Same as MADV_DONTNEED but used with posix_madvise() sys-tem system /// tem call. /// -/// MADV_FREE Indicates that the application will not need the infor-mation information -/// mation contained in this address range, so the pages may +/// MADV_FREE Indicates that the application will not need the information +/// contained in this address range, so the pages may /// be reused right away. The address range will remain /// valid. This is used with madvise() system call. /// @@ -350,16 +352,8 @@ pub fn getSelfExeSharedLibPaths(allocator: std.mem.Allocator) error{OutOfMemory} /// with POSIX_ prefix for the advice system call argument. pub extern "c" fn posix_madvise(ptr: *anyopaque, len: usize, advice: i32) c_int; -pub fn getProcessPriority(pid_: i32) i32 { - const pid = @as(c_uint, @intCast(pid_)); - return get_process_priority(pid); -} - -pub fn setProcessPriority(pid_: i32, priority_: i32) std.c.E { - if (pid_ < 0) return .SRCH; - - const pid = @as(c_uint, @intCast(pid_)); - const priority = @as(c_int, @intCast(priority_)); +pub fn setProcessPriority(pid: i32, priority: i32) std.c.E { + if (pid < 0) return .SRCH; const code: i32 = set_process_priority(pid, priority); @@ -468,9 +462,18 @@ pub fn dlsym(comptime Type: type, comptime name: [:0]const u8) ?Type { return dlsymWithHandle(Type, name, handle_getter); } +/// Error condition is encoded as null +/// The only error in this function is ESRCH (no process found) +pub fn getProcessPriority(pid: i32) ?i32 { + return switch (get_process_priority(pid)) { + std.math.maxInt(i32) => null, + else => |prio| prio, + }; +} + // set in c-bindings.cpp -pub extern fn get_process_priority(pid: c_uint) i32; -pub extern fn set_process_priority(pid: c_uint, priority: c_int) i32; +extern fn get_process_priority(pid: i32) i32; +pub extern fn set_process_priority(pid: i32, priority: i32) i32; pub extern fn strncasecmp(s1: [*]const u8, s2: [*]const u8, n: usize) i32; pub extern fn memmove(dest: [*]u8, src: [*]const u8, n: usize) void; @@ -493,3 +496,7 @@ pub extern "C" fn bun_restore_stdio() void; pub extern "C" fn open_as_nonblocking_tty(i32, i32) i32; pub extern fn strlen(ptr: [*c]const u8) usize; + +pub const passwd = translated.passwd; +pub const geteuid = translated.geteuid; +pub const getpwuid_r = translated.getpwuid_r; diff --git a/src/codegen/bindgen-lib-internal.ts b/src/codegen/bindgen-lib-internal.ts index 3a47ad6663..7c4ee555fa 100644 --- a/src/codegen/bindgen-lib-internal.ts +++ b/src/codegen/bindgen-lib-internal.ts @@ -47,6 +47,8 @@ export const extJsFunction = (namespaceVar: string, fnLabel: string) => /** Each variant gets a dispatcher function. */ export const extDispatchVariant = (namespaceVar: string, fnLabel: string, variantNumber: number) => `bindgen_${cap(namespaceVar)}_dispatch${cap(fnLabel)}${variantNumber}`; +export const extInternalDispatchVariant = (namespaceVar: string, fnLabel: string, variantNumber: string | number) => + `bindgen_${cap(namespaceVar)}_js${cap(fnLabel)}_v${variantNumber}`; interface TypeDataDefs { /** The name */ @@ -70,12 +72,18 @@ interface TypeDataDefs { } type TypeData = K extends keyof TypeDataDefs ? TypeDataDefs[K] : any; +export const enum NodeValidator { + validateInteger = "validateInteger", +} + interface Flags { + nodeValidator?: NodeValidator; optional?: boolean; required?: boolean; - nullable?: boolean; + nonNull?: boolean; default?: any; range?: ["clamp" | "enforce", bigint, bigint] | ["clamp" | "enforce", "abi", "abi"]; + finite?: boolean; } export interface DictionaryField { @@ -85,6 +93,8 @@ export interface DictionaryField { export declare const isType: unique symbol; +const numericTypes = new Set(["f64", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "usize"]); + /** * Implementation of the Type interface. All types are immutable and hashable. * Hashes de-duplicate structure and union definitions. Flags do not account for @@ -263,7 +273,7 @@ export class TypeImpl { } cppClassName() { - assert(this.lowersToNamedType()); + assert(this.lowersToNamedType(), `Does not lower to named type: ${inspect(this)}`); const name = this.name(); const namespace = typeHashToNamespace.get(this.hash()); return namespace ? `${namespace}::${cap(name)}` : name; @@ -327,48 +337,6 @@ export class TypeImpl { } } - // Interface definition API - get optional() { - if (this.flags.required) { - throw new Error("Cannot derive optional on a required type"); - } - if (this.flags.default) { - throw new Error("Cannot derive optional on a something with a default value (default implies optional)"); - } - return new TypeImpl(this.kind, this.data, { - ...this.flags, - optional: true, - }); - } - - get nullable() { - return new TypeImpl(this.kind, this.data, { - ...this.flags, - nullable: true, - }); - } - - get required() { - if (this.flags.required) { - throw new Error("This type already has required set"); - } - if (this.flags.required) { - throw new Error("Cannot derive required on an optional type"); - } - return new TypeImpl(this.kind, this.data, { - ...this.flags, - required: true, - }); - } - - clamp(min?: number | bigint, max?: number | bigint) { - return this.#rangeModifier(min, max, "clamp"); - } - - enforceRange(min?: number | bigint, max?: number | bigint) { - return this.#rangeModifier(min, max, "enforce"); - } - #rangeModifier(min: undefined | number | bigint, max: undefined | number | bigint, kind: "clamp" | "enforce") { if (this.flags.range) { throw new Error("This type already has a range modifier set"); @@ -467,6 +435,9 @@ export class TypeImpl { } } break; + case "undefined": + assert(value === undefined, `Expected undefined, got ${inspect(value)}`); + break; default: throw new Error(`TODO: set default value on type ${this.kind}`); } @@ -515,6 +486,8 @@ export class TypeImpl { throw new Error(`TODO: non-empty string default`); } break; + case "undefined": + throw new Error("Zero-sized type"); default: throw new Error(`TODO: set default value on type ${this.kind}`); } @@ -527,25 +500,31 @@ export class TypeImpl { throw new Error("TODO: generate non-extern struct for representing this data type"); } - default(def: any) { - if ("default" in this.flags) { - throw new Error("This type already has a default value"); - } - if (this.flags.required) { - throw new Error("Cannot derive default on a required type"); - } - this.assertDefaultIsValid(def); - return new TypeImpl(this.kind, this.data, { - ...this.flags, - default: def, - }); + isIgnoredUndefinedType() { + return this.kind === "undefined"; + } + + isStringType() { + return ( + this.kind === "DOMString" || this.kind === "ByteString" || this.kind === "USVString" || this.kind === "UTF8String" + ); + } + + isNumberType() { + return numericTypes.has(this.kind); + } + + isObjectType() { + return this.kind === "externalClass" || this.kind === "dictionary"; } [Symbol.toStringTag] = "Type"; [Bun.inspect.custom](depth, options, inspect) { return ( `${options.stylize("Type", "special")} ${ - this.nameDeduplicated ? options.stylize(JSON.stringify(this.nameDeduplicated), "string") + " " : "" + this.lowersToNamedType() && this.nameDeduplicated + ? options.stylize(JSON.stringify(this.nameDeduplicated), "string") + " " + : "" }${options.stylize( `[${this.kind}${["required", "optional", "nullable"] .filter(k => this.flags[k]) @@ -562,9 +541,105 @@ export class TypeImpl { : "") ); } + + // Public interface definition API + get optional() { + if (this.flags.required) { + throw new Error("Cannot derive optional on a required type"); + } + if (this.flags.default) { + throw new Error("Cannot derive optional on a something with a default value (default implies optional)"); + } + return new TypeImpl(this.kind, this.data, { + ...this.flags, + optional: true, + }); + } + + get finite() { + if (this.kind !== "f64") { + throw new Error("finite can only be used on f64"); + } + if (this.flags.finite) { + throw new Error("This type already has finite set"); + } + return new TypeImpl(this.kind, this.data, { + ...this.flags, + finite: true, + }); + } + + get required() { + if (this.flags.required) { + throw new Error("This type already has required set"); + } + if (this.flags.required) { + throw new Error("Cannot derive required on an optional type"); + } + return new TypeImpl(this.kind, this.data, { + ...this.flags, + required: true, + }); + } + + default(def: any) { + if ("default" in this.flags) { + throw new Error("This type already has a default value"); + } + if (this.flags.required) { + throw new Error("Cannot derive default on a required type"); + } + this.assertDefaultIsValid(def); + return new TypeImpl(this.kind, this.data, { + ...this.flags, + default: def, + }); + } + + clamp(min?: number | bigint, max?: number | bigint) { + return this.#rangeModifier(min, max, "clamp"); + } + + enforceRange(min?: number | bigint, max?: number | bigint) { + return this.#rangeModifier(min, max, "enforce"); + } + + get nonNull() { + if (this.flags.nonNull) { + throw new Error("Cannot derive nonNull on a nonNull type"); + } + return new TypeImpl(this.kind, this.data, { + ...this.flags, + nonNull: true, + }); + } + + validateInt32(min?: number, max?: number) { + if (this.kind !== "i32") { + throw new Error("validateInt32 can only be used on i32 or u32"); + } + const rangeInfo = cAbiIntegerLimits("i32"); + return this.validateInteger(min ?? rangeInfo[0], max ?? rangeInfo[1]); + } + + validateUint32(min?: number, max?: number) { + if (this.kind !== "u32") { + throw new Error("validateUint32 can only be used on i32 or u32"); + } + const rangeInfo = cAbiIntegerLimits("u32"); + return this.validateInteger(min ?? rangeInfo[0], max ?? rangeInfo[1]); + } + + validateInteger(min?: number | bigint, max?: number | bigint) { + min ??= Number.MIN_SAFE_INTEGER; + max ??= Number.MAX_SAFE_INTEGER; + const enforceRange = this.#rangeModifier(min, max, "enforce") as TypeImpl; + enforceRange.flags.nodeValidator = NodeValidator.validateInteger; + return enforceRange; + } } -function cAbiIntegerLimits(type: CAbiType) { +export function cAbiIntegerLimits(type: CAbiType) { switch (type) { case "u8": return [0, 255]; @@ -584,6 +659,8 @@ function cAbiIntegerLimits(type: CAbiType) { return [-2147483648, 2147483647]; case "i64": return [-9223372036854775808n, 9223372036854775807n]; + case "f64": + return [-Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]; default: throw new Error(`Unexpected type ${type}`); } @@ -603,9 +680,6 @@ export function oneOfImpl(types: TypeImpl[]): TypeImpl { if (type.kind === "oneOf") { out.push(...type.data); } else { - if (type.flags.nullable) { - throw new Error("Union type cannot include nullable"); - } if (type.flags.default) { throw new Error( "Union type cannot include a default value. Instead, set a default value on the union type itself", @@ -711,6 +785,8 @@ export type ArgStrategyChildItem = export type ReturnStrategy = // JSValue is special cased because it encodes exception as 0x0 | { type: "jsvalue" } + // Return value doesnt exist. function returns a boolean indicating success/error. + | { type: "void" } // For primitives and simple structures where direct assignment into a // pointer is possible. function returns a boolean indicating success/error. | { type: "basic-out-param"; abiType: CAbiType }; @@ -741,7 +817,8 @@ export function registerFunction(opts: FuncOptions) { for (const variant of opts.variants) { const { minRequiredArgs } = validateVariant(variant); variants.push({ - ...variant, + args: Object.entries(variant.args).map(([name, type]) => ({ name, type })) as Arg[], + ret: variant.ret as TypeImpl, suffix: `${i}`, minRequiredArgs, } as unknown as Variant); diff --git a/src/codegen/bindgen-lib.ts b/src/codegen/bindgen-lib.ts index 2ef06e92ed..483e6d2531 100644 --- a/src/codegen/bindgen-lib.ts +++ b/src/codegen/bindgen-lib.ts @@ -10,43 +10,107 @@ import { isFunc, } from "./bindgen-lib-internal"; -export type Type = { - [isType]: true | [T, K, Flags]; -} & (Flags extends null - ? { - /** - * Optional means the value may be omitted from a parameter definition. - * Parameters are required by default. - */ - optional: Type; - /** - * When this is used as a dictionary value, this makes that parameter - * required. Dictionary entries are optional by default. - */ - required: Type, K, false>; +/** A type definition for argument parsing. See `bindgen.md` for usage details. */ +export type Type< + /** T = JavaScript type that the Type represents */ + T, + /** K = "kind" a string pertaining to the `t.` that created this type. affects method listing */ + K extends TypeKind = TypeKind, + /** F = "flags" defining if the value is optional. null = not set, false = required, true = optional. */ + F extends TypeFlag = null, +> = F extends null + ? Props + : F extends true + ? { + [isType]: true | [T, K, F]; + nonNull: Type; + } + : { [isType]: true | [T, K, F] }; - /** Implies `optional`, this sets a default value if omitted */ - default(def: T): Type; - } & (K extends IntegerTypeKind - ? { - /** - * Applies [Clamp] semantics - * https://webidl.spec.whatwg.org/#Clamp - * If a custom numeric range is provided, it will be used instead of the built-in clamp rules. - */ - clamp(min?: T, max?: T): Type; - /** - * Applies [EnforceRange] semantics - * https://webidl.spec.whatwg.org/#EnforceRange - * If a custom numeric range is provided, it will be used instead of the built-in enforce rules. - */ - enforceRange(min?: T, max?: T): Type; - } - : {}) - : {}); +type TypeFlag = boolean | "opt-nonnull" | null; + +interface BaseTypeProps { + [isType]: true | [T, K]; + /** + * Optional means the value may be omitted from a parameter definition. + * Parameters are required by default. + */ + optional: Type; + /** + * When this is used as a dictionary value, this makes that parameter + * required. Dictionary entries are optional by default. + */ + required: Type, K, false>; + + /** Implies `optional`, this sets a default value if omitted */ + default(def: T): Type; +} + +interface NumericTypeProps extends BaseTypeProps { + /** + * Applies [Clamp] semantics + * https://webidl.spec.whatwg.org/#Clamp + * If a custom numeric range is provided, it will be used instead of the built-in clamp rules. + */ + clamp(min?: T, max?: T): Type; + /** + * Applies [EnforceRange] semantics + * https://webidl.spec.whatwg.org/#EnforceRange + * If a custom numeric range is provided, it will be used instead of the built-in enforce rules. + */ + enforceRange(min?: T, max?: T): Type; + + /** + * Equivalent to calling Node.js' `validateInteger(val, prop, min, max)` + */ + validateInteger(min?: T, max?: T): Type; +} + +interface I32TypeProps extends NumericTypeProps { + /** + * Equivalent to calling Node.js' `validateInt32(val, prop, min, max)` + */ + validateInt32(min?: number, max?: number): Type; +} + +interface U32TypeProps extends NumericTypeProps { + /** + * Equivalent to calling Node.js' `validateUint32(val, prop, min, max)` + */ + validateUint32(min?: number, max?: number): Type; +} + +interface F64TypeProps extends NumericTypeProps { + /** + * Throws an error if the input is non-finite (NaN, ±Infinity) + */ + finite: Type; + /** + * Equivalent to calling Node.js' `validateNumber(val, prop, min, max)` + */ + validateNumber(min?: number, max?: number): Type; +} + +// If an entry does not exist, then `BaseTypeProps` is assumed. +// T = JavaScript type that the Type represents +interface TypePropsMap { + // Integer types are always numbers, so T is not passed + ["u8"]: NumericTypeProps; + ["i8"]: NumericTypeProps; + ["u16"]: NumericTypeProps; + ["i16"]: NumericTypeProps; + ["u32"]: U32TypeProps; + ["i32"]: I32TypeProps; + ["u64"]: NumericTypeProps; + ["i64"]: NumericTypeProps; + // F64 is always a number, so T is not passed. + ["f64"]: F64TypeProps; +} + +type PropertyMapKeys = keyof TypePropsMap; +type Props = K extends PropertyMapKeys ? TypePropsMap[K] : BaseTypeProps; export type AcceptedDictionaryTypeKind = Exclude; -export type IntegerTypeKind = "usize" | "i32" | "i64" | "u32" | "u64" | "i8" | "u8" | "i16" | "u16"; function builtinType() { return (kind: K) => new TypeImpl(kind, undefined as any, {}) as Type as Type; @@ -78,6 +142,10 @@ export namespace t { /** Throws if the value is not a boolean. */ export const strictBoolean = builtinType()("strictBoolean"); + /** + * Equivalent to IDL's `unrestricted double`, allowing NaN and Infinity. + * To restrict to finite values, use `f64.finite`. + */ export const f64 = builtinType()("f64"); export const u8 = builtinType()("u8"); diff --git a/src/codegen/bindgen.ts b/src/codegen/bindgen.ts index ef6d870908..f9f9d5e402 100644 --- a/src/codegen/bindgen.ts +++ b/src/codegen/bindgen.ts @@ -7,7 +7,6 @@ import * as path from "node:path"; import { CodeWriter, TypeImpl, - cAbiTypeInfo, cAbiTypeName, cap, extDispatchVariant, @@ -31,10 +30,12 @@ import { alignForward, isFunc, Func, + NodeValidator, + cAbiIntegerLimits, + extInternalDispatchVariant, } from "./bindgen-lib-internal"; import assert from "node:assert"; import { argParse, readdirRecursiveWithExclusionsAndExtensionsSync, writeIfNotChanged } from "./helpers"; -import { type IntegerTypeKind } from "bindgen"; // arg parsing let { "codegen-root": codegenRoot, debug } = argParse(["codegen-root", "debug"]); @@ -54,7 +55,7 @@ function resolveVariantStrategies(vari: Variant, name: string) { argIndex += 1; // If `extern struct` can represent this type, that is the simplest way to cross the C-ABI boundary. - const isNullable = (arg.type.flags.optional && !("default" in arg.type.flags)) || arg.type.flags.nullable; + const isNullable = arg.type.flags.optional && !("default" in arg.type.flags); const abiType = !isNullable && arg.type.canDirectlyMapToCAbi(); if (abiType) { arg.loweringStrategy = { @@ -85,6 +86,10 @@ function resolveVariantStrategies(vari: Variant, name: string) { } return_strategy: { + if (vari.ret.kind === "undefined") { + vari.returnStrategy = { type: "void" }; + break return_strategy; + } if (vari.ret.kind === "any") { vari.returnStrategy = { type: "jsvalue" }; break return_strategy; @@ -109,7 +114,7 @@ function resolveNullableArgumentStrategy( prefix: string, communicationStruct: Struct, ): ArgStrategyChildItem[] { - assert((type.flags.optional && !("default" in type.flags)) || type.flags.nullable); + assert(type.flags.optional && !("default" in type.flags)); communicationStruct.add(`${prefix}Set`, "bool"); return resolveComplexArgumentStrategy(type, `${prefix}Value`, communicationStruct); } @@ -155,6 +160,10 @@ function emitCppCallToVariant(name: string, variant: Variant, dispatchFunctionNa for (const arg of variant.args) { const type = arg.type; if (type.isVirtualArgument()) continue; + if (type.isIgnoredUndefinedType()) { + i += 1; + continue; + } const exceptionContext: ExceptionContext = { type: "argument", @@ -187,21 +196,22 @@ function emitCppCallToVariant(name: string, variant: Variant, dispatchFunctionNa const jsValueRef = `arg${i}.value()`; /** If JavaScript may pass null or undefined */ - const isOptionalToUser = type.flags.nullable || type.flags.optional || "default" in type.flags; + const isOptionalToUser = type.flags.optional || "default" in type.flags; /** If the final representation may include null */ - const isNullable = type.flags.nullable || (type.flags.optional && !("default" in type.flags)); + const isNullable = type.flags.optional && !("default" in type.flags); if (isOptionalToUser) { if (needDeclare) { addHeaderForType(type); cpp.line(`${type.cppName()} ${storageLocation};`); } + const isUndefinedOrNull = type.flags.nonNull ? "isUndefined" : "isUndefinedOrNull"; if (isNullable) { assert(strategy.type === "uses-communication-buffer"); - cpp.line(`if ((${storageLocation}Set = !${jsValueRef}.isUndefinedOrNull())) {`); + cpp.line(`if ((${storageLocation}Set = !${jsValueRef}.${isUndefinedOrNull}())) {`); storageLocation = `${storageLocation}Value`; } else { - cpp.line(`if (!${jsValueRef}.isUndefinedOrNull()) {`); + cpp.line(`if (!${jsValueRef}.${isUndefinedOrNull}()) {`); } cpp.indent(); emitConvertValue(storageLocation, arg.type, jsValueRef, exceptionContext, "assign"); @@ -233,6 +243,9 @@ function emitCppCallToVariant(name: string, variant: Variant, dispatchFunctionNa cpp.line(`${cAbiTypeName(returnStrategy.abiType)} out;`); cpp.line(`if (!${dispatchFunctionName}(`); break; + case "void": + cpp.line(`if (!${dispatchFunctionName}(`); + break; default: throw new Error(`TODO: emitCppCallToVariant for ${inspect(returnStrategy)}`); } @@ -257,6 +270,8 @@ function emitCppCallToVariant(name: string, variant: Variant, dispatchFunctionNa for (const arg of variant.args) { i += 1; + if (arg.type.isIgnoredUndefinedType()) continue; + if (arg.type.isVirtualArgument()) { switch (arg.type.kind) { case "zigVirtualMachine": @@ -300,6 +315,13 @@ function emitCppCallToVariant(name: string, variant: Variant, dispatchFunctionNa } cpp.line(");"); break; + case "void": + cpp.dedent(); + cpp.line(")) {"); + cpp.line(` return {};`); + cpp.line("}"); + cpp.line("return JSC::JSValue::encode(JSC::jsUndefined());"); + break; case "basic-out-param": addCommaAfterArgument(); cpp.add("&out"); @@ -335,7 +357,6 @@ function getSimpleIdlType(type: TypeImpl): string | undefined { const map: { [K in TypeKind]?: string } = { boolean: "WebCore::IDLBoolean", undefined: "WebCore::IDLUndefined", - f64: "WebCore::IDLDouble", usize: "WebCore::IDLUnsignedLongLong", u8: "WebCore::IDLOctet", u16: "WebCore::IDLUnsignedShort", @@ -349,6 +370,11 @@ function getSimpleIdlType(type: TypeImpl): string | undefined { let entry = map[type.kind]; if (!entry) { switch (type.kind) { + case "f64": + entry = type.flags.finite // + ? "WebCore::IDLDouble" + : "WebCore::IDLUnrestrictedDouble"; + break; case "stringEnum": type.lowersToNamedType; // const cType = cAbiTypeForEnum(type.data.length); @@ -361,14 +387,27 @@ function getSimpleIdlType(type: TypeImpl): string | undefined { } if (type.flags.range) { - // TODO: when enforceRange is used, a custom adaptor should be used instead - // of chaining both `WebCore::IDLEnforceRangeAdaptor` and custom logic. - const rangeAdaptor = { - "clamp": "WebCore::IDLClampAdaptor", - "enforce": "WebCore::IDLEnforceRangeAdaptor", - }[type.flags.range[0]]; - assert(rangeAdaptor); - entry = `${rangeAdaptor}<${entry}>`; + const { range, nodeValidator } = type.flags; + if ((range[0] === "enforce" && range[1] !== "abi") || nodeValidator) { + if (nodeValidator) assert(nodeValidator === NodeValidator.validateInteger); // TODO? + + const [abiMin, abiMax] = cAbiIntegerLimits(type.kind as CAbiType); + let [_, min, max] = range as [string, bigint | number | "abi", bigint | number | "abi"]; + if (min === "abi") min = abiMin; + if (max === "abi") max = abiMax; + + headers.add("BindgenCustomEnforceRange.h"); + entry = `Bun::BindgenCustomEnforceRange<${cAbiTypeName(type.kind as CAbiType)}, ${min}, ${max}, Bun::BindgenCustomEnforceRangeKind::${ + nodeValidator ? "Node" : "Web" + }>`; + } else { + const rangeAdaptor = { + "clamp": "WebCore::IDLClampAdaptor", + "enforce": "WebCore::IDLEnforceRangeAdaptor", + }[range[0]]; + assert(rangeAdaptor); + entry = `${rangeAdaptor}<${entry}>`; + } } return entry; @@ -393,29 +432,30 @@ function emitConvertValue( if (simpleType) { const cAbiType = type.canDirectlyMapToCAbi(); assert(cAbiType); - let exceptionHandlerBody; + let exceptionHandler: ExceptionHandler | undefined; + switch (exceptionContext.type) { + case "none": + break; + case "argument": + exceptionHandler = getArgumentExceptionHandler( + type, + exceptionContext.argumentIndex, + exceptionContext.name, + exceptionContext.functionName, + ); + } switch (type.kind) { - case "zigEnum": - case "stringEnum": { - if (exceptionContext.type === "argument") { - const { argumentIndex, name, functionName: quotedFunctionName } = exceptionContext; - exceptionHandlerBody = `WebCore::throwArgumentMustBeEnumError(lexicalGlobalObject, scope, ${argumentIndex}, ${str(name)}_s, ${str(type.name())}_s, ${str(quotedFunctionName)}_s, WebCore::expectedEnumerationValues<${type.cppClassName()}>());`; - } - break; - } } if (decl === "declare") { cpp.add(`${type.cppName()} `); } - let exceptionHandler = exceptionHandlerBody - ? `, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { ${exceptionHandlerBody} }` - : ""; - cpp.line(`${storageLocation} = WebCore::convert<${simpleType}>(*global, ${jsValueRef}${exceptionHandler});`); + let exceptionHandlerText = exceptionHandler ? `, ${exceptionHandler.params} { ${exceptionHandler.body} }` : ""; + cpp.line(`${storageLocation} = WebCore::convert<${simpleType}>(*global, ${jsValueRef}${exceptionHandlerText});`); - if (type.flags.range && type.flags.range[1] !== "abi") { + if (type.flags.range && type.flags.range[0] === "clamp" && type.flags.range[1] !== "abi") { emitRangeModifierCheck(cAbiType, storageLocation, type.flags.range); } @@ -469,6 +509,47 @@ function emitConvertValue( } } +interface ExceptionHandler { + /** @example "[](JSC::JSGlobalObject& global, ThrowScope& scope)" */ + params: string; + /** @example "WebCore::throwTypeError(global, scope)" */ + body: string; +} + +function getArgumentExceptionHandler(type: TypeImpl, argumentIndex: number, name: string, functionName: string) { + const { nodeValidator } = type.flags; + if (nodeValidator) { + switch (nodeValidator) { + case NodeValidator.validateInteger: + headers.add("ErrorCode.h"); + return { + params: `[]()`, + body: `return ${str(name)}_s;`, + }; + default: + throw new Error(`TODO: implement exception thrower for node validator ${nodeValidator}`); + } + } + switch (type.kind) { + case "zigEnum": + case "stringEnum": { + return { + params: `[](JSC::JSGlobalObject& global, JSC::ThrowScope& scope)`, + body: `WebCore::throwArgumentMustBeEnumError(${[ + `global`, + `scope`, + `${argumentIndex}`, + `${str(name)}_s`, + `${str(type.name())}_s`, + `${str(functionName)}_s`, + `WebCore::expectedEnumerationValues<${type.cppClassName()}>()`, + ].join(", ")});`, + }; + break; + } + } +} + /** * The built in WebCore range adaptors do not support arbitrary ranges, but that * is something we want to have. They aren't common, so they are just tacked @@ -483,23 +564,15 @@ function emitRangeModifierCheck( if (kind === "clamp") { cpp.line(`if (${storageLocation} < ${min}) ${storageLocation} = ${min};`); cpp.line(`else if (${storageLocation} > ${max}) ${storageLocation} = ${max};`); - } else if (kind === "enforce") { - cpp.line(`if (${storageLocation} < ${min} || ${storageLocation} > ${max}) {`); - cpp.indent(); - cpp.line( - `throwTypeError(global, throwScope, rangeErrorString<${cAbiTypeName(cAbiType)}>(${storageLocation}, ${min}, ${max}));`, - ); - cpp.line(`return {};`); - cpp.dedent(); - cpp.line(`}`); } else { - throw new Error(`TODO: range modifier ${kind}`); + // Implemented in BindgenCustomEnforceRange + throw new Error(`This should not be called for 'enforceRange' types.`); } } function addHeaderForType(type: TypeImpl) { if (type.lowersToNamedType() && type.ownerFile) { - headers.add(`Generated${cap(type.ownerFile)}.h`); + headers.add(`Generated${pascal(type.ownerFile)}.h`); } } @@ -747,6 +820,7 @@ function zigTypeNameInner(type: TypeImpl): string { function returnStrategyCppType(strategy: ReturnStrategy): string { switch (strategy.type) { case "basic-out-param": + case "void": return "bool"; // true=success, false=exception case "jsvalue": return "JSC::EncodedJSValue"; @@ -760,6 +834,7 @@ function returnStrategyCppType(strategy: ReturnStrategy): string { function returnStrategyZigType(strategy: ReturnStrategy): string { switch (strategy.type) { case "basic-out-param": + case "void": return "bool"; // true=success, false=exception case "jsvalue": return "JSC.JSValue"; @@ -809,6 +884,190 @@ function emitComplexZigDecoder(w: CodeWriter, prefix: string, type: TypeImpl, ch } } +type DistinguishablePrimitive = "undefined" | "string" | "number" | "boolean" | "object"; +type DistinguishStrategy = DistinguishablePrimitive; + +function typeCanDistinguish(t: TypeImpl[]) { + const seen: Record = { + undefined: false, + string: false, + number: false, + boolean: false, + object: false, + }; + let strategies: DistinguishStrategy[] = []; + + for (const type of t) { + let primitive: DistinguishablePrimitive | null = null; + if (type.kind === "undefined") { + primitive = "undefined"; + } else if (type.isStringType()) { + primitive = "string"; + } else if (type.isNumberType()) { + primitive = "number"; + } else if (type.kind === "boolean") { + primitive = "boolean"; + } else if (type.isObjectType()) { + primitive = "object"; + } + if (primitive) { + if (seen[primitive]) { + return null; + } + seen[primitive] = true; + strategies.push(primitive); + continue; + } + return null; // TODO: + } + + return strategies; +} + +/** This is an arbitrary classifier to allow consistent sorting for distinguishing arguments */ +function typeDistinguishmentWeight(type: TypeImpl): number { + if (type.kind === "undefined") { + return 100; + } + + if (type.isObjectType()) { + return 10; + } + + if (type.isStringType()) { + return 5; + } + + if (type.isNumberType()) { + return 3; + } + + if (type.kind === "boolean") { + return -1; + } + + return 0; +} + +function getDistinguishCode(strategy: DistinguishStrategy, type: TypeImpl, value: string) { + switch (strategy) { + case "string": + return { condition: `${value}.isString()`, canThrow: false }; + case "number": + return { condition: `${value}.isNumber()`, canThrow: false }; + case "boolean": + return { condition: `${value}.isBoolean()`, canThrow: false }; + case "object": + return { condition: `${value}.isObject()`, canThrow: false }; + case "undefined": + return { condition: `${value}.isUndefined()`, canThrow: false }; + default: + throw new Error(`TODO: getDistinguishCode for ${strategy}`); + } +} + +/** The variation selector implementation decides which variation dispatch to call. */ +function emitCppVariationSelector(fn: Func, namespaceVar: string) { + let minRequiredArgs = Infinity; + let maxArgs = 0; + + const variationsByArgumentCount = new Map(); + + const pushToList = (argCount: number, vari: Variant) => { + assert(typeof argCount === "number"); + let list = variationsByArgumentCount.get(argCount); + if (!list) { + list = []; + variationsByArgumentCount.set(argCount, list); + } + list.push(vari); + }; + + for (const vari of fn.variants) { + const vmra = vari.minRequiredArgs; + minRequiredArgs = Math.min(minRequiredArgs, vmra); + maxArgs = Math.max(maxArgs, vari.args.length); + const allArgCount = vari.args.filter(arg => !arg.type.isVirtualArgument()).length; + pushToList(vmra, vari); + if (allArgCount != vmra) { + pushToList(allArgCount, vari); + } + } + + cpp.line(`auto& vm = JSC::getVM(global);`); + cpp.line(`auto throwScope = DECLARE_THROW_SCOPE(vm);`); + if (minRequiredArgs > 0) { + cpp.line(`size_t argumentCount = std::min(callFrame->argumentCount(), ${maxArgs});`); + cpp.line(`if (argumentCount < ${minRequiredArgs}) {`); + cpp.line(` return JSC::throwVMError(global, throwScope, createNotEnoughArgumentsError(global));`); + cpp.line(`}`); + } + + const sorted = [...variationsByArgumentCount.entries()] + .map(([key, value]) => ({ argCount: key, variants: value })) + .sort((a, b) => b.argCount - a.argCount); + let argCountI = 0; + for (const { argCount, variants } of sorted) { + argCountI++; + const checkArgCount = argCountI < sorted.length && argCount !== minRequiredArgs; + if (checkArgCount) { + cpp.line(`if (argumentCount >= ${argCount}) {`); + cpp.indent(); + } + + if (variants.length === 1) { + cpp.line(`return ${extInternalDispatchVariant(namespaceVar, fn.name, variants[0].suffix)}(global, callFrame);`); + } else { + let argIndex = 0; + let strategies: DistinguishStrategy[] | null = null; + while (argIndex < argCount) { + strategies = typeCanDistinguish( + variants.map(v => v.args.filter(v => !v.type.isVirtualArgument())[argIndex].type), + ); + if (strategies) { + break; + } + argIndex++; + } + if (!strategies) { + const err = new Error( + `\x1b[0mVariations with ${argCount} required arguments must have at least one argument that can distinguish between them.\n` + + `Variations:\n${variants.map(v => ` ${inspect(v.args.filter(a => !a.type.isVirtualArgument()).map(x => x.type))}`).join("\n")}`, + ); + err.stack = `Error: ${err.message}\n${fn.snapshot}`; + throw err; + } + + const getArgument = minRequiredArgs > 0 ? "uncheckedArgument" : "argument"; + cpp.line(`JSC::JSValue distinguishingValue = callFrame->${getArgument}(${argIndex});`); + const sortedVariants = variants + .map((v, i) => ({ + variant: v, + type: v.args.filter(a => !a.type.isVirtualArgument())[argIndex].type, + strategy: strategies[i], + })) + .sort((a, b) => typeDistinguishmentWeight(a.type) - typeDistinguishmentWeight(b.type)); + for (const { variant: v, strategy: s } of sortedVariants) { + const arg = v.args[argIndex]; + const { condition, canThrow } = getDistinguishCode(s, arg.type, "distinguishingValue"); + cpp.line(`if (${condition}) {`); + cpp.indent(); + cpp.line(`return ${extInternalDispatchVariant(namespaceVar, fn.name, v.suffix)}(global, callFrame);`); + cpp.dedent(); + cpp.line(`}`); + if (canThrow) { + cpp.line(`RETURN_IF_EXCEPTION(throwScope, {});`); + } + } + } + + if (checkArgCount) { + cpp.dedent(); + cpp.line(`}`); + } + } +} + // BEGIN MAIN CODE GENERATION // Search for all .bind.ts files @@ -866,12 +1125,6 @@ zigInternal.indent(); cpp.line("namespace Generated {"); cpp.line(); -cpp.line("template"); -cpp.line("static String rangeErrorString(T value, T min, T max)"); -cpp.line("{"); -cpp.line(` return makeString("Value "_s, value, " is outside the range ["_s, min, ", "_s, max, ']');`); -cpp.line("}"); -cpp.line(); cppInternal.line('// These "Arguments" definitions are for communication between C++ and Zig.'); cppInternal.line('// Field layout depends on implementation details in "bindgen.ts", and'); @@ -953,15 +1206,15 @@ for (const [filename, { functions, typedefs }] of files) { `${pascal(namespaceVar)}${pascal(fn.name)}Arguments${fn.variants.length > 1 ? variNum : ""}`, ); const dispatchName = extDispatchVariant(namespaceVar, fn.name, variNum); + const internalDispatchName = extInternalDispatchVariant(namespaceVar, fn.name, variNum); const args: string[] = []; - let argNum = 0; if (vari.globalObjectArg === "hidden") { args.push("JSC::JSGlobalObject*"); } for (const arg of vari.args) { - argNum += 1; + if (arg.type.isIgnoredUndefinedType()) continue; const strategy = arg.loweringStrategy!; switch (strategy.type) { case "c-abi-pointer": @@ -989,6 +1242,18 @@ for (const [filename, { functions, typedefs }] of files) { cpp.line(`extern "C" ${returnStrategyCppType(vari.returnStrategy!)} ${dispatchName}(${args.join(", ")});`); + if (fn.variants.length > 1) { + // Emit separate variant dispatch functions + cpp.line( + `extern "C" SYSV_ABI JSC::EncodedJSValue ${internalDispatchName}(JSC::JSGlobalObject* global, JSC::CallFrame* callFrame)`, + ); + cpp.line(`{`); + cpp.indent(); + cpp.resetTemporaries(); + emitCppCallToVariant(fn.name, vari, dispatchName); + cpp.dedent(); + cpp.line(`}`); + } variNum += 1; } @@ -1008,7 +1273,7 @@ for (const [filename, { functions, typedefs }] of files) { if (fn.variants.length === 1) { emitCppCallToVariant(fn.name, fn.variants[0], extDispatchVariant(namespaceVar, fn.name, 1)); } else { - throw new Error(`TODO: multiple variant dispatch`); + emitCppVariationSelector(fn, namespaceVar); } cpp.dedent(); @@ -1036,6 +1301,7 @@ for (const [filename, { functions, typedefs }] of files) { } let argNum = 0; for (const arg of vari.args) { + if (arg.type.isIgnoredUndefinedType()) continue; let argName = `arg_${snake(arg.name)}`; if (vari.globalObjectArg === argNum) { if (arg.type.kind !== "globalObject") { @@ -1093,6 +1359,9 @@ for (const [filename, { functions, typedefs }] of files) { case "basic-out-param": zigInternal.add(`out.* = @as(bun.JSError!${returnStrategy.abiType}, `); break; + case "void": + zigInternal.add(`@as(bun.JSError!void, `); + break; } zigInternal.line(`${zid("import_" + namespaceVar)}.${fn.zigPrefix}${fn.name + vari.suffix}(`); @@ -1100,6 +1369,8 @@ for (const [filename, { functions, typedefs }] of files) { for (const arg of vari.args) { const argName = arg.zigMappedName!; + if (arg.type.isIgnoredUndefinedType()) continue; + if (arg.type.isVirtualArgument()) { switch (arg.type.kind) { case "zigVirtualMachine": @@ -1129,7 +1400,7 @@ for (const [filename, { functions, typedefs }] of files) { case "uses-communication-buffer": const prefix = `buf.${snake(arg.name)}`; const type = arg.type; - const isNullable = (type.flags.optional && !("default" in type.flags)) || type.flags.nullable; + const isNullable = type.flags.optional && !("default" in type.flags); if (isNullable) emitNullableZigDecoder(zigInternal, prefix, type, strategy.children); else emitComplexZigDecoder(zigInternal, prefix, type, strategy.children); zigInternal.line(`,`); @@ -1144,6 +1415,7 @@ for (const [filename, { functions, typedefs }] of files) { zigInternal.line(`));`); break; case "basic-out-param": + case "void": zigInternal.line(`)) catch |err| switch (err) {`); zigInternal.line(` error.JSError => return false,`); zigInternal.line(` error.OutOfMemory => ${globalObjectArg}.throwOutOfMemory() catch return false,`); diff --git a/src/darwin_c.zig b/src/darwin_c.zig index 7fb07e64d9..ed367f5f05 100644 --- a/src/darwin_c.zig +++ b/src/darwin_c.zig @@ -652,9 +652,6 @@ pub extern fn host_processor_info(host: std.c.host_t, flavor: processor_flavor_t pub extern fn getuid(...) std.posix.uid_t; pub extern fn getgid(...) std.posix.gid_t; -pub extern fn get_process_priority(pid: c_uint) i32; -pub extern fn set_process_priority(pid: c_uint, priority: c_int) i32; - pub fn get_version(buf: []u8) []const u8 { @memset(buf, 0); diff --git a/src/deps/libuv.zig b/src/deps/libuv.zig index 0940fdf3de..071b1862b1 100644 --- a/src/deps/libuv.zig +++ b/src/deps/libuv.zig @@ -2327,7 +2327,7 @@ pub const uv_rusage_t = extern struct { ru_nivcsw: u64, }; pub extern fn uv_getrusage(rusage: [*c]uv_rusage_t) c_int; -pub extern fn uv_os_homedir(buffer: [*]u8, size: [*c]usize) c_int; +pub extern fn uv_os_homedir(buffer: [*]u8, size: *usize) ReturnCode; pub extern fn uv_os_tmpdir(buffer: [*]u8, size: [*c]usize) c_int; pub extern fn uv_os_get_passwd(pwd: [*c]uv_passwd_t) c_int; pub extern fn uv_os_free_passwd(pwd: [*c]uv_passwd_t) void; diff --git a/src/js/node/async_hooks.ts b/src/js/node/async_hooks.ts index 5f109ae3ea..840afac3b9 100644 --- a/src/js/node/async_hooks.ts +++ b/src/js/node/async_hooks.ts @@ -23,7 +23,7 @@ // calls to $assert which will verify this invariant (only during bun-debug) // const [setAsyncHooksEnabled, cleanupLater] = $cpp("NodeAsyncHooks.cpp", "createAsyncHooksBinding"); -const { validateFunction, validateString } = require("internal/validators"); +const { validateFunction, validateString, validateObject } = require("internal/validators"); // Only run during debug function assertValidAsyncContextArray(array: unknown): array is ReadonlyArray | undefined { @@ -260,8 +260,22 @@ class AsyncResource { type; #snapshot; - constructor(type, options?) { + constructor(type, opts?) { validateString(type, "type"); + + let triggerAsyncId = opts; + if (opts != null) { + if (typeof opts !== "number") { + triggerAsyncId = opts.triggerAsyncId === undefined ? 1 : opts.triggerAsyncId; + } + if (!Number.isSafeInteger(triggerAsyncId) || triggerAsyncId < -1) { + throw $ERR_INVALID_ASYNC_ID(`Invalid triggerAsyncId value: ${triggerAsyncId}`); + } + } + if (hasEnabledCreateHook && type.length === 0) { + throw $ERR_ASYNC_TYPE(`Invalid name for async "type": ${type}`); + } + setAsyncHooksEnabled(true); this.type = type; this.#snapshot = get(); @@ -300,6 +314,7 @@ class AsyncResource { } bind(fn, thisArg) { + validateFunction(fn, "fn"); return this.runInAsyncScope.bind(this, fn, thisArg ?? this); } @@ -354,10 +369,28 @@ const createHookNotImpl = createWarning( true, ); -function createHook(callbacks) { +let hasEnabledCreateHook = false; +function createHook(hook) { + validateObject(hook, "hook"); + const { init, before, after, destroy, promiseResolve } = hook; + if (init !== undefined && typeof init !== "function") throw $ERR_ASYNC_CALLBACK("hook.init must be a function"); + if (before !== undefined && typeof before !== "function") throw $ERR_ASYNC_CALLBACK("hook.before must be a function"); + if (after !== undefined && typeof after !== "function") throw $ERR_ASYNC_CALLBACK("hook.after must be a function"); + if (destroy !== undefined && typeof destroy !== "function") + throw $ERR_ASYNC_CALLBACK("hook.destroy must be a function"); + if (promiseResolve !== undefined && typeof promiseResolve !== "function") + throw $ERR_ASYNC_CALLBACK("hook.promiseResolve must be a function"); + return { - enable: () => createHookNotImpl(callbacks), - disable: createHookNotImpl, + enable() { + createHookNotImpl(hook); + hasEnabledCreateHook = true; + return this; + }, + disable() { + createHookNotImpl(); + return this; + }, }; } diff --git a/src/js/node/os.ts b/src/js/node/os.ts index f962ed31e2..53d6fd5b8f 100644 --- a/src/js/node/os.ts +++ b/src/js/node/os.ts @@ -1,5 +1,4 @@ // Hardcoded module "node:os" - var tmpdir = function () { var env = Bun.env; @@ -19,6 +18,8 @@ var tmpdir = function () { return path; }; + tmpdir[Symbol.toPrimitive] = tmpdir; + return tmpdir(); }; @@ -85,7 +86,7 @@ function lazyCpus({ cpus }) { } // all logic based on `process.platform` and `process.arch` is inlined at bundle time -function bound(obj) { +function bound(binding) { return { availableParallelism: function () { return navigator.hardwareConcurrency; @@ -93,25 +94,27 @@ function bound(obj) { arch: function () { return process.arch; }, - cpus: lazyCpus(obj), + cpus: lazyCpus(binding), endianness: function () { - return process.arch === "arm64" || process.arch === "x64" ? "LE" : $bundleError("TODO: endianness"); + return process.arch === "arm64" || process.arch === "x64" // + ? "LE" + : $bundleError("TODO: endianness"); }, - freemem: obj.freemem.bind(obj), - getPriority: obj.getPriority.bind(obj), - homedir: obj.homedir.bind(obj), - hostname: obj.hostname.bind(obj), - loadavg: obj.loadavg.bind(obj), - networkInterfaces: obj.networkInterfaces.bind(obj), + freemem: binding.freemem, + getPriority: binding.getPriority, + homedir: binding.homedir, + hostname: binding.hostname, + loadavg: binding.loadavg, + networkInterfaces: binding.networkInterfaces, platform: function () { return process.platform; }, - release: obj.release.bind(obj), - setPriority: obj.setPriority.bind(obj), + release: binding.release, + setPriority: binding.setPriority, get tmpdir() { return tmpdir; }, - totalmem: obj.totalmem.bind(obj), + totalmem: binding.totalmem, type: function () { return process.platform === "win32" ? "Windows_NT" @@ -121,17 +124,25 @@ function bound(obj) { ? "Linux" : $bundleError("TODO: type"); }, - uptime: obj.uptime.bind(obj), - userInfo: obj.userInfo.bind(obj), - version: obj.version.bind(obj), - machine: obj.machine.bind(obj), + uptime: binding.uptime, + userInfo: binding.userInfo, + version: binding.version, + machine: function () { + return process.arch === "arm64" // + ? "arm64" + : process.arch === "x64" + ? "x86_64" + : $bundleError("TODO: machine"); + }, devNull: process.platform === "win32" ? "\\\\.\\nul" : "/dev/null", - EOL: process.platform === "win32" ? "\r\n" : "\n", + get EOL() { + return process.platform === "win32" ? "\r\n" : "\n"; + }, constants: $processBindingConstants.os, }; } -const out = bound($zig("node_os.zig", "OS.create")); +const out = bound($zig("node_os.zig", "createNodeOsBinding")); symbolToStringify(out, "arch"); symbolToStringify(out, "availableParallelism"); @@ -147,8 +158,10 @@ symbolToStringify(out, "type"); symbolToStringify(out, "uptime"); symbolToStringify(out, "version"); symbolToStringify(out, "machine"); + function symbolToStringify(obj, key) { - obj[key][Symbol.toPrimitive] = function (hint) { + $assert(obj[key] !== undefined, `Missing ${key}`); + obj[key][Symbol.toPrimitive] = function (hint: string) { return obj[key](); }; } diff --git a/src/js/private.d.ts b/src/js/private.d.ts index aeb86e97d2..b058cc40c5 100644 --- a/src/js/private.d.ts +++ b/src/js/private.d.ts @@ -210,6 +210,9 @@ declare function $newZigFunction any>( argCount: number, ): T; /** + * Retrieves a handle to a function defined in Zig or C++, defined in a + * `.bind.ts` file. For more information on how to define bindgen functions, see + * [bindgen's documentation](https://bun.sh/docs/project/bindgen). * @param filename - The basename of the `.bind.ts` file. * @param symbol - The name of the function to call. */ diff --git a/src/sys.zig b/src/sys.zig index aa9df098d5..179ed41fec 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -255,6 +255,7 @@ pub const Tag = enum(u8) { uv_pipe, uv_tty_set_mode, uv_open_osfhandle, + uv_os_homedir, // Below this line are Windows API calls only. @@ -3462,8 +3463,8 @@ pub const File = struct { }; } - /// Use this function on small files < 1024 bytes. - /// This will skip the fstat() call. + /// Use this function on small files <= 1024 bytes. + /// This will skip the fstat() call, preallocating 64 bytes instead of the file's size. pub fn readToEndSmall(this: File, allocator: std.mem.Allocator) ReadToEndResult { var list = std.ArrayList(u8).init(allocator); return switch (readToEndWithArrayList(this, &list, true)) { diff --git a/test/js/node/os/os.test.js b/test/js/node/os/os.test.js index 469089c2a6..a887b113cd 100644 --- a/test/js/node/os/os.test.js +++ b/test/js/node/os/os.test.js @@ -222,3 +222,22 @@ describe("toString works like node", () => { }); } }); + +it("getPriority system error object", () => { + try { + os.getPriority(-1); + expect.unreachable(); + } catch (err) { + expect(err.name).toBe("SystemError"); + expect(err.message).toBe("A system error occurred: uv_os_getpriority returned ESRCH (no such process)"); + expect(err.code).toBe("ERR_SYSTEM_ERROR"); + expect(err.info).toEqual({ + errno: isWindows ? -4040 : -3, + code: "ESRCH", + message: "no such process", + syscall: "uv_os_getpriority", + }); + expect(err.errno).toBe(isWindows ? -4040 : -3); + expect(err.syscall).toBe("uv_os_getpriority"); + } +}); diff --git a/test/js/node/test/parallel/test-async-hooks-asyncresource-constructor.js b/test/js/node/test/parallel/test-async-hooks-asyncresource-constructor.js new file mode 100644 index 0000000000..8b504aa7a7 --- /dev/null +++ b/test/js/node/test/parallel/test-async-hooks-asyncresource-constructor.js @@ -0,0 +1,41 @@ +'use strict'; + +// This tests that AsyncResource throws an error if bad parameters are passed + +require('../common'); +const assert = require('assert'); +const async_hooks = require('async_hooks'); +const { AsyncResource } = async_hooks; + +// Setup init hook such parameters are validated +async_hooks.createHook({ + init() {} +}).enable(); + +assert.throws(() => { + return new AsyncResource(); +}, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', +}); + +assert.throws(() => { + new AsyncResource(''); +}, { + code: 'ERR_ASYNC_TYPE', + name: 'TypeError', +}); + +assert.throws(() => { + new AsyncResource('type', -4); +}, { + code: 'ERR_INVALID_ASYNC_ID', + name: 'RangeError', +}); + +assert.throws(() => { + new AsyncResource('type', Math.PI); +}, { + code: 'ERR_INVALID_ASYNC_ID', + name: 'RangeError', +}); diff --git a/test/js/node/test/parallel/test-async-hooks-constructor.js b/test/js/node/test/parallel/test-async-hooks-constructor.js new file mode 100644 index 0000000000..62ec854108 --- /dev/null +++ b/test/js/node/test/parallel/test-async-hooks-constructor.js @@ -0,0 +1,21 @@ +'use strict'; + +// This tests that AsyncHooks throws an error if bad parameters are passed. + +require('../common'); +const assert = require('assert'); +const async_hooks = require('async_hooks'); +const nonFunctionArray = [null, -1, 1, {}, []]; + +['init', 'before', 'after', 'destroy', 'promiseResolve'].forEach( + (functionName) => { + nonFunctionArray.forEach((nonFunction) => { + assert.throws(() => { + async_hooks.createHook({ [functionName]: nonFunction }); + }, { + code: 'ERR_ASYNC_CALLBACK', + name: 'TypeError', + message: `hook.${functionName} must be a function`, + }); + }); + }); diff --git a/test/js/node/test/parallel/test-async-wrap-constructor.js b/test/js/node/test/parallel/test-async-wrap-constructor.js new file mode 100644 index 0000000000..853898aa0a --- /dev/null +++ b/test/js/node/test/parallel/test-async-wrap-constructor.js @@ -0,0 +1,21 @@ +'use strict'; + +// This tests that using falsy values in createHook throws an error. + +require('../common'); +const assert = require('assert'); +const async_hooks = require('async_hooks'); + +const falsyValues = [0, 1, false, true, null, 'hello']; +for (const badArg of falsyValues) { + const hookNames = ['init', 'before', 'after', 'destroy', 'promiseResolve']; + for (const hookName of hookNames) { + assert.throws(() => { + async_hooks.createHook({ [hookName]: badArg }); + }, { + code: 'ERR_ASYNC_CALLBACK', + name: 'TypeError', + message: `hook.${hookName} must be a function` + }); + } +} diff --git a/test/js/node/test/parallel/test-os-eol.js b/test/js/node/test/parallel/test-os-eol.js new file mode 100644 index 0000000000..412751a151 --- /dev/null +++ b/test/js/node/test/parallel/test-os-eol.js @@ -0,0 +1,24 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const os = require('os'); + +const eol = common.isWindows ? '\r\n' : '\n'; + +assert.strictEqual(os.EOL, eol); + +// Test that the `Error` is a `TypeError` but do not check the message as it +// varies between different JavaScript engines. +assert.throws(function() { os.EOL = 123; }, TypeError); + +const foo = 'foo'; +Object.defineProperties(os, { + EOL: { + configurable: true, + enumerable: true, + writable: false, + value: foo + } +}); +assert.strictEqual(os.EOL, foo); diff --git a/test/js/node/test/parallel/test-os-process-priority.js b/test/js/node/test/parallel/test-os-process-priority.js new file mode 100644 index 0000000000..2edabf53df --- /dev/null +++ b/test/js/node/test/parallel/test-os-process-priority.js @@ -0,0 +1,145 @@ +'use strict'; +const common = require('../common'); +// IBMi process priority is different. +if (common.isIBMi) + common.skip('IBMi has a different process priority'); + +const assert = require('assert'); +const os = require('os'); +const { + PRIORITY_LOW, + PRIORITY_BELOW_NORMAL, + PRIORITY_NORMAL, + PRIORITY_ABOVE_NORMAL, + PRIORITY_HIGH, + PRIORITY_HIGHEST +} = os.constants.priority; + +// Validate priority constants. +assert.strictEqual(typeof PRIORITY_LOW, 'number'); +assert.strictEqual(typeof PRIORITY_BELOW_NORMAL, 'number'); +assert.strictEqual(typeof PRIORITY_NORMAL, 'number'); +assert.strictEqual(typeof PRIORITY_ABOVE_NORMAL, 'number'); +assert.strictEqual(typeof PRIORITY_HIGH, 'number'); +assert.strictEqual(typeof PRIORITY_HIGHEST, 'number'); + +// Test pid type validation. +[null, true, false, 'foo', {}, [], /x/].forEach((pid) => { + const errObj = { + code: 'ERR_INVALID_ARG_TYPE', + message: /The "pid" argument must be of type number\./ + }; + + assert.throws(() => { + os.setPriority(pid, PRIORITY_NORMAL); + }, errObj); + + assert.throws(() => { + os.getPriority(pid); + }, errObj); +}); + +// Test pid range validation. +[NaN, Infinity, -Infinity, 3.14, 2 ** 32].forEach((pid) => { + const errObj = { + code: 'ERR_OUT_OF_RANGE', + message: /The value of "pid" is out of range\./ + }; + + assert.throws(() => { + os.setPriority(pid, PRIORITY_NORMAL); + }, errObj); + + assert.throws(() => { + os.getPriority(pid); + }, errObj); +}); + +// Test priority type validation. +[null, true, false, 'foo', {}, [], /x/].forEach((priority) => { + assert.throws(() => { + os.setPriority(0, priority); + }, { + code: 'ERR_INVALID_ARG_TYPE', + message: /The "priority" argument must be of type number\./ + }); +}); + +// Test priority range validation. +[ + NaN, + Infinity, + -Infinity, + 3.14, + 2 ** 32, + PRIORITY_HIGHEST - 1, + PRIORITY_LOW + 1, +].forEach((priority) => { + assert.throws(() => { + os.setPriority(0, priority); + }, { + code: 'ERR_OUT_OF_RANGE', + message: /The value of "priority" is out of range\./ + }); +}); + +// Verify that valid values work. +for (let i = PRIORITY_HIGHEST; i <= PRIORITY_LOW; i++) { + // A pid of 0 corresponds to the current process. + try { + os.setPriority(0, i); + } catch (err) { + // The current user might not have sufficient permissions to set this + // specific priority level. Skip this priority, but keep trying lower + // priorities. + if (err.info.code === 'EACCES') + continue; + + assert(err); + } + + checkPriority(0, i); + + // An undefined pid corresponds to the current process. + os.setPriority(i); + checkPriority(undefined, i); + + // Specifying the actual pid works. + os.setPriority(process.pid, i); + checkPriority(process.pid, i); +} + +{ + assert.throws(() => { os.getPriority(-1); }, { + code: 'ERR_SYSTEM_ERROR', + message: /A system error occurred: uv_os_getpriority returned /, + name: 'SystemError' + }); +} + + +function checkPriority(pid, expected) { + const priority = os.getPriority(pid); + + // Verify that the priority values match on Unix, and are range mapped on + // Windows. + if (!common.isWindows) { + assert.strictEqual(priority, expected); + return; + } + + // On Windows setting PRIORITY_HIGHEST will only work for elevated user, + // for others it will be silently reduced to PRIORITY_HIGH + if (expected < PRIORITY_HIGH) + assert.ok(priority === PRIORITY_HIGHEST || priority === PRIORITY_HIGH); + else if (expected < PRIORITY_ABOVE_NORMAL) + assert.strictEqual(priority, PRIORITY_HIGH); + else if (expected < PRIORITY_NORMAL) + assert.strictEqual(priority, PRIORITY_ABOVE_NORMAL); + else if (expected < PRIORITY_BELOW_NORMAL) + assert.strictEqual(priority, PRIORITY_NORMAL); + else if (expected < PRIORITY_LOW) + assert.strictEqual(priority, PRIORITY_BELOW_NORMAL); + else + assert.strictEqual(priority, PRIORITY_LOW); +} diff --git a/test/js/node/test/parallel/test-os-userinfo-handles-getter-errors.js b/test/js/node/test/parallel/test-os-userinfo-handles-getter-errors.js new file mode 100644 index 0000000000..ca7b560012 --- /dev/null +++ b/test/js/node/test/parallel/test-os-userinfo-handles-getter-errors.js @@ -0,0 +1,19 @@ +'use strict'; +// Tests that os.userInfo correctly handles errors thrown by option property +// getters. See https://github.com/nodejs/node/issues/12370. + +const common = require('../common'); +const assert = require('assert'); +const execFile = require('child_process').execFile; + +const script = `os.userInfo({ + get encoding() { + throw new Error('xyz'); + } +})`; + +const node = process.execPath; +execFile(node, [ '-e', script ], common.mustCall((err, stdout, stderr) => { + // Edited for Bun to lowercase `error` + assert(stderr.includes('xyz'), 'userInfo crashes'); +})); diff --git a/test/js/node/test/parallel/test-os.js b/test/js/node/test/parallel/test-os.js new file mode 100644 index 0000000000..3d9fe5c1a6 --- /dev/null +++ b/test/js/node/test/parallel/test-os.js @@ -0,0 +1,281 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const os = require('os'); +const path = require('path'); +const { inspect } = require('util'); + +const is = { + number: (value, key) => { + assert(!Number.isNaN(value), `${key} should not be NaN`); + assert.strictEqual(typeof value, 'number'); + }, + string: (value) => { assert.strictEqual(typeof value, 'string'); }, + array: (value) => { assert.ok(Array.isArray(value)); }, + object: (value) => { + assert.strictEqual(typeof value, 'object'); + assert.notStrictEqual(value, null); + } +}; + +process.env.TMPDIR = '/tmpdir'; +process.env.TMP = '/tmp'; +process.env.TEMP = '/temp'; +if (common.isWindows) { + assert.strictEqual(os.tmpdir(), '/temp'); + process.env.TEMP = ''; + assert.strictEqual(os.tmpdir(), '/tmp'); + process.env.TMP = ''; + const expected = `${process.env.SystemRoot || process.env.windir}\\temp`; + assert.strictEqual(os.tmpdir(), expected); + process.env.TEMP = '\\temp\\'; + assert.strictEqual(os.tmpdir(), '\\temp'); + process.env.TEMP = '\\tmpdir/'; + assert.strictEqual(os.tmpdir(), '\\tmpdir/'); + process.env.TEMP = '\\'; + assert.strictEqual(os.tmpdir(), '\\'); + process.env.TEMP = 'C:\\'; + assert.strictEqual(os.tmpdir(), 'C:\\'); +} else { + assert.strictEqual(os.tmpdir(), '/tmpdir'); + process.env.TMPDIR = ''; + assert.strictEqual(os.tmpdir(), '/tmp'); + process.env.TMP = ''; + assert.strictEqual(os.tmpdir(), '/temp'); + process.env.TEMP = ''; + assert.strictEqual(os.tmpdir(), '/tmp'); + process.env.TMPDIR = '/tmpdir/'; + assert.strictEqual(os.tmpdir(), '/tmpdir'); + process.env.TMPDIR = '/tmpdir\\'; + assert.strictEqual(os.tmpdir(), '/tmpdir\\'); + process.env.TMPDIR = '/'; + assert.strictEqual(os.tmpdir(), '/'); +} + +const endianness = os.endianness(); +is.string(endianness); +assert.match(endianness, /[BL]E/); + +const hostname = os.hostname(); +is.string(hostname); +assert.ok(hostname.length > 0); + +// IBMi process priority is different. +if (!common.isIBMi) { + const { PRIORITY_BELOW_NORMAL, PRIORITY_LOW } = os.constants.priority; + // Priority means niceness: higher numeric value <=> lower priority + const LOWER_PRIORITY = os.getPriority() < PRIORITY_BELOW_NORMAL ? PRIORITY_BELOW_NORMAL : PRIORITY_LOW; + os.setPriority(LOWER_PRIORITY); + const priority = os.getPriority(); + is.number(priority); + assert.strictEqual(priority, LOWER_PRIORITY); +} + +// On IBMi, os.uptime() returns 'undefined' +if (!common.isIBMi) { + const uptime = os.uptime(); + is.number(uptime); + assert.ok(uptime > 0); +} + +const cpus = os.cpus(); +is.array(cpus); +assert.ok(cpus.length > 0); +for (const cpu of cpus) { + assert.strictEqual(typeof cpu.model, 'string'); + assert.strictEqual(typeof cpu.speed, 'number'); + assert.strictEqual(typeof cpu.times.user, 'number'); + assert.strictEqual(typeof cpu.times.nice, 'number'); + assert.strictEqual(typeof cpu.times.sys, 'number'); + assert.strictEqual(typeof cpu.times.idle, 'number'); + assert.strictEqual(typeof cpu.times.irq, 'number'); +} + +const type = os.type(); +is.string(type); +assert.ok(type.length > 0); + +const release = os.release(); +is.string(release); +assert.ok(release.length > 0); +// TODO: Check format on more than just AIX +if (common.isAIX) + assert.match(release, /^\d+\.\d+$/); + +const platform = os.platform(); +is.string(platform); +assert.ok(platform.length > 0); + +const arch = os.arch(); +is.string(arch); +assert.ok(arch.length > 0); + +if (!common.isSunOS) { + // not implemented yet + assert.ok(os.loadavg().length > 0); + assert.ok(os.freemem() > 0); + assert.ok(os.totalmem() > 0); +} + +const interfaces = os.networkInterfaces(); +switch (platform) { + case 'linux': { + const filter = (e) => + e.address === '127.0.0.1' && + e.netmask === '255.0.0.0'; + + const actual = interfaces.lo.filter(filter); + const expected = [{ + address: '127.0.0.1', + netmask: '255.0.0.0', + family: 'IPv4', + mac: '00:00:00:00:00:00', + internal: true, + cidr: '127.0.0.1/8' + }]; + assert.deepStrictEqual(actual, expected); + break; + } + case 'win32': { + const filter = (e) => + e.address === '127.0.0.1'; + + const actual = interfaces['Loopback Pseudo-Interface 1'].filter(filter); + const expected = [{ + address: '127.0.0.1', + netmask: '255.0.0.0', + family: 'IPv4', + mac: '00:00:00:00:00:00', + internal: true, + cidr: '127.0.0.1/8' + }]; + assert.deepStrictEqual(actual, expected); + break; + } +} +const netmaskToCIDRSuffixMap = new Map(Object.entries({ + '255.0.0.0': 8, + '255.255.255.0': 24, + 'ffff:ffff:ffff:ffff::': 64, + 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff': 128 +})); + +Object.values(interfaces) + .flat(Infinity) + .map((v) => ({ v, mask: netmaskToCIDRSuffixMap.get(v.netmask) })) + .forEach(({ v, mask }) => { + assert.ok('cidr' in v, `"cidr" prop not found in ${inspect(v)}`); + if (mask) { + assert.strictEqual(v.cidr, `${v.address}/${mask}`); + } + }); + +const EOL = os.EOL; +if (common.isWindows) { + assert.strictEqual(EOL, '\r\n'); +} else { + assert.strictEqual(EOL, '\n'); +} + +const home = os.homedir(); +is.string(home); +assert.ok(home.includes(path.sep)); + +const version = os.version(); +assert.strictEqual(typeof version, 'string'); +assert(version); + +if (common.isWindows && process.env.USERPROFILE) { + assert.strictEqual(home, process.env.USERPROFILE); + delete process.env.USERPROFILE; + assert.ok(os.homedir().includes(path.sep)); + process.env.USERPROFILE = home; +} else if (!common.isWindows && process.env.HOME) { + assert.strictEqual(home, process.env.HOME); + delete process.env.HOME; + assert.ok(os.homedir().includes(path.sep)); + process.env.HOME = home; +} + +const pwd = os.userInfo(); +is.object(pwd); +const pwdBuf = os.userInfo({ encoding: 'buffer' }); + +if (common.isWindows) { + assert.strictEqual(pwd.uid, -1); + assert.strictEqual(pwd.gid, -1); + assert.strictEqual(pwd.shell, null); + assert.strictEqual(pwdBuf.uid, -1); + assert.strictEqual(pwdBuf.gid, -1); + assert.strictEqual(pwdBuf.shell, null); +} else { + is.number(pwd.uid); + is.number(pwd.gid); + assert.strictEqual(typeof pwd.shell, 'string'); + // It's possible for /etc/passwd to leave the user's shell blank. + if (pwd.shell.length > 0) { + assert(pwd.shell.includes(path.sep)); + } + assert.strictEqual(pwd.uid, pwdBuf.uid); + assert.strictEqual(pwd.gid, pwdBuf.gid); + assert.strictEqual(pwd.shell, pwdBuf.shell.toString('utf8')); +} + +is.string(pwd.username); +assert.ok(pwd.homedir.includes(path.sep)); +assert.strictEqual(pwd.username, pwdBuf.username.toString('utf8')); +assert.strictEqual(pwd.homedir, pwdBuf.homedir.toString('utf8')); + +assert.strictEqual(`${os.hostname}`, os.hostname()); +assert.strictEqual(`${os.homedir}`, os.homedir()); +assert.strictEqual(`${os.release}`, os.release()); +assert.strictEqual(`${os.type}`, os.type()); +assert.strictEqual(`${os.endianness}`, os.endianness()); +assert.strictEqual(`${os.tmpdir}`, os.tmpdir()); +assert.strictEqual(`${os.arch}`, os.arch()); +assert.strictEqual(`${os.platform}`, os.platform()); +assert.strictEqual(`${os.version}`, os.version()); +assert.strictEqual(`${os.machine}`, os.machine()); +assert.strictEqual(+os.totalmem, os.totalmem()); + +// Assert that the following values are coercible to numbers. +// On IBMi, os.uptime() returns 'undefined' +if (!common.isIBMi) { + is.number(+os.uptime, 'uptime'); + is.number(os.uptime(), 'uptime'); +} + +is.number(+os.availableParallelism, 'availableParallelism'); +is.number(os.availableParallelism(), 'availableParallelism'); +is.number(+os.freemem, 'freemem'); +is.number(os.freemem(), 'freemem'); + +const devNull = os.devNull; +if (common.isWindows) { + assert.strictEqual(devNull, '\\\\.\\nul'); +} else { + assert.strictEqual(devNull, '/dev/null'); +} + +assert.ok(os.availableParallelism() > 0); From 9524e1c86ab76d7f00248506b7f7540d925e0042 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Mon, 16 Dec 2024 22:33:34 -0800 Subject: [PATCH 034/125] fix: `Bun.deepMatch` on circular objects causing segfault (#15672) Co-authored-by: Don Isaac Co-authored-by: DonIsaac Co-authored-by: Jarred Sumner --- src/bun.js/bindings/BunObject.cpp | 6 +- src/bun.js/bindings/bindings.cpp | 70 ++++++- src/bun.js/bindings/headers-handwritten.h | 47 ++++- test/js/bun/bun-object/deep-match.spec.ts | 222 ++++++++++++++++++++++ 4 files changed, 338 insertions(+), 7 deletions(-) create mode 100644 test/js/bun/bun-object/deep-match.spec.ts diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index 7188d1bb4b..225f422e4b 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -495,7 +495,11 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepMatch, (JSGlobalObject * globalObject, J return {}; } - bool match = Bun__deepMatch(object, subset, globalObject, &scope, false, false); + std::set objVisited; + std::set subsetVisited; + MarkedArgumentBuffer gcBuffer; + bool match = Bun__deepMatch(object, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, false, false); + RETURN_IF_EXCEPTION(scope, {}); return JSValue::encode(jsBoolean(match)); } diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index b370262e00..7df8634f02 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -526,7 +526,10 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global if (patternObject.isObject()) { if (otherProp.isObject()) { ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm()); - if (Bun__deepMatch(otherProp, patternObject, globalObject, &scope, false, true)) { + // SAFETY: visited property sets are not required when + // `enableAsymmetricMatchers` and `isMatchingObjectContaining` + // are both true + if (Bun__deepMatch(otherProp, nullptr, patternObject, nullptr, globalObject, &scope, nullptr, false, true)) { return AsymmetricMatcherResult::PASS; } } @@ -1354,9 +1357,51 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, return true; } +/** + * @brief `Bun.deepMatch(a, b)` + * + * @note + * The sets recording already visited properties (`seenObjProperties`, + * `seenSubsetProperties`, and `gcBuffer`) aren not needed when both + * `enableAsymmetricMatchers` and `isMatchingObjectContaining` are true. In + * this case, it is safe to pass a `nullptr`. + * + * `gcBuffer` ensures JSC's stack scan does not come up empty-handed and free + * properties currently within those stacks. Likely unnecessary, but better to + * be safe tnan sorry + * + * @tparam enableAsymmetricMatchers + * @param objValue + * @param seenObjProperties already visited properties of `objValue`. + * @param subsetValue + * @param seenSubsetProperties already visited properties of `subsetValue`. + * @param globalObject + * @param throwScope + * @param gcBuffer + * @param replacePropsWithAsymmetricMatchers + * @param isMatchingObjectContaining + * + * @return true + * @return false + */ template -bool Bun__deepMatch(JSValue objValue, JSValue subsetValue, JSGlobalObject* globalObject, ThrowScope* throwScope, bool replacePropsWithAsymmetricMatchers, bool isMatchingObjectContaining) +bool Bun__deepMatch( + JSValue objValue, + std::set* seenObjProperties, + JSValue subsetValue, + std::set* seenSubsetProperties, + JSGlobalObject* globalObject, + ThrowScope* throwScope, + MarkedArgumentBuffer* gcBuffer, + bool replacePropsWithAsymmetricMatchers, + bool isMatchingObjectContaining) { + + // Caller must ensure only objects are passed to this function. + ASSERT(objValue.isCell()); + ASSERT(subsetValue.isCell()); + // fast path for reference equality. + if (objValue == subsetValue) return true; VM& vm = globalObject->vm(); JSObject* obj = objValue.getObject(); JSObject* subsetObj = subsetValue.getObject(); @@ -1436,7 +1481,16 @@ bool Bun__deepMatch(JSValue objValue, JSValue subsetValue, JSGlobalObject* globa return false; } } else { - if (!Bun__deepMatch(prop, subsetProp, globalObject, throwScope, replacePropsWithAsymmetricMatchers, isMatchingObjectContaining)) { + ASSERT(seenObjProperties != nullptr); + ASSERT(seenSubsetProperties != nullptr); + ASSERT(gcBuffer != nullptr); + auto didInsertProp = seenObjProperties->insert(JSC::JSValue::encode(prop)); + auto didInsertSubset = seenSubsetProperties->insert(JSC::JSValue::encode(subsetProp)); + gcBuffer->append(prop); + gcBuffer->append(subsetProp); + // property cycle detected + if (!didInsertProp.second || !didInsertSubset.second) continue; + if (!Bun__deepMatch(prop, seenObjProperties, subsetProp, seenSubsetProperties, globalObject, throwScope, gcBuffer, replacePropsWithAsymmetricMatchers, isMatchingObjectContaining)) { return false; } } @@ -2420,7 +2474,10 @@ bool JSC__JSValue__deepMatch(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__ ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm()); - return Bun__deepMatch(obj, subset, globalObject, &scope, replacePropsWithAsymmetricMatchers, false); + std::set objVisited; + std::set subsetVisited; + MarkedArgumentBuffer gcBuffer; + return Bun__deepMatch(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false); } bool JSC__JSValue__jestDeepMatch(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject, bool replacePropsWithAsymmetricMatchers) @@ -2430,7 +2487,10 @@ bool JSC__JSValue__jestDeepMatch(JSC__JSValue JSValue0, JSC__JSValue JSValue1, J ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm()); - return Bun__deepMatch(obj, subset, globalObject, &scope, replacePropsWithAsymmetricMatchers, false); + std::set objVisited; + std::set subsetVisited; + MarkedArgumentBuffer gcBuffer; + return Bun__deepMatch(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false); } extern "C" JSC__JSValue Bun__JSValue__call(JSContextRef ctx, JSC__JSValue object, diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h index f21fc27bf9..8c7b6802a5 100644 --- a/src/bun.js/bindings/headers-handwritten.h +++ b/src/bun.js/bindings/headers-handwritten.h @@ -1,6 +1,10 @@ #pragma once #include "wtf/Compiler.h" #include "wtf/text/OrdinalNumber.h" +#include "JavaScriptCore/JSCJSValue.h" +#include "JavaScriptCore/ArgList.h" +#include + #ifndef HEADERS_HANDWRITTEN #define HEADERS_HANDWRITTEN typedef uint16_t ZigErrorCode; @@ -380,8 +384,49 @@ extern "C" int64_t Bun__encoding__constructFromUTF16(void*, const UChar* ptr, si template bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JSValue v2, JSC::MarkedArgumentBuffer&, Vector, 16>& stack, JSC::ThrowScope* scope, bool addToStack); +/** + * @brief `Bun.deepMatch(a, b)` + * + * `object` and `subset` must be objects. In the future we should change the + * signature of this function to only take `JSC::JSCell`. For now, panics + * if either `object` or `subset` are not `JSCCell`. + * + * @note + * The sets recording already visited properties (`seenObjProperties` and + * `seenSubsetProperties`) aren not needed when both `enableAsymmetricMatchers` + * and `isMatchingObjectContaining` are true. In this case, it is safe to pass a + * `nullptr`. + * + * `gcBuffer` ensures JSC's stack scan does not come up empty-handed and free + * properties currently within those stacks. Likely unnecessary, but better to + * be safe tnan sorry + * + * + * @tparam enableAsymmetricMatchers + * @param objValue + * @param seenObjProperties already visited properties of `objValue`. + * @param subsetValue + * @param seenSubsetProperties already visited properties of `subsetValue`. + * @param globalObject + * @param Scope + * @param gcBuffer + * @param replacePropsWithAsymmetricMatchers + * @param isMatchingObjectContaining + * + * @return true + * @return false + */ template -bool Bun__deepMatch(JSC::JSValue object, JSC::JSValue subset, JSC::JSGlobalObject* globalObject, JSC::ThrowScope* throwScope, bool replacePropsWithAsymmetricMatchers, bool isMatchingObjectContaining); +bool Bun__deepMatch( + JSC::JSValue object, + std::set* seenObjProperties, + JSC::JSValue subset, + std::set* seenSubsetProperties, + JSC::JSGlobalObject* globalObject, + JSC::ThrowScope* throwScope, + JSC::MarkedArgumentBuffer* gcBuffer, + bool replacePropsWithAsymmetricMatchers, + bool isMatchingObjectContaining); extern "C" void Bun__remapStackFramePositions(JSC::JSGlobalObject*, ZigStackFrame*, size_t); diff --git a/test/js/bun/bun-object/deep-match.spec.ts b/test/js/bun/bun-object/deep-match.spec.ts new file mode 100644 index 0000000000..1a70301937 --- /dev/null +++ b/test/js/bun/bun-object/deep-match.spec.ts @@ -0,0 +1,222 @@ +type TestCase = [a: unknown, b: unknown]; + +// @ts-ignore +if (typeof Bun === "undefined") + [ + // @ts-ignore + (globalThis.Bun = { + deepMatch(a, b) { + try { + expect(b).toMatchObject(a); + return true; + } catch (e) { + if (e instanceof TypeError) throw e; + return false; + } + }, + }), + ]; +describe("Bun.deepMatch", () => { + it.each([ + // force line break + {}, + { a: 1 }, + [[1, 2, 3]], + ] as TestCase[])("returns `true` for referentially equal objects (%p)", obj => { + expect(Bun.deepMatch(obj, obj)).toBe(true); + // expect(Bun.deepMatch(obj, obj)).toBe(true); + }); + + // prettier-ignore + it.each([ + // POJOs + [{}, {}], + [{ a: 1 }, { a: 1 }], + [{ a: Symbol.for("foo") }, { a: Symbol.for("foo") }], + [ + { a: { b: "foo" }, c: true }, + { a: { b: "foo" }, c: true }, + ], + [ + { a: [{ b: [] }, "foo", 0, null] }, + { a: [{ b: [] }, "foo", 0, null] } + ], + [{ }, { a: undefined }], // NOTE: `b` may be a superset of `a`, but not vice-versa + [{ a: { b: "foo" } }, { a: { b: "foo", c: undefined } }], + [{ a: { b: "foo" } }, { a: { b: "foo", c: 1 } }], + + // Arrays + [[], []], + [ + [1, 2, 3], + [1, 2, 3], + ], + [ + [{}, "foo", 1], + [{}, "foo", 1], + ], + + // Maps + [new Map(), new Map()], + [ + new Map([ [1, 2], [2, 3], [3, 4] ]), + new Map([ [1, 2], [2, 3], [3, 4] ]), + ], + [ + new Map([ ["foo", 1] ]), + new Map([ ["foo", 1] ]), + ], + + // Sets + [new Set(), new Set()], + [ + new Set([1, 2, 3]), + new Set([1, 2, 3]), + ], + [ + new Set(["a", "b", "c"]), + new Set(["a", "b", "c"]), + ], + ])("Bun.deepMatch(%p, %p) === true", (a, b) => { + expect(Bun.deepMatch(a, b)).toBe(true); + }); + + // prettier-ignore + it.each([ + // POJOs + [{ a: undefined }, { }], // NOTE: `a` may not be a superset of `b` + [{ a: 1 }, { a: 2 }], + [{ a: 1 }, { b: 1 }], + [{ a: null }, { a: undefined }], + [{ a: { b: "foo" } }, { a: { b: "bar"} }], + [{ a: { b: "foo", c: 1 } }, { a: { b: "foo" } }], + [{ a: Symbol.for("a") }, { a: Symbol.for("b") }], + [{ a: Symbol("a") }, { a: Symbol("a") }], // new symbols are never equal + + // Arrays + [[1, 2, 3], [1, 2]], + [[1, 2, 3], [1, 2, 4]], + [[null], [undefined]], + [[], [undefined]], + [["a", "b", "c"], ["a", "b", "d"]], + + // Maps + // FIXME: I assume this is incorrect but I need confirmation on expected behavior. + // [ + // new Map([ [1, 2], [2, 3], [3, 4] ]), + // new Map([ [1, 2], [2, 3] ]), + // ], + // [ + // new Map([ [1, 2], [2, 3], [3, 4] ]), + // new Map([ [1, 2], [2, 3], [3, 4], [4, 5] ]), + // ], + // [ + // new Map([ [1, 2], [2, 3], [3, 4], [4, 5] ]), + // new Map([ [1, 2], [2, 3], [3, 4] ]), + // ], + + // Sets + // FIXME: I assume this is incorrect but I need confirmation on expected behavior. + // [ + // new Set([1, 2, 3]), + // new Set([4, 5, 6]), + // ], + // [ + // new Set([1, 2, 3]), + // new Set([1, 2]), + // ], + // [ + // new Set([1, 2]), + // new Set([1, 2, 3]), + // ], + // [ + // new Set(["a", "b", "c"]), + // new Set(["a", "b", "d"]), + // ], + ])("Bun.deepMatch(%p, %p) === false", (a, b) => { + expect(Bun.deepMatch(a, b)).toBe(false); + }); + + it("When comparing same-shape objects with different constructors, returns true", () => { + class Foo {} + class Bar {} + + expect(Bun.deepMatch(new Foo(), new Bar())).toBe(true); + }); + + describe("When provided objects with circular references", () => { + let foo: Record; + + const makeCircular = () => { + let foo = { bar: undefined as any }; + let bar = { foo: undefined as any }; + foo.bar = bar; + bar.foo = foo; + return foo; + }; + + beforeEach(() => { + foo = makeCircular(); + }); + + // a, b are ref equal + it("when a and b are _exactly_ the same object, returns true", () => { + expect(Bun.deepMatch(foo, foo)).toBe(true); + }); + + // a, b are not ref equal but their properties are + it("When a and b are different objects whose properties point to the same object, returns true", () => { + const foo2 = { ...foo }; // pointer to bar is copied. + expect(Bun.deepMatch(foo, foo2)).toBe(true); + }); + + // a, b are structurally equal but share no pointers + it.skip("when a and b are structurally equal but share no pointers, returns true", () => { + const bar = makeCircular(); + expect(Bun.deepMatch(foo, bar)).toBe(true); + }); + + // a, b are neither ref or structurally equal + it("when a and b are different, returns false", () => { + const bar = { bar: undefined } as any; + bar.bar = bar; + expect(Bun.deepMatch(foo, bar)).toBe(false); + }); + }); + + describe("array inputs", () => { + it.each([ + // line break + [[1, 2, 3], [1, 2, 3], true], + ] as [any[], any[], boolean][])("Bun.deepMatch(%p, %p) === %p", (a, b, expected) => { + expect(Bun.deepMatch(a, b)).toBe(expected); + }); + }); + + it("does not work on functions", () => { + function foo() {} + function bar() {} + function baz(a) { + return a; + } + expect(Bun.deepMatch(foo, foo)).toBe(true); + expect(Bun.deepMatch(foo, bar)).toBe(true); + // FIXME + // expect(Bun.deepMatch(foo, baz)).toBe(false); + }); + + describe("Invalid arguments", () => { + it.each([ + [null, null], + [undefined, undefined], + [1, 1], + [true, true], + [true, false], + ["a", "a"], + [Symbol.for("a"), Symbol.for("a")], + [Symbol("a"), Symbol("a")], + ])("throws a TypeError for primitives", (a, b) => { + expect(() => Bun.deepMatch(a, b)).toThrow(TypeError); + }); + }); +}); From 903d8bfa4abd872a0d8573e1b56d159bedbdf414 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 17 Dec 2024 01:14:08 -0800 Subject: [PATCH 035/125] Be more careful about setting the rlimit max --- src/fs.zig | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/fs.zig b/src/fs.zig index eec9ef34a8..9f8cd22f24 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -819,10 +819,19 @@ pub const FileSystem = struct { Limit.handles_before = limit; file_limit = limit.max; Limit.handles = file_limit; - if (limit.cur < limit.max or limit.max < 163840) { + const max_to_use: @TypeOf(limit.max) = if (Environment.isMusl) + // musl has extremely low defaults here, so we really want + // to enable this on musl or tests will start failing. + @max(limit.max, 163840) + else + // apparently, requesting too high of a number can cause other processes to not start. + // https://discord.com/channels/876711213126520882/1316342194176790609/1318175562367242271 + // https://github.com/postgres/postgres/blob/fee2b3ea2ecd0da0c88832b37ac0d9f6b3bfb9a9/src/backend/storage/file/fd.c#L1072 + limit.max; + if (limit.cur < max_to_use) { var new_limit = std.mem.zeroes(std.posix.rlimit); - new_limit.cur = @max(limit.max, 163840); - new_limit.max = @max(limit.max, 163840); + new_limit.cur = max_to_use; + new_limit.max = max_to_use; std.posix.setrlimit(resource, new_limit) catch break :blk; file_limit = new_limit.max; From eecbeb32ec636c721c6d216d1c46d4428f9f824e Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 17 Dec 2024 01:31:14 -0800 Subject: [PATCH 036/125] Move bundler plugin docs --- docs/bundler/plugins.md | 346 +++++++++++++++++++++++++++++++++++++++- docs/runtime/plugins.md | 147 ----------------- 2 files changed, 345 insertions(+), 148 deletions(-) diff --git a/docs/bundler/plugins.md b/docs/bundler/plugins.md index 6ac9654f0f..c71117b53e 100644 --- a/docs/bundler/plugins.md +++ b/docs/bundler/plugins.md @@ -2,7 +2,43 @@ Bun provides a universal plugin API that can be used to extend both the _runtime Plugins intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to add support for additional file types, like `.scss` or `.yaml`. In the context of Bun's bundler, plugins can be used to implement framework-level features like CSS extraction, macros, and client-server code co-location. -For more complete documentation of the Plugin API, see [Runtime > Plugins](https://bun.sh/docs/runtime/plugins). +## Lifecycle hooks + +Plugins can register callbacks to be run at various points in the lifecycle of a bundle: + +- [`onStart()`](#onstart): Run once the bundler has started a bundle +- [`onResolve()`](#onresolve): Run before a module is resolved +- [`onLoad()`](#onload): Run before a module is loaded. +- [`onBeforeParse()`](#onbeforeparse): Run zero-copy native addons in the parser thread before a file is parsed. + +### Reference + +A rough overview of the types (please refer to Bun's `bun.d.ts` for the full type definitions): + +```ts +type PluginBuilder = { + onStart(callback: () => void): void; + onResolve: ( + args: { filter: RegExp; namespace?: string }, + callback: (args: { path: string; importer: string }) => { + path: string; + namespace?: string; + } | void, + ) => void; + onLoad: ( + args: { filter: RegExp; namespace?: string }, + defer: () => Promise, + callback: (args: { path: string }) => { + loader?: Loader; + contents?: string; + exports?: Record; + }, + ) => void; + config: BuildConfig; +}; + +type Loader = "js" | "jsx" | "ts" | "tsx" | "css" | "json" | "toml" | "object"; +``` ## Usage @@ -28,3 +64,311 @@ Bun.build({ plugins: [myPlugin], }); ``` + +## Plugin lifecycle + +### Namespaces + +`onLoad` and `onResolve` accept an optional `namespace` string. What is a namespaace? + +Every module has a namespace. Namespaces are used to prefix the import in transpiled code; for instance, a loader with a `filter: /\.yaml$/` and `namespace: "yaml:"` will transform an import from `./myfile.yaml` into `yaml:./myfile.yaml`. + +The default namespace is `"file"` and it is not necessary to specify it, for instance: `import myModule from "./my-module.ts"` is the same as `import myModule from "file:./my-module.ts"`. + +Other common namespaces are: + +- `"bun"`: for Bun-specific modules (e.g. `"bun:test"`, `"bun:sqlite"`) +- `"node"`: for Node.js modules (e.g. `"node:fs"`, `"node:path"`) + +### `onStart` + +```ts +onStart(callback: () => void): Promise | void; +``` + +Registers a callback to be run when the bundler starts a new bundle. + +```ts +import { plugin } from "bun"; + +plugin({ + name: "onStart example", + + setup(build) { + build.onStart(() => { + console.log("Bundle started!"); + }); + }, +}); +``` + +The callback can return a `Promise`. After the bundle process has initialized, the bundler waits until all `onStart()` callbacks have completed before continuing. + +For example: + +```ts +const result = await Bun.build({ + entrypoints: ["./app.ts"], + outdir: "./dist", + sourcemap: "external", + plugins: [ + { + name: "Sleep for 10 seconds", + setup(build) { + build.onStart(async () => { + await Bunlog.sleep(10_000); + }); + }, + }, + { + name: "Log bundle time to a file", + setup(build) { + build.onStart(async () => { + const now = Date.now(); + await Bun.$`echo ${now} > bundle-time.txt`; + }); + }, + }, + ], +}); +``` + +In the above example, Bun will wait until the first `onStart()` (sleeping for 10 seconds) has completed, _as well as_ the second `onStart()` (writing the bundle time to a file). + +Note that `onStart()` callbacks (like every other lifecycle callback) do not have the ability to modify the `build.config` object. If you want to mutate `build.config`, you must do so directly in the `setup()` function. + +### `onResolve` + +```ts +onResolve( + args: { filter: RegExp; namespace?: string }, + callback: (args: { path: string; importer: string }) => { + path: string; + namespace?: string; + } | void, +): void; +``` + +To bundle your project, Bun walks down the dependency tree of all modules in your project. For each imported module, Bun actually has to find and read that module. The "finding" part is known as "resolving" a module. + +The `onResolve()` plugin lifecycle callback allows you to configure how a module is resolved. + +The first argument to `onResolve()` is an object with a `filter` and [`namespace`](#what-is-a-namespace) property. The filter is a regular expression which is run on the import string. Effectively, these allow you to filter which modules your custom resolution logic will apply to. + +The second argument to `onResolve()` is a callback which is run for each module import Bun finds that matches the `filter` and `namespace` defined in the first argument. + +The callback receives as input the _path_ to the matching module. The callback can return a _new path_ for the module. Bun will read the contents of the _new path_ and parse it as a module. + +For example, redirecting all imports to `images/` to `./public/images/`: + +```ts +import { plugin } from "bun"; + +plugin({ + name: "onResolve example", + setup(build) { + build.onResolve({ filter: /.*/, namespace: "file" }, args => { + if (args.path.startsWith("images/")) { + return { + path: args.path.replace("images/", "./public/images/"), + }; + } + }); + }, +}); +``` + +### `onLoad` + +```ts +onLoad( + args: { filter: RegExp; namespace?: string }, + defer: () => Promise, + callback: (args: { path: string, importer: string, namespace: string, kind: ImportKind }) => { + loader?: Loader; + contents?: string; + exports?: Record; + }, +): void; +``` + +After Bun's bundler has resolved a module, it needs to read the contents of the module and parse it. + +The `onLoad()` plugin lifecycle callback allows you to modify the _contents_ of a module before it is read and parsed by Bun. + +Like `onResolve()`, the first argument to `onLoad()` allows you to filter which modules this invocation of `onLoad()` will apply to. + +The second argument to `onLoad()` is a callback which is run for each matching module _before_ Bun loads the contents of the module into memory. + +This callback receives as input the _path_ to the matching module, the _importer_ of the module (the module that imported the module), the _namespace_ of the module, and the _kind_ of the module. + +The callback can return a new `contents` string for the module as well as a new `loader`. + +For example: + +```ts +import { plugin } from "bun"; + +const envPlugin: BunPlugin = { + name: "env plugin", + setup(build) { + build.onLoad({ filter: /env/, namespace: "file" }, args => { + return { + contents: `export default ${JSON.stringify(process.env)}`, + loader: "js", + }; + }); + }, +}); + +Bun.build({ + entrypoints: ["./app.ts"], + outdir: "./dist", + plugins: [envPlugin], +}); + +// import env from "env" +// env.FOO === "bar" +``` + +This plugin will transform all imports of the form `import env from "env"` into a JavaScript module that exports the current environment variables. + +#### `.defer()` + +One of the arguments passed to the `onLoad` callback is a `defer` function. This function returns a `Promise` that is resolved when all _other_ modules have been loaded. + +This allows you to delay execution of the `onLoad` callback until all other modules have been loaded. + +This is useful for returning contens of a module that depends on other modules. + +##### Example: tracking and reporting unused exports + +```ts +import { plugin } from "bun"; + +plugin({ + name: "track imports", + setup(build) { + const transpiler = new Bun.Transpiler(); + + let trackedImports: Record = {}; + + // Each module that goes through this onLoad callback + // will record its imports in `trackedImports` + build.onLoad({ filter: /\.ts/ }, async ({ path }) => { + const contents = await Bun.file(path).arrayBuffer(); + + const imports = transpiler.scanImports(contents); + + for (const i of imports) { + trackedImports[i.path] = (trackedImports[i.path] || 0) + 1; + } + + return undefined; + }); + + build.onLoad({ filter: /stats\.json/ }, async ({ defer }) => { + // Wait for all files to be loaded, ensuring + // that every file goes through the above `onLoad()` function + // and their imports tracked + await defer(); + + // Emit JSON containing the stats of each import + return { + contents: `export default ${JSON.stringify(trackedImports)}`, + loader: "json", + }; + }); + }, +}); +``` + +Note that the `.defer()` function currently has the limitation that it can only be called once per `onLoad` callback. + +## Native plugins + +One of the reasons why Bun's bundler is so fast is that it is written in native code and leverages multi-threading to load and parse modules in parallel. + +However, one limitation of plugins written in JavaScript is that JavaScript itself is single-threaded. + +Native plugins are written as [NAPI](/docs/node-api) modules and can be run on multiple threads. This allows native plugins to run much faster than JavaScript plugins. + +In addition, native plugins can skip unnecessary work such as the UTF-8 -> UTF-16 conversion needed to pass strings to JavaScript. + +These are the following lifecycle hooks which are available to native plugins: + +- [`onBeforeParse()`](#onbeforeparse): Called on any thread before a file is parsed by Bun's bundler. + +Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions. + +To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement. + +### Creating a native plugin in Rust + +Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions. + +To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement. + +ve bundler plugins are NAPI modules, the easiest way to get started is to create a new [napi-rs](https://github.com/napi-rs/napi-rs) project: + +```bash +bun add -g @napi-rs/cli +napi new +``` + +Then install this crate: + +```bash +cargo add bun-native-plugin +``` + +Now, inside the `lib.rs` file, we'll use the `bun_native_plugin::bun` proc macro to define a function which +will implement our native plugin. + +Here's an example implementing the `onBeforeParse` hook: + +```rs +use bun_native_plugin::{define_bun_plugin, OnBeforeParse, bun, Result, anyhow, BunLoader}; +use napi_derive::napi; + +/// Define the plugin and its name +define_bun_plugin!("replace-foo-with-bar"); + +/// Here we'll implement `onBeforeParse` with code that replaces all occurrences of +/// `foo` with `bar`. +/// +/// We use the #[bun] macro to generate some of the boilerplate code. +/// +/// The argument of the function (`handle: &mut OnBeforeParse`) tells +/// the macro that this function implements the `onBeforeParse` hook. +#[bun] +pub fn replace_foo_with_bar(handle: &mut OnBeforeParse) -> Result<()> { + // Fetch the input source code. + let input_source_code = handle.input_source_code()?; + + // Get the Loader for the file + let loader = handle.output_loader(); + + + let output_source_code = input_source_code.replace("foo", "bar"); + + handle.set_output_source_code(output_source_code, BunLoader::BUN_LOADER_JSX); + + Ok(()) +} +``` + +### `onBeforeParse` + +```ts +onBeforeParse( + args: { filter: RegExp; namespace?: string }, + callback: { napiModule: NapiModule; symbol: string; external?: unknown }, +): void; +``` + +This lifecycle callback is run immediately before a file is parsed by Bun's bundler. + +As input, it receives the file's contents and can optionally return new source code. + +This callback can be called from any thread and so the napi module implementation must be thread-safe. diff --git a/docs/runtime/plugins.md b/docs/runtime/plugins.md index 129d129936..e555e232e3 100644 --- a/docs/runtime/plugins.md +++ b/docs/runtime/plugins.md @@ -553,150 +553,3 @@ plugin({ ``` This plugin will transform all imports of the form `import env from "env"` into a JavaScript module that exports the current environment variables. - -#### `.defer()` - -One of the arguments passed to the `onLoad` callback is a `defer` function. This function returns a `Promise` that is resolved when all _other_ modules have been loaded. - -This allows you to delay execution of the `onLoad` callback until all other modules have been loaded. - -This is useful for returning contens of a module that depends on other modules. - -##### Example: tracking and reporting unused exports - -```ts -import { plugin } from "bun"; - -plugin({ - name: "track imports", - setup(build) { - const transpiler = new Bun.Transpiler(); - - let trackedImports: Record = {}; - - // Each module that goes through this onLoad callback - // will record its imports in `trackedImports` - build.onLoad({ filter: /\.ts/ }, async ({ path }) => { - const contents = await Bun.file(path).arrayBuffer(); - - const imports = transpiler.scanImports(contents); - - for (const i of imports) { - trackedImports[i.path] = (trackedImports[i.path] || 0) + 1; - } - - return undefined; - }); - - build.onLoad({ filter: /stats\.json/ }, async ({ defer }) => { - // Wait for all files to be loaded, ensuring - // that every file goes through the above `onLoad()` function - // and their imports tracked - await defer(); - - // Emit JSON containing the stats of each import - return { - contents: `export default ${JSON.stringify(trackedImports)}`, - loader: "json", - }; - }); - }, -}); -``` - -Note that the `.defer()` function currently has the limitation that it can only be called once per `onLoad` callback. - -## Native plugins - -{% callout %} -**NOTE** — This is an advanced and experiemental API recommended for plugin developers who are familiar with systems programming and the C ABI. Use with caution. -{% /callout %} - -One of the reasons why Bun's bundler is so fast is that it is written in native code and leverages multi-threading to load and parse modules in parallel. - -However, one limitation of plugins written in JavaScript is that JavaScript itself is single-threaded. - -Native plugins are written as [NAPI](/docs/node-api) modules and can be run on multiple threads. This allows native plugins to run much faster than JavaScript plugins. - -In addition, native plugins can skip unnecessary work such as the UTF-8 -> UTF-16 conversion needed to pass strings to JavaScript. - -These are the following lifecycle hooks which are available to native plugins: - -- [`onBeforeParse()`](#onbeforeparse): Called on any thread before a file is parsed by Bun's bundler. - -### Creating a native plugin - -Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions. - -To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement. - -#### Example: Rust with napi-rs - -First initialize a napi project (see [here](https://napi.rs/docs/introduction/getting-started) for a more comprehensive guide). - -Then install Bun's official safe plugin wrapper crate: - -```bash -cargo add bun-native-plugin -``` - -Now you can export an `extern "C" fn` which is the implementation of your plugin: - -```rust -#[no_mangle] -extern "C" fn on_before_parse_impl( - args: *const bun_native_plugin::sys::OnBeforeParseArguments, - result: *mut bun_native_plugin::sys::OnBeforeParseResult, -) { - let args = unsafe { &*args }; - let result = unsafe { &mut *result }; - - let mut handle = match bun_native_plugin::OnBeforeParse::from_raw(args, result) { - Ok(handle) => handle, - Err(_) => { - return; - } - }; - - let source_code = match handle.input_source_code() { - Ok(source_code) => source_code, - Err(_) => { - handle.log_error("Fetching source code failed!"); - return; - } - }; - - let loader = handle.output_loader(); - handle.set_output_source_code(source_code.replace("foo", "bar"), loader); -``` - -Use napi-rs to compile the plugin to a `.node` file, then you can `require()` it from JS and use it: - -```js -await Bun.build({ - entrypoints: ["index.ts"], - setup(build) { - const myNativePlugin = require("./path/to/plugin.node"); - - build.onBeforeParse( - { filter: /\.ts/ }, - { napiModule: myNativePlugin, symbol: "on_before_parse_impl" }, - ); - }, -}); -``` - -### `onBeforeParse` - -```ts -onBeforeParse( - args: { filter: RegExp; namespace?: string }, - callback: { napiModule: NapiModule; symbol: string; external?: unknown }, -): void; -``` - -This lifecycle callback is run immediately before a file is parsed by Bun's bundler. - -As input, it receives the file's contents and can optionally return new source code. - -This callback can be called from any thread and so the napi module implementation must be thread-safe. From 385868f504e1661d48e8a99c6b3d25ca8b42cc2c Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 17 Dec 2024 01:34:00 -0800 Subject: [PATCH 037/125] Update plugins.md --- docs/bundler/plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bundler/plugins.md b/docs/bundler/plugins.md index c71117b53e..1aae9b51f0 100644 --- a/docs/bundler/plugins.md +++ b/docs/bundler/plugins.md @@ -42,7 +42,7 @@ type Loader = "js" | "jsx" | "ts" | "tsx" | "css" | "json" | "toml" | "object"; ## Usage -A plugin is defined as simple JavaScript object containing a `name` property and a `setup` function. Register a plugin with Bun using the `plugin` function. +A plugin is defined as simple JavaScript object containing a `name` property and a `setup` function. ```tsx#myPlugin.ts import type { BunPlugin } from "bun"; From f2e0d606b6635cef6a715ca4f1dd682971a90f57 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 17 Dec 2024 01:34:17 -0800 Subject: [PATCH 038/125] Update plugins.md --- docs/bundler/plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bundler/plugins.md b/docs/bundler/plugins.md index 1aae9b51f0..44fa937d3f 100644 --- a/docs/bundler/plugins.md +++ b/docs/bundler/plugins.md @@ -37,7 +37,7 @@ type PluginBuilder = { config: BuildConfig; }; -type Loader = "js" | "jsx" | "ts" | "tsx" | "css" | "json" | "toml" | "object"; +type Loader = "js" | "jsx" | "ts" | "tsx" | "css" | "json" | "toml"; ``` ## Usage From 1d4856170978abe3aa47960e2fd7d4f400423808 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 17 Dec 2024 01:49:02 -0800 Subject: [PATCH 039/125] Update plugins.md --- docs/bundler/plugins.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/bundler/plugins.md b/docs/bundler/plugins.md index 44fa937d3f..0cfd29ade6 100644 --- a/docs/bundler/plugins.md +++ b/docs/bundler/plugins.md @@ -309,8 +309,6 @@ Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions. To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement. -ve bundler plugins are NAPI modules, the easiest way to get started is to create a new [napi-rs](https://github.com/napi-rs/napi-rs) project: - ```bash bun add -g @napi-rs/cli napi new @@ -358,6 +356,34 @@ pub fn replace_foo_with_bar(handle: &mut OnBeforeParse) -> Result<()> { } ``` +And to use it in Bun.build(): + +```typescript +import myNativeAddon from "./my-native-addon"; +Bun.build({ + entrypoints: ["./app.tsx"], + plugins: [ + { + name: "my-plugin", + + setup(build) { + build.onBeforeParse( + { + namespace: "file", + filter: "**/*.tsx", + }, + { + napiModule: myNativeAddon, + symbol: "replace_foo_with_bar", + // external: myNativeAddon.getSharedState() + }, + ); + }, + }, + ], +}); +``` + ### `onBeforeParse` ```ts From b7efaa5b19318fba1786a49bc845d0c9cec0db01 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 17 Dec 2024 15:30:18 -0800 Subject: [PATCH 040/125] Bump --- LATEST | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LATEST b/LATEST index c99926d330..f2f5ed4e0b 100644 --- a/LATEST +++ b/LATEST @@ -1 +1 @@ -1.1.38 \ No newline at end of file +1.1.39 \ No newline at end of file diff --git a/package.json b/package.json index f32b639df7..79db159c7d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "bun", - "version": "1.1.39", + "version": "1.1.40", "workspaces": [ "./packages/bun-types" ], From ad1738d23cb43356f192c96f90cd93c001c130fa Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 17 Dec 2024 16:51:19 -0800 Subject: [PATCH 041/125] Fix process.on from non-mainthread (#15825) --- src/bun.js/bindings/BunProcess.cpp | 3 +- src/bun.js/event_loop.zig | 15 ++-- src/bun.js/javascript.zig | 17 ++++- test/js/node/process/process-on-fixture.ts | 26 +++++++ test/js/node/process/process-on.test.ts | 87 ++++++++++++++++++++++ 5 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 test/js/node/process/process-on-fixture.ts create mode 100644 test/js/node/process/process-on.test.ts diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 5be9e86cdc..452c89b97e 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -940,10 +940,11 @@ extern "C" void Bun__setChannelRef(GlobalObject* globalObject, bool enabled) } } extern "C" void Bun__ensureSignalHandler(); +extern "C" bool Bun__isMainThreadVM(); extern "C" void Bun__onPosixSignal(int signalNumber); static void onDidChangeListeners(EventEmitter& eventEmitter, const Identifier& eventName, bool isAdded) { - if (eventEmitter.scriptExecutionContext()->isMainThread()) { + if (Bun__isMainThreadVM()) { // IPC handlers if (eventName.string() == "message"_s || eventName.string() == "disconnect"_s) { auto* global = jsCast(eventEmitter.scriptExecutionContext()->jsGlobalObject()); diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index cad5a65525..8705a7b08f 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -787,11 +787,12 @@ pub const EventLoop = struct { pub export fn Bun__ensureSignalHandler() void { if (Environment.isPosix) { - const vm = JSC.VirtualMachine.getMainThreadVM(); - const this = vm.eventLoop(); - if (this.signal_handler == null) { - this.signal_handler = PosixSignalHandle.new(.{}); - @memset(&this.signal_handler.?.signals, 0); + if (JSC.VirtualMachine.getMainThreadVM()) |vm| { + const this = vm.eventLoop(); + if (this.signal_handler == null) { + this.signal_handler = PosixSignalHandle.new(.{}); + @memset(&this.signal_handler.?.signals, 0); + } } } } @@ -2356,7 +2357,7 @@ pub const PosixSignalHandle = struct { // Publish the new tail (Release so that the consumer sees the updated tail). this.tail.store(old_tail +% 1, .release); - JSC.VirtualMachine.getMainThreadVM().eventLoop().wakeup(); + JSC.VirtualMachine.getMainThreadVM().?.eventLoop().wakeup(); return true; } @@ -2364,7 +2365,7 @@ pub const PosixSignalHandle = struct { /// This is the signal handler entry point. Calls enqueue on the ring buffer. /// Note: Must be minimal logic here. Only do atomics & signal‐safe calls. export fn Bun__onPosixSignal(number: i32) void { - const vm = JSC.VirtualMachine.getMainThreadVM(); + const vm = JSC.VirtualMachine.getMainThreadVM().?; _ = vm.eventLoop().signal_handler.?.enqueue(@intCast(number)); } diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index e12bfc4873..14811872f2 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -972,10 +972,15 @@ pub const VirtualMachine = struct { pub const VMHolder = struct { pub threadlocal var vm: ?*VirtualMachine = null; pub threadlocal var cached_global_object: ?*JSGlobalObject = null; - pub var main_thread_vm: *VirtualMachine = undefined; + pub var main_thread_vm: ?*VirtualMachine = null; pub export fn Bun__setDefaultGlobalObject(global: *JSGlobalObject) void { if (vm) |vm_instance| { vm_instance.global = global; + + // Ensure this is always set when it should be. + if (vm_instance.is_main_thread) { + VMHolder.main_thread_vm = vm_instance; + } } cached_global_object = global; @@ -995,7 +1000,7 @@ pub const VirtualMachine = struct { return VMHolder.vm.?; } - pub fn getMainThreadVM() *VirtualMachine { + pub fn getMainThreadVM() ?*VirtualMachine { return VMHolder.main_thread_vm; } @@ -1931,7 +1936,9 @@ pub const VirtualMachine = struct { vm.bundler.configureLinkerWithAutoJSX(false); vm.bundler.macro_context = js_ast.Macro.MacroContext.init(&vm.bundler); - + if (opts.is_main_thread) { + VMHolder.main_thread_vm = vm; + } vm.global = ZigGlobalObject.create( vm.console, -1, @@ -1949,6 +1956,10 @@ pub const VirtualMachine = struct { return vm; } + export fn Bun__isMainThreadVM() callconv(.C) bool { + return get().is_main_thread; + } + pub const Options = struct { allocator: std.mem.Allocator, args: Api.TransformOptions, diff --git a/test/js/node/process/process-on-fixture.ts b/test/js/node/process/process-on-fixture.ts new file mode 100644 index 0000000000..61d57ecad4 --- /dev/null +++ b/test/js/node/process/process-on-fixture.ts @@ -0,0 +1,26 @@ +export function initialize() { + const handler = () => { + console.log("SIGINT"); + }; + + const handler2 = () => { + console.log("SIGTERM"); + }; + + process.on("SIGINT", handler); + process.on("SIGTERM", handler2); + process.off("SIGTERM", handler2); + process.off("SIGINT", handler); + + process.on("SIGINT", handler); + process.on("SIGTERM", handler2); + process.off("SIGTERM", handler2); + process.off("SIGINT", handler); + + process.on("SIGINT", handler); + process.on("SIGTERM", handler2); + process.off("SIGTERM", handler2); + process.off("SIGINT", handler); +} + +initialize(); diff --git a/test/js/node/process/process-on.test.ts b/test/js/node/process/process-on.test.ts new file mode 100644 index 0000000000..092626b233 --- /dev/null +++ b/test/js/node/process/process-on.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, it } from "bun:test"; +import { bunEnv, tempDirWithFiles } from "harness"; +import { bunExe } from "harness"; +import path from "path"; + +describe("process.on", () => { + it("when called from the main thread", () => { + const result = Bun.spawnSync({ + cmd: [bunExe(), path.join(__dirname, "process-on-fixture.ts")], + env: bunEnv, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }); + + expect(result.exitCode).toBe(0); + }); + + it("should work inside --compile", () => { + const dir = tempDirWithFiles("process-on-test", { + "process-on-fixture.ts": require("fs").readFileSync(require.resolve("./process-on-fixture.ts"), "utf-8"), + "package.json": `{ + "name": "process-on-test", + "type": "module", + "scripts": { + "start": "bun run process-on-fixture.ts" + } + }`, + }); + const result1 = Bun.spawnSync({ + cmd: [bunExe(), "build", "--compile", path.join(dir, "./process-on-fixture.ts"), "--outfile=./out"], + env: bunEnv, + cwd: dir, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }); + + expect(result1.exitCode).toBe(0); + + const result2 = Bun.spawnSync({ + cmd: ["./out"], + env: bunEnv, + cwd: dir, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }); + expect(result2.exitCode).toBe(0); + }); + + it("should work inside a macro", () => { + const dir = tempDirWithFiles("process-on-test", { + "process-on-fixture.ts": require("fs").readFileSync(require.resolve("./process-on-fixture.ts"), "utf-8"), + "entry.ts": `import { initialize } from "./process-on-fixture.ts" with {type: "macro"}; + initialize();`, + "package.json": `{ + "name": "process-on-test", + "type": "module", + "scripts": { + "start": "bun run entry.ts" + } + }`, + }); + + expect( + Bun.spawnSync({ + cmd: [bunExe(), "build", "--target=bun", path.join(dir, "entry.ts"), "--outfile=./out.ts"], + env: bunEnv, + cwd: dir, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }).exitCode, + ).toBe(0); + + const result2 = Bun.spawnSync({ + cmd: [bunExe(), "run", "./out.ts"], + env: bunEnv, + cwd: dir, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }); + expect(result2.exitCode).toBe(0); + }); +}); From 430c1dd58379d3a8869e6f33586212d437ae1042 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:52:04 -0800 Subject: [PATCH 042/125] add `install.saveTextLockfile` to `bunfig.toml` (#15827) --- docs/cli/bun-install.md | 4 ++ docs/cli/install.md | 3 + docs/install/index.md | 3 + docs/install/lockfile.md | 18 ++++++ docs/runtime/bunfig.md | 11 ++++ src/api/schema.zig | 2 + src/bunfig.zig | 6 ++ src/install/install.zig | 10 +++- .../__snapshots__/bun-install.test.ts.snap | 17 ++++++ test/cli/install/bun-install.test.ts | 55 ++++++++++++++++++- test/cli/install/dummy.registry.ts | 4 ++ 11 files changed, 129 insertions(+), 4 deletions(-) diff --git a/docs/cli/bun-install.md b/docs/cli/bun-install.md index 20832cc53e..f06e1843e5 100644 --- a/docs/cli/bun-install.md +++ b/docs/cli/bun-install.md @@ -47,6 +47,9 @@ registry = "https://registry.yarnpkg.com/" # Install for production? This is the equivalent to the "--production" CLI argument production = false +# Save a text-based lockfile? This is equivalent to the "--save-text-lockfile" CLI argument +saveTextLockfile = false + # Disallow changes to lockfile? This is the equivalent to the "--frozen-lockfile" CLI argument frozenLockfile = false @@ -108,6 +111,7 @@ export interface Install { scopes: Scopes; registry: Registry; production: boolean; + saveTextLockfile: boolean; frozenLockfile: boolean; dryRun: boolean; optional: boolean; diff --git a/docs/cli/install.md b/docs/cli/install.md index 56212b5c47..2fa9db7461 100644 --- a/docs/cli/install.md +++ b/docs/cli/install.md @@ -174,6 +174,9 @@ peer = true # equivalent to `--production` flag production = false +# equivalent to `--save-text-lockfile` flag +saveTextLockfile = false + # equivalent to `--frozen-lockfile` flag frozenLockfile = false diff --git a/docs/install/index.md b/docs/install/index.md index cdf41b9311..5631b55adb 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -86,6 +86,9 @@ peer = true # equivalent to `--production` flag production = false +# equivalent to `--save-text-lockfile` flag +saveTextLockfile = false + # equivalent to `--frozen-lockfile` flag frozenLockfile = false diff --git a/docs/install/lockfile.md b/docs/install/lockfile.md index 66fb28e2b2..315b90f48d 100644 --- a/docs/install/lockfile.md +++ b/docs/install/lockfile.md @@ -72,6 +72,24 @@ $ bun install --yarn print = "yarn" ``` +### Text-based lockfile + +Bun v1.1.39 introduced `bun.lock`, a JSONC formatted lockfile. `bun.lock` is human-readable and git-diffable without configuration, at [no cost to performance](https://bun.sh/blog/bun-lock-text-lockfile#cached-bun-install-gets-30-faster). + +To generate the lockfile, use `--save-text-lockfile` with `bun install`. You can do this for new projects and existing projects already using `bun.lockb` (resolutions will be preserved). + +```bash +$ bun install --save-text-lockfile +$ head -n3 bun.lock +{ + "lockfileVersion": 0, + "workspaces": { +``` + +Once `bun.lock` is generated, Bun will use it for all subsequent installs and updates through commands that read and modify the lockfile. If both lockfiles exist, `bun.lock` will be choosen over `bun.lockb`. + +Bun v1.2.0 will switch the default lockfile format to `bun.lock`. + {% /codetabs %} {% details summary="Configuring lockfile" %} diff --git a/docs/runtime/bunfig.md b/docs/runtime/bunfig.md index 1bfcd540e5..8a19be1ce5 100644 --- a/docs/runtime/bunfig.md +++ b/docs/runtime/bunfig.md @@ -238,6 +238,17 @@ By default Bun uses caret ranges; if the `latest` version of a package is `2.4.1 exact = false ``` +### `install.saveTextLockfile` + +Generate `bun.lock`, a human-readable text-based lockfile. Once generated, Bun will use this file instead of `bun.lockb`, choosing it over the binary lockfile if both are present. + +Default `false`. In Bun v1.2.0 the default lockfile format will change to `bun.lock`. + +```toml +[install] +saveTextLockfile = true +``` + + + +By default, `Bun.build` only throws if invalid options are provided. Read the `success` property to determine if the build was successful; the `logs` property will contain additional details. ```ts const result = await Bun.build({ @@ -1457,6 +1526,27 @@ if (!result.success) { } ``` +In Bun 1.2, throwing an aggregate error like this will become the default beahavior. You can opt-into it early using the `throw: true` option. + +```ts +try { + const result = await Bun.build({ + entrypoints: ["./index.tsx"], + outdir: "./out", + }); +} catch (e) { + // TypeScript does not allow annotations on the catch clause + const error = e as AggregateError; + console.error("Build Failed"); + + // Example: Using the built-in formatter + console.error(error); + + // Example: Serializing the failure as a JSON string. + console.error(JSON.stringify(error, null, 2)); +} +``` + ## Reference ```ts @@ -1478,39 +1568,23 @@ interface BuildConfig { * * @default "esm" */ - format?: /** - - * ECMAScript Module format - */ - | "esm" - /** - * CommonJS format - * **Experimental** - */ - | "cjs" - /** - * IIFE format - * **Experimental** - */ - | "iife"; + format?: "esm" | "cjs" | "iife"; naming?: | string | { chunk?: string; entry?: string; asset?: string; - }; // | string; + }; root?: string; // project root splitting?: boolean; // default true, enable code splitting plugins?: BunPlugin[]; - // manifest?: boolean; // whether to return manifest external?: string[]; packages?: "bundle" | "external"; publicPath?: string; define?: Record; - // origin?: string; // e.g. http://mydomain.com loader?: { [k in string]: Loader }; - sourcemap?: "none" | "linked" | "inline" | "external" | "linked"; // default: "none", true -> "inline" + sourcemap?: "none" | "linked" | "inline" | "external" | "linked" | boolean; // default: "none", true -> "inline" /** * package.json `exports` conditions used when resolving imports * @@ -1519,6 +1593,18 @@ interface BuildConfig { * https://nodejs.org/api/packages.html#exports */ conditions?: Array | string; + + /** + * Controls how environment variables are handled during bundling. + * + * Can be one of: + * - `"inline"`: Injects environment variables into the bundled output by converting `process.env.FOO` + * references to string literals containing the actual environment variable values + * - `"disable"`: Disables environment variable injection entirely + * - A string ending in `*`: Inlines environment variables that match the given prefix. + * For example, `"MY_PUBLIC_*"` will only include env vars starting with "MY_PUBLIC_" + */ + env?: "inline" | "disable" | `${string}*`; minify?: | boolean | { @@ -1536,20 +1622,6 @@ interface BuildConfig { * Force emitting @__PURE__ annotations even if minify.whitespace is true. */ emitDCEAnnotations?: boolean; - // treeshaking?: boolean; - - // jsx?: - // | "automatic" - // | "classic" - // | /* later: "preserve" */ { - // runtime?: "automatic" | "classic"; // later: "preserve" - // /** Only works when runtime=classic */ - // factory?: string; // default: "React.createElement" - // /** Only works when runtime=classic */ - // fragment?: string; // default: "React.Fragment" - // /** Only works when runtime=automatic */ - // importSource?: string; // default: "react" - // }; /** * Generate bytecode for the output. This can dramatically improve cold @@ -1562,6 +1634,37 @@ interface BuildConfig { * @default false */ bytecode?: boolean; + /** + * Add a banner to the bundled code such as "use client"; + */ + banner?: string; + /** + * Add a footer to the bundled code such as a comment block like + * + * `// made with bun!` + */ + footer?: string; + + /** + * **Experimental** + * + * Enable CSS support. + */ + experimentalCss?: boolean; + + /** + * Drop function calls to matching property accesses. + */ + drop?: string[]; + + /** + * When set to `true`, the returned promise rejects with an AggregateError when a build failure happens. + * When set to `false`, the `success` property of the returned object will be `false` when a build failure happens. + * + * This defaults to `false` in Bun 1.1 and will change to `true` in Bun 1.2 + * as most usage of `Bun.build` forgets to check for errors. + */ + throw?: boolean; } interface BuildOutput { @@ -1619,32 +1722,3 @@ declare class ResolveMessage { toString(): string; } ``` - - diff --git a/docs/bundler/plugins.md b/docs/bundler/plugins.md index 0cfd29ade6..8e6b79c0e7 100644 --- a/docs/bundler/plugins.md +++ b/docs/bundler/plugins.md @@ -58,7 +58,7 @@ const myPlugin: BunPlugin = { This plugin can be passed into the `plugins` array when calling `Bun.build`. ```ts -Bun.build({ +await Bun.build({ entrypoints: ["./app.ts"], outdir: "./out", plugins: [myPlugin], diff --git a/docs/bundler/vs-esbuild.md b/docs/bundler/vs-esbuild.md index 1266914c05..35bb62f6f7 100644 --- a/docs/bundler/vs-esbuild.md +++ b/docs/bundler/vs-esbuild.md @@ -695,7 +695,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot - In Bun, `minify` can be a boolean or an object. ```ts - Bun.build({ + await Bun.build({ entrypoints: ['./index.tsx'], // enable all minification minify: true diff --git a/docs/runtime/modules.md b/docs/runtime/modules.md index 526446751e..cde5890a86 100644 --- a/docs/runtime/modules.md +++ b/docs/runtime/modules.md @@ -259,6 +259,7 @@ await Bun.build({ conditions: ["react-server"], target: "bun", entryPoints: ["./app/foo/route.js"], + throw: true, }); ``` diff --git a/docs/runtime/plugins.md b/docs/runtime/plugins.md index e555e232e3..714fb49191 100644 --- a/docs/runtime/plugins.md +++ b/docs/runtime/plugins.md @@ -307,7 +307,7 @@ await import("my-object-virtual-module"); // { baz: "quix" } Plugins can read and write to the [build config](https://bun.sh/docs/bundler#api) with `build.config`. ```ts -Bun.build({ +await Bun.build({ entrypoints: ["./app.ts"], outdir: "./dist", sourcemap: "external", @@ -324,6 +324,7 @@ Bun.build({ }, }, ], + throw: true, }); ``` @@ -332,7 +333,7 @@ Bun.build({ **NOTE**: Plugin lifcycle callbacks (`onStart()`, `onResolve()`, etc.) do not have the ability to modify the `build.config` object in the `setup()` function. If you want to mutate `build.config`, you must do so directly in the `setup()` function: ```ts -Bun.build({ +await Bun.build({ entrypoints: ["./app.ts"], outdir: "./dist", sourcemap: "external", @@ -350,6 +351,7 @@ Bun.build({ }, }, ], + throw: true, }); ``` diff --git a/packages/bun-inspector-frontend/scripts/build.ts b/packages/bun-inspector-frontend/scripts/build.ts index 08f6e68e15..cbe1737d3a 100644 --- a/packages/bun-inspector-frontend/scripts/build.ts +++ b/packages/bun-inspector-frontend/scripts/build.ts @@ -116,6 +116,7 @@ try { entrypoints: [join(import.meta.dir, "out/manifest.js")], outdir: "out", minify: true, + throw: true, }); const jsFilename = "manifest-" + jsBundle.outputs[0].hash + ".js"; // const cssBundle = await build({ diff --git a/packages/bun-plugin-yaml/README.md b/packages/bun-plugin-yaml/README.md index 556a67bbaf..58450954fa 100644 --- a/packages/bun-plugin-yaml/README.md +++ b/packages/bun-plugin-yaml/README.md @@ -15,7 +15,7 @@ This plugin can be used to support `.yaml` loaders in Bun's bundler by passing i ```ts import yamlPlugin from "bun-plugin-yaml"; -Bun.build({ +await Bun.build({ entrypoints: ["./index.tsx"], // other config diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index c077e3b6f0..1d14d6f15a 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -1544,7 +1544,7 @@ declare module "bun" { define?: Record; // origin?: string; // e.g. http://mydomain.com loader?: { [k in string]: Loader }; - sourcemap?: "none" | "linked" | "inline" | "external" | "linked"; // default: "none", true -> "inline" + sourcemap?: "none" | "linked" | "inline" | "external" | "linked" | boolean; // default: "none", true -> "inline" /** * package.json `exports` conditions used when resolving imports * @@ -1638,6 +1638,15 @@ declare module "bun" { * Drop function calls to matching property accesses. */ drop?: string[]; + + /** + * When set to `true`, the returned promise rejects with an AggregateError when a build failure happens. + * When set to `false`, the `success` property of the returned object will be `false` when a build failure happens. + * + * This defaults to `false` in Bun 1.1 and will change to `true` in Bun 1.2 + * as most usage of `Bun.build` forgets to check for errors. + */ + throw?: boolean; } namespace Password { diff --git a/src/bake/DevServer.zig b/src/bake/DevServer.zig index fc00d222c5..47ba7fac54 100644 --- a/src/bake/DevServer.zig +++ b/src/bake/DevServer.zig @@ -314,7 +314,7 @@ pub fn init(options: Options) bun.JSOOM!*DevServer { dev.framework = dev.framework.resolve(&dev.server_bundler.resolver, &dev.client_bundler.resolver, options.arena) catch { if (dev.framework.is_built_in_react) try bake.Framework.addReactInstallCommandNote(&dev.log); - return global.throwValue(dev.log.toJSAggregateError(global, "Framework is missing required files!")); + return global.throwValue(dev.log.toJSAggregateError(global, bun.String.static("Framework is missing required files!"))); }; errdefer dev.route_lookup.clearAndFree(allocator); diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig index 444e68f3d2..d122808bde 100644 --- a/src/bun.js/api/JSBundler.zig +++ b/src/bun.js/api/JSBundler.zig @@ -79,6 +79,7 @@ pub const JSBundler = struct { css_chunking: bool = false, drop: bun.StringSet = bun.StringSet.init(bun.default_allocator), has_any_on_before_parse: bool = false, + throw_on_error: bool = if (bun.FeatureFlags.breaking_changes_1_2) true else false, env_behavior: Api.DotEnvBehavior = if (!bun.FeatureFlags.breaking_changes_1_2) .load_all else .disable, env_prefix: OwnedString = OwnedString.initEmpty(bun.default_allocator), @@ -506,6 +507,10 @@ pub const JSBundler = struct { }; } + if (try config.getBooleanLoose(globalThis, "throw")) |flag| { + this.throw_on_error = flag; + } + return this; } diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index b708cc6810..260b82c242 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -1690,6 +1690,12 @@ pub const BundleV2 = struct { bundler.configureLinker(); try bundler.configureDefines(); + if (bun.FeatureFlags.breaking_changes_1_2) { + if (!bundler.options.production) { + try bundler.options.conditions.appendSlice(&.{"development"}); + } + } + bundler.resolver.opts = bundler.options; } @@ -1717,11 +1723,16 @@ pub const BundleV2 = struct { this.poll_ref.unref(globalThis.bunVM()); const promise = this.promise.swap(); - const root_obj = JSC.JSValue.createEmptyObject(globalThis, 2); switch (this.result) { .pending => unreachable, - .err => { + .err => brk: { + if (this.config.throw_on_error) { + promise.reject(globalThis, this.log.toJSAggregateError(globalThis, bun.String.static("Bundle failed"))); + break :brk; + } + + const root_obj = JSC.JSValue.createEmptyObject(globalThis, 3); root_obj.put(globalThis, JSC.ZigString.static("outputs"), JSC.JSValue.createEmptyArray(globalThis, 0)); root_obj.put( globalThis, @@ -1733,8 +1744,10 @@ pub const BundleV2 = struct { JSC.ZigString.static("logs"), this.log.toJSArray(globalThis, bun.default_allocator), ); + promise.resolve(globalThis, root_obj); }, .value => |*build| { + const root_obj = JSC.JSValue.createEmptyObject(globalThis, 3); const output_files: []options.OutputFile = build.output_files.items; const output_files_js = JSC.JSValue.createEmptyArray(globalThis, output_files.len); if (output_files_js == .zero) { @@ -1799,10 +1812,13 @@ pub const BundleV2 = struct { JSC.ZigString.static("logs"), this.log.toJSArray(globalThis, bun.default_allocator), ); + promise.resolve(globalThis, root_obj); }, } - promise.resolve(globalThis, root_obj); + if (Environment.isDebug) { + bun.assert(promise.status(globalThis.vm()) != .pending); + } } }; diff --git a/src/cli/build_command.zig b/src/cli/build_command.zig index 3a975221f6..f9600fd335 100644 --- a/src/cli/build_command.zig +++ b/src/cli/build_command.zig @@ -217,6 +217,13 @@ pub const BuildCommand = struct { try this_bundler.configureDefines(); this_bundler.configureLinker(); + if (bun.FeatureFlags.breaking_changes_1_2) { + // This is currently done in DevServer by default, but not in Bun.build + if (!this_bundler.options.production) { + try this_bundler.options.conditions.appendSlice(&.{"development"}); + } + } + this_bundler.resolver.opts = this_bundler.options; this_bundler.options.jsx.development = !this_bundler.options.production; this_bundler.resolver.opts.jsx.development = this_bundler.options.jsx.development; @@ -237,6 +244,7 @@ pub const BuildCommand = struct { client_bundler.options = this_bundler.options; client_bundler.options.target = .browser; client_bundler.options.server_components = true; + client_bundler.options.conditions = try this_bundler.options.conditions.clone(); try this_bundler.options.conditions.appendSlice(&.{"react-server"}); this_bundler.options.react_fast_refresh = false; this_bundler.options.minify_syntax = true; diff --git a/src/codegen/bundle-functions.ts b/src/codegen/bundle-functions.ts index 7756e44afd..0cebe25825 100644 --- a/src/codegen/bundle-functions.ts +++ b/src/codegen/bundle-functions.ts @@ -223,7 +223,9 @@ $$capture_start$$(${fn.async ? "async " : ""}${ define, target: "bun", minify: { syntax: true, whitespace: false }, + throw: true, }); + // TODO: Wait a few versions before removing this if (!build.success) { throw new AggregateError(build.logs, "Failed bundling builtin function " + fn.name + " from " + basename + ".ts"); } diff --git a/src/logger.zig b/src/logger.zig index 516dd70ed8..d0af8cb71e 100644 --- a/src/logger.zig +++ b/src/logger.zig @@ -742,35 +742,15 @@ pub const Log = struct { } /// unlike toJS, this always produces an AggregateError object - pub fn toJSAggregateError(this: Log, global: *JSC.JSGlobalObject, message: []const u8) JSC.JSValue { - const msgs: []const Msg = this.msgs.items; - - // TODO: remove arbitrary upper limit. cannot use the heap because - // values could be GC'd. to do this correctly, expose a binding that - // allows creating an AggregateError using an array - var errors_stack: [256]JSC.JSValue = undefined; - - const count = @min(msgs.len, errors_stack.len); - - for (msgs[0..count], 0..) |msg, i| { - errors_stack[i] = switch (msg.metadata) { - .build => JSC.BuildMessage.create(global, bun.default_allocator, msg), - .resolve => JSC.ResolveMessage.create(global, bun.default_allocator, msg, ""), - }; - } - - const out = JSC.ZigString.init(message); - return global.createAggregateError(errors_stack[0..count], &out); + pub fn toJSAggregateError(this: Log, global: *JSC.JSGlobalObject, message: bun.String) JSC.JSValue { + return global.createAggregateErrorWithArray(message, this.toJSArray(global, bun.default_allocator)); } pub fn toJSArray(this: Log, global: *JSC.JSGlobalObject, allocator: std.mem.Allocator) JSC.JSValue { const msgs: []const Msg = this.msgs.items; - const errors_stack: [256]*anyopaque = undefined; - const count = @as(u16, @intCast(@min(msgs.len, errors_stack.len))); - var arr = JSC.JSValue.createEmptyArray(global, count); - - for (msgs[0..count], 0..) |msg, i| { + const arr = JSC.JSValue.createEmptyArray(global, msgs.len); + for (msgs, 0..) |msg, i| { arr.putIndex(global, @as(u32, @intCast(i)), msg.toJS(global, allocator)); } diff --git a/src/options.zig b/src/options.zig index 4bccea93e6..1b1a674686 100644 --- a/src/options.zig +++ b/src/options.zig @@ -909,9 +909,9 @@ pub const defaultLoaders = bun.ComptimeStringMap(Loader, default_loaders); // https://webpack.js.org/guides/package-exports/#reference-syntax pub const ESMConditions = struct { - default: ConditionsMap = undefined, - import: ConditionsMap = undefined, - require: ConditionsMap = undefined, + default: ConditionsMap, + import: ConditionsMap, + require: ConditionsMap, pub fn init(allocator: std.mem.Allocator, defaults: []const string) !ESMConditions { var default_condition_amp = ConditionsMap.init(allocator); @@ -936,22 +936,37 @@ pub const ESMConditions = struct { import_condition_map.putAssumeCapacity("default", {}); require_condition_map.putAssumeCapacity("default", {}); - return ESMConditions{ + return .{ .default = default_condition_amp, .import = import_condition_map, .require = require_condition_map, }; } + pub fn clone(self: *const ESMConditions) !ESMConditions { + var default = try self.default.clone(); + errdefer default.deinit(); + var import = try self.import.clone(); + errdefer import.deinit(); + var require = try self.require.clone(); + errdefer require.deinit(); + + return .{ + .default = default, + .import = import, + .require = require, + }; + } + pub fn appendSlice(self: *ESMConditions, conditions: []const string) !void { try self.default.ensureUnusedCapacity(conditions.len); try self.import.ensureUnusedCapacity(conditions.len); try self.require.ensureUnusedCapacity(conditions.len); for (conditions) |condition| { - self.default.putAssumeCapacityNoClobber(condition, {}); - self.import.putAssumeCapacityNoClobber(condition, {}); - self.require.putAssumeCapacityNoClobber(condition, {}); + self.default.putAssumeCapacity(condition, {}); + self.import.putAssumeCapacity(condition, {}); + self.require.putAssumeCapacity(condition, {}); } } }; @@ -1714,11 +1729,6 @@ pub const BundleOptions = struct { opts.conditions = try ESMConditions.init(allocator, opts.target.defaultConditions()); - if (bun.FeatureFlags.breaking_changes_1_2) { - // This is currently done in DevServer by default, but not in Bun.build - @compileError("if (!production) { add \"development\" condition }"); - } - if (transform.conditions.len > 0) { opts.conditions.appendSlice(transform.conditions) catch bun.outOfMemory(); } diff --git a/test/bundler/bun-build-api.test.ts b/test/bundler/bun-build-api.test.ts index df1624622e..3ea2c0416a 100644 --- a/test/bundler/bun-build-api.test.ts +++ b/test/bundler/bun-build-api.test.ts @@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"; import { readFileSync, writeFileSync } from "fs"; import { bunEnv, bunExe, tempDirWithFiles } from "harness"; import path, { join } from "path"; +import assert from "assert"; describe("Bun.build", () => { test("experimentalCss = true works", async () => { @@ -175,6 +176,26 @@ describe("Bun.build", () => { Bun.gc(true); }); + test("`throw: true` works", async () => { + Bun.gc(true); + try { + await Bun.build({ + entrypoints: [join(import.meta.dir, "does-not-exist.ts")], + throw: true, + }); + expect.unreachable(); + } catch (e) { + assert(e instanceof AggregateError); + expect(e.errors).toHaveLength(1); + expect(e.errors[0]).toBeInstanceOf(BuildMessage); + expect(e.errors[0].message).toMatch(/ModuleNotFound/); + expect(e.errors[0].name).toBe("BuildMessage"); + expect(e.errors[0].position).toEqual(null); + expect(e.errors[0].level).toEqual("error"); + Bun.gc(true); + } + }); + test("returns output files", async () => { Bun.gc(true); const build = await Bun.build({ diff --git a/test/bundler/bundler_bun.test.ts b/test/bundler/bundler_bun.test.ts index 43b29c517e..9638fe5254 100644 --- a/test/bundler/bundler_bun.test.ts +++ b/test/bundler/bundler_bun.test.ts @@ -102,4 +102,51 @@ error: Hello World`, }, run: { stdout: "" }, }); + if (Bun.version.startsWith("1.2")) { + throw new Error("TODO: enable these tests please"); + for (const backend of ["api", "cli"] as const) { + itBundled("bun/ExportsConditionsDevelopment" + backend.toUpperCase(), { + files: { + "src/entry.js": `import 'pkg1'`, + "node_modules/pkg1/package.json": /* json */ ` + { + "exports": { + "development": "./custom1.js", + "default": "./default.js" + } + } + `, + "node_modules/pkg1/custom1.js": `console.log('SUCCESS')`, + "node_modules/pkg1/default.js": `console.log('FAIL')`, + }, + backend, + outfile: "out.js", + define: { "process.env.NODE_ENV": '"development"' }, + run: { + stdout: "SUCCESS", + }, + }); + itBundled("bun/ExportsConditionsDevelopmentInProduction" + backend.toUpperCase(), { + files: { + "src/entry.js": `import 'pkg1'`, + "node_modules/pkg1/package.json": /* json */ ` + { + "exports": { + "development": "./custom1.js", + "default": "./default.js" + } + } + `, + "node_modules/pkg1/custom1.js": `console.log('FAIL')`, + "node_modules/pkg1/default.js": `console.log('SUCCESS')`, + }, + backend, + outfile: "/Users/user/project/out.js", + define: { "process.env.NODE_ENV": '"production"' }, + run: { + stdout: "SUCCESS", + }, + }); + } + } }); diff --git a/test/bundler/bundler_defer.test.ts b/test/bundler/bundler_defer.test.ts index c3becd5ac4..7f9bca5f13 100644 --- a/test/bundler/bundler_defer.test.ts +++ b/test/bundler/bundler_defer.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; -import { itBundled } from './expectBundled'; -import { bunExe, bunEnv, tempDirWithFiles } from 'harness'; -import * as path from 'node:path'; +import { itBundled } from "./expectBundled"; +import { bunExe, bunEnv, tempDirWithFiles } from "harness"; +import * as path from "node:path"; describe("defer", () => { { @@ -179,10 +179,12 @@ describe("defer", () => { }, }, ], + throw: true, }); console.log(result); - } catch (err) { + } catch (err: any) { expect(err).toBeDefined(); + expect(err.message).toBe("WOOPS"); return; } throw new Error("DIDNT GET ERROR!"); @@ -213,15 +215,15 @@ describe("defer", () => { console.log("Foo", foo, lmao); `, - "/lmao.ts": ` + "/lmao.ts": ` import { foo } from "./foo.ts"; export const lmao = "lolss"; console.log(foo); `, - "/foo.ts": ` + "/foo.ts": ` export const foo = 'lkdfjlsdf'; console.log('hi')`, - "/a.css": ` + "/a.css": ` h1 { color: blue; } diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index 555e2a9e88..28ad2eb78c 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -1034,6 +1034,7 @@ function expectBundled( ignoreDCEAnnotations, experimentalCss, drop, + define: define ?? {}, } as BuildConfig; if (dotenv) { @@ -1050,12 +1051,9 @@ function expectBundled( const debugFile = `import path from 'path'; import assert from 'assert'; const {plugins} = (${x})({ root: ${JSON.stringify(root)} }); -const options = ${JSON.stringify({ ...buildConfig, plugins: undefined }, null, 2)}; +const options = ${JSON.stringify({ ...buildConfig, throw: true, plugins: undefined }, null, 2)}; options.plugins = typeof plugins === "function" ? [{ name: "plugin", setup: plugins }] : plugins; const build = await Bun.build(options); -if (build.logs) { - throw build.logs; -} for (const [key, blob] of build.outputs) { await Bun.write(path.join(options.outdir, blob.path), blob.result); } diff --git a/test/bundler/native-plugin.test.ts b/test/bundler/native-plugin.test.ts index 10c67d8ce5..8a09905eaf 100644 --- a/test/bundler/native-plugin.test.ts +++ b/test/bundler/native-plugin.test.ts @@ -264,7 +264,7 @@ const many_foo = ["foo","foo","foo","foo","foo","foo","foo"] await Bun.$`echo ${files.map(([fp]) => fp).join("\n")} >> index.ts`; await Bun.$`echo ${files.map(([, varname]) => `console.log(JSON.stringify(${varname}))`).join("\n")} >> index.ts`; - const resultPromise = Bun.build({ + const result = await Bun.build({ outdir, entrypoints: [path.join(tempdir, "index.ts")], plugins: [ @@ -290,12 +290,9 @@ const many_foo = ["foo","foo","foo","foo","foo","foo","foo"] }, }, ], + throw: true, }); - const result = await resultPromise; - - if (!result.success) console.log(result); - expect(result.success).toBeTrue(); const output = await Bun.$`${bunExe()} run dist/index.js`.cwd(tempdir).text(); const outputJsons = output .trim() diff --git a/test/js/bun/css/css-fuzz.test.ts b/test/js/bun/css/css-fuzz.test.ts index 668847af94..6a144bc607 100644 --- a/test/js/bun/css/css-fuzz.test.ts +++ b/test/js/bun/css/css-fuzz.test.ts @@ -183,12 +183,9 @@ if (!isCI) { const result = await Bun.build({ entrypoints: ["invalid.css"], experimentalCss: true, + throw: true, }); - if (result.logs.length > 0) { - throw new AggregateError("CSS parser returned logs", result.logs); - } - // We expect the parser to either throw an error or return a valid result // If it returns undefined/null, that's a potential issue if (result === undefined || result === null) { diff --git a/test/js/bun/css/doesnt_crash.test.ts b/test/js/bun/css/doesnt_crash.test.ts index c7cdad5947..64eaa7172d 100644 --- a/test/js/bun/css/doesnt_crash.test.ts +++ b/test/js/bun/css/doesnt_crash.test.ts @@ -35,6 +35,7 @@ describe("doesnt_crash", async () => { experimentalCss: true, minify: minify, target, + throw: true, }); console.timeEnd(timeLog); @@ -56,6 +57,7 @@ describe("doesnt_crash", async () => { experimentalCss: true, target, minify: minify, + throw: true, }); if (logs?.length) { diff --git a/test/napi/napi.test.ts b/test/napi/napi.test.ts index 7c79e53de0..b00513cb86 100644 --- a/test/napi/napi.test.ts +++ b/test/napi/napi.test.ts @@ -115,6 +115,7 @@ describe("napi", () => { outdir: dir, target, format, + throw: true, }); expect(build.logs).toBeEmpty(); diff --git a/test/regression/issue/14976/14976.test.ts b/test/regression/issue/14976/14976.test.ts index 37e7c72df0..804eb7cc20 100644 --- a/test/regression/issue/14976/14976.test.ts +++ b/test/regression/issue/14976/14976.test.ts @@ -39,6 +39,7 @@ test("bun build --target=bun outputs only ascii", async () => { const build_result = await Bun.build({ entrypoints: [import.meta.dirname + "/import_target.ts"], target: "bun", + throw: true, }); expect(build_result.success).toBe(true); expect(build_result.outputs.length).toBe(1); From 8e20d02b9b7dfb01823b52159e1e2b8ae2c7073d Mon Sep 17 00:00:00 2001 From: Michael H Date: Thu, 19 Dec 2024 14:28:23 +1100 Subject: [PATCH 050/125] update registry scope guide (.npmrc is supported) (#15866) --- docs/guides/install/registry-scope.md | 4 +++- docs/install/npmrc.md | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/guides/install/registry-scope.md b/docs/guides/install/registry-scope.md index a36cde6fb0..0eeb973dee 100644 --- a/docs/guides/install/registry-scope.md +++ b/docs/guides/install/registry-scope.md @@ -2,7 +2,9 @@ name: Configure a private registry for an organization scope with bun install --- -Bun does not read `.npmrc` files; instead private registries are configured via `bunfig.toml`. To configure a registry for a particular npm scope: +Private registries can be configured using either [`.npmrc`](https://bun.sh/docs/install/npmrc) or [`bunfig.toml`](https://bun.sh/docs/runtime/bunfig#install-registry). While both are supported, we recommend using **bunfig.toml** for enhanced flexibility and Bun-specific options. + +To configure a registry for a particular npm scope: ```toml#bunfig.toml [install.scopes] diff --git a/docs/install/npmrc.md b/docs/install/npmrc.md index ae3c074892..3153dd6feb 100644 --- a/docs/install/npmrc.md +++ b/docs/install/npmrc.md @@ -6,7 +6,7 @@ Bun supports loading configuration options from [`.npmrc`](https://docs.npmjs.co {% /callout %} -# Supported options +## Supported options ### `registry`: Set the default registry From ac6723eab7901d561fda0d46a84ee3b86751a860 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 18 Dec 2024 19:41:37 -0800 Subject: [PATCH 051/125] +13 passing node:vm tests (#15865) --- src/bun.js/bindings/BunClientData.cpp | 2 + src/bun.js/bindings/BunClientData.h | 1 + src/bun.js/bindings/ErrorCode.cpp | 1 - src/bun.js/bindings/ErrorCode.ts | 2 + src/bun.js/bindings/NodeVM.cpp | 638 +++++++++++++----- src/bun.js/bindings/NodeVM.h | 114 +--- src/bun.js/bindings/ZigGlobalObject.cpp | 18 +- .../bindings/webcore/DOMClientIsoSubspaces.h | 1 + src/bun.js/bindings/webcore/DOMIsoSubspaces.h | 1 + .../test-vm-create-and-run-in-context.js | 50 ++ .../parallel/test-vm-create-context-arg.js | 40 ++ test/js/node/test/parallel/test-vm-getters.js | 24 + .../test-vm-global-define-property.js | 47 ++ .../test-vm-global-non-writable-properties.js | 15 + .../test-vm-global-property-interceptors.js | 129 ++++ .../test/parallel/test-vm-global-setter.js | 161 +++++ .../parallel/test-vm-inherited_properties.js | 39 ++ .../node/test/parallel/test-vm-not-strict.js | 37 + test/js/node/test/parallel/test-vm-ownkeys.js | 26 + .../test/parallel/test-vm-ownpropertynames.js | 26 + .../parallel/test-vm-ownpropertysymbols.js | 26 + .../parallel/test-vm-preserves-property.js | 25 + .../parallel/test-vm-set-property-proxy.js | 16 + test/js/node/test/parallel/test-vm-symbols.js | 23 + 24 files changed, 1187 insertions(+), 275 deletions(-) create mode 100644 test/js/node/test/parallel/test-vm-create-and-run-in-context.js create mode 100644 test/js/node/test/parallel/test-vm-create-context-arg.js create mode 100644 test/js/node/test/parallel/test-vm-getters.js create mode 100644 test/js/node/test/parallel/test-vm-global-define-property.js create mode 100644 test/js/node/test/parallel/test-vm-global-non-writable-properties.js create mode 100644 test/js/node/test/parallel/test-vm-global-property-interceptors.js create mode 100644 test/js/node/test/parallel/test-vm-global-setter.js create mode 100644 test/js/node/test/parallel/test-vm-inherited_properties.js create mode 100644 test/js/node/test/parallel/test-vm-not-strict.js create mode 100644 test/js/node/test/parallel/test-vm-ownkeys.js create mode 100644 test/js/node/test/parallel/test-vm-ownpropertynames.js create mode 100644 test/js/node/test/parallel/test-vm-ownpropertysymbols.js create mode 100644 test/js/node/test/parallel/test-vm-preserves-property.js create mode 100644 test/js/node/test/parallel/test-vm-set-property-proxy.js create mode 100644 test/js/node/test/parallel/test-vm-symbols.js diff --git a/src/bun.js/bindings/BunClientData.cpp b/src/bun.js/bindings/BunClientData.cpp index f8734725e4..37f1e097f2 100644 --- a/src/bun.js/bindings/BunClientData.cpp +++ b/src/bun.js/bindings/BunClientData.cpp @@ -22,6 +22,7 @@ #include "JSDOMWrapper.h" #include +#include "NodeVM.h" namespace WebCore { using namespace JSC; @@ -30,6 +31,7 @@ RefPtr createBuiltinsSourceProvider(); JSHeapData::JSHeapData(Heap& heap) : m_heapCellTypeForJSWorkerGlobalScope(JSC::IsoHeapCellType::Args()) + , m_heapCellTypeForNodeVMGlobalObject(JSC::IsoHeapCellType::Args()) , m_domBuiltinConstructorSpace ISO_SUBSPACE_INIT(heap, heap.cellHeapCellType, JSDOMBuiltinConstructorBase) , m_domConstructorSpace ISO_SUBSPACE_INIT(heap, heap.cellHeapCellType, JSDOMConstructorBase) , m_domNamespaceObjectSpace ISO_SUBSPACE_INIT(heap, heap.cellHeapCellType, JSDOMObject) diff --git a/src/bun.js/bindings/BunClientData.h b/src/bun.js/bindings/BunClientData.h index c4b7f5745a..92fcad4ad4 100644 --- a/src/bun.js/bindings/BunClientData.h +++ b/src/bun.js/bindings/BunClientData.h @@ -58,6 +58,7 @@ public: } JSC::IsoHeapCellType m_heapCellTypeForJSWorkerGlobalScope; + JSC::IsoHeapCellType m_heapCellTypeForNodeVMGlobalObject; private: Lock m_lock; diff --git a/src/bun.js/bindings/ErrorCode.cpp b/src/bun.js/bindings/ErrorCode.cpp index 20f6c0639c..cd2ad0ee1f 100644 --- a/src/bun.js/bindings/ErrorCode.cpp +++ b/src/bun.js/bindings/ErrorCode.cpp @@ -686,7 +686,6 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject return JSValue::encode(ERR_INVALID_ARG_TYPE(scope, globalObject, arg0, arg1, arg2)); } - default: { break; } diff --git a/src/bun.js/bindings/ErrorCode.ts b/src/bun.js/bindings/ErrorCode.ts index b9ed12271f..d04c096ae6 100644 --- a/src/bun.js/bindings/ErrorCode.ts +++ b/src/bun.js/bindings/ErrorCode.ts @@ -49,6 +49,8 @@ export default [ ["ERR_STREAM_RELEASE_LOCK", Error, "AbortError"], ["ERR_INCOMPATIBLE_OPTION_PAIR", TypeError, "TypeError"], ["ERR_INVALID_URI", URIError, "URIError"], + ["ERR_SCRIPT_EXECUTION_TIMEOUT", Error, "Error"], + ["ERR_SCRIPT_EXECUTION_INTERRUPTED", Error, "Error"], // Bun-specific ["ERR_FORMDATA_PARSE_ERROR", TypeError], diff --git a/src/bun.js/bindings/NodeVM.cpp b/src/bun.js/bindings/NodeVM.cpp index 7f7dad886d..336f88e09c 100644 --- a/src/bun.js/bindings/NodeVM.cpp +++ b/src/bun.js/bindings/NodeVM.cpp @@ -1,5 +1,12 @@ + #include "root.h" + +#include "JavaScriptCore/PropertySlot.h" #include "JavaScriptCore/ExecutableInfo.h" +#include "JavaScriptCore/WriteBarrierInlines.h" +#include "ErrorCode.h" +#include +#include #include "BunClientData.h" #include "NodeVM.h" @@ -28,9 +35,251 @@ #include #include #include +#include "JavaScriptCore/LazyClassStructureInlines.h" -namespace WebCore { -using namespace JSC; +#include "JavaScriptCore/JSCInlines.h" + +namespace Bun { +using namespace WebCore; + +class NodeVMScriptConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + + static NodeVMScriptConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::JSObject* prototype); + + DECLARE_EXPORT_INFO; + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, Base::StructureFlags), info()); + } + +private: + NodeVMScriptConstructor(JSC::VM& vm, JSC::Structure* structure); + + void finishCreation(JSC::VM&, JSC::JSObject* prototype); +}; +STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(NodeVMScriptConstructor, JSC::InternalFunction); + +class NodeVMScript final : public JSC::JSDestructibleObject { +public: + using Base = JSC::JSDestructibleObject; + + static NodeVMScript* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::SourceCode source); + + DECLARE_EXPORT_INFO; + template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForNodeVMScript.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForNodeVMScript = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForNodeVMScript.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForNodeVMScript = std::forward(space); }); + } + + static void destroy(JSC::JSCell*); + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + + static JSObject* createPrototype(VM& vm, JSGlobalObject* globalObject); + + const JSC::SourceCode& source() const { return m_source; } + + DECLARE_VISIT_CHILDREN; + mutable JSC::WriteBarrier m_cachedDirectExecutable; + +private: + JSC::SourceCode m_source; + + NodeVMScript(JSC::VM& vm, JSC::Structure* structure, JSC::SourceCode source) + : Base(vm, structure) + , m_source(source) + { + } + + void finishCreation(JSC::VM&); +}; + +NodeVMGlobalObject::NodeVMGlobalObject(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) +{ +} + +template JSC::GCClient::IsoSubspace* NodeVMGlobalObject::subspaceFor(JSC::VM& vm) +{ + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForNodeVMGlobalObject.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForNodeVMGlobalObject = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForNodeVMGlobalObject.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForNodeVMGlobalObject = std::forward(space); }, + [](auto& server) -> JSC::HeapCellType& { return server.m_heapCellTypeForNodeVMGlobalObject; }); +} + +NodeVMGlobalObject* NodeVMGlobalObject::create(JSC::VM& vm, JSC::Structure* structure) +{ + auto* cell = new (NotNull, JSC::allocateCell(vm)) NodeVMGlobalObject(vm, structure); + cell->finishCreation(vm); + return cell; +} + +Structure* NodeVMGlobalObject::createStructure(JSC::VM& vm, JSC::JSValue prototype) +{ + return JSC::Structure::create(vm, nullptr, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info()); +} + +void NodeVMGlobalObject::finishCreation(JSC::VM&) +{ + Base::finishCreation(vm()); +} + +void NodeVMGlobalObject::destroy(JSCell* cell) +{ + static_cast(cell)->~NodeVMGlobalObject(); +} + +NodeVMGlobalObject::~NodeVMGlobalObject() +{ +} + +void NodeVMGlobalObject::setContextifiedObject(JSC::JSObject* contextifiedObject) +{ + m_sandbox.set(vm(), this, contextifiedObject); +} + +void NodeVMGlobalObject::clearContextifiedObject() +{ + m_sandbox.clear(); +} + +bool NodeVMGlobalObject::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +{ + // if (!propertyName.isSymbol()) + // printf("put called for %s\n", propertyName.publicName()->utf8().data()); + auto* thisObject = jsCast(cell); + + if (!thisObject->m_sandbox) { + return Base::put(cell, globalObject, propertyName, value, slot); + } + + auto* sandbox = thisObject->m_sandbox.get(); + + auto& vm = globalObject->vm(); + JSValue thisValue = slot.thisValue(); + bool isContextualStore = thisValue != JSValue(globalObject); + (void)isContextualStore; + bool isDeclaredOnGlobalObject = slot.type() == JSC::PutPropertySlot::NewProperty; + auto scope = DECLARE_THROW_SCOPE(vm); + PropertySlot getter(sandbox, PropertySlot::InternalMethodType::Get, nullptr); + bool isDeclaredOnSandbox = sandbox->getPropertySlot(globalObject, propertyName, getter); + RETURN_IF_EXCEPTION(scope, false); + + bool isDeclared = isDeclaredOnGlobalObject || isDeclaredOnSandbox; + bool isFunction = value.isCallable(); + + if (slot.isStrictMode() && !isDeclared && isContextualStore && !isFunction) { + return Base::put(cell, globalObject, propertyName, value, slot); + } + + if (!isDeclared && value.isSymbol()) { + return Base::put(cell, globalObject, propertyName, value, slot); + } + + slot.setThisValue(sandbox); + + if (!sandbox->methodTable()->put(sandbox, globalObject, propertyName, value, slot)) { + return false; + } + RETURN_IF_EXCEPTION(scope, false); + + slot.setThisValue(sandbox); + if (isDeclaredOnSandbox && getter.isAccessor() and (getter.attributes() & PropertyAttribute::DontEnum) == 0) { + return true; + } + + slot.setThisValue(thisValue); + + return Base::put(cell, globalObject, propertyName, value, slot); +} + +bool NodeVMGlobalObject::getOwnPropertySlot(JSObject* cell, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) +{ + // if (!propertyName.isSymbol()) + // printf("getOwnPropertySlot called for %s\n", propertyName.publicName()->utf8().data()); + auto* thisObject = jsCast(cell); + if (thisObject->m_sandbox) { + auto* contextifiedObject = thisObject->m_sandbox.get(); + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + slot.setThisValue(contextifiedObject); + if (contextifiedObject->getPropertySlot(globalObject, propertyName, slot)) { + return true; + } + + slot.setThisValue(globalObject); + RETURN_IF_EXCEPTION(scope, false); + } + + return Base::getOwnPropertySlot(cell, globalObject, propertyName, slot); +} + +bool NodeVMGlobalObject::defineOwnProperty(JSObject* cell, JSGlobalObject* globalObject, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) +{ + // if (!propertyName.isSymbol()) + // printf("defineOwnProperty called for %s\n", propertyName.publicName()->utf8().data()); + auto* thisObject = jsCast(cell); + if (!thisObject->m_sandbox) { + return Base::defineOwnProperty(cell, globalObject, propertyName, descriptor, shouldThrow); + } + + auto* contextifiedObject = thisObject->m_sandbox.get(); + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + PropertySlot slot(globalObject, PropertySlot::InternalMethodType::GetOwnProperty, nullptr); + bool isDeclaredOnGlobalProxy = globalObject->JSC::JSGlobalObject::getOwnPropertySlot(globalObject, globalObject, propertyName, slot); + + // If the property is set on the global as neither writable nor + // configurable, don't change it on the global or sandbox. + if (isDeclaredOnGlobalProxy && (slot.attributes() & PropertyAttribute::ReadOnly) != 0 && (slot.attributes() & PropertyAttribute::DontDelete) != 0) { + return Base::defineOwnProperty(cell, globalObject, propertyName, descriptor, shouldThrow); + } + + if (descriptor.isAccessorDescriptor()) { + return contextifiedObject->defineOwnProperty(contextifiedObject, contextifiedObject->globalObject(), propertyName, descriptor, shouldThrow); + } + + bool isDeclaredOnSandbox = contextifiedObject->getPropertySlot(globalObject, propertyName, slot); + RETURN_IF_EXCEPTION(scope, false); + + if (isDeclaredOnSandbox && !isDeclaredOnGlobalProxy) { + return contextifiedObject->defineOwnProperty(contextifiedObject, contextifiedObject->globalObject(), propertyName, descriptor, shouldThrow); + } + + if (!contextifiedObject->defineOwnProperty(contextifiedObject, contextifiedObject->globalObject(), propertyName, descriptor, shouldThrow)) { + return false; + } + + return Base::defineOwnProperty(cell, globalObject, propertyName, descriptor, shouldThrow); +} + +DEFINE_VISIT_CHILDREN(NodeVMGlobalObject); + +template +void NodeVMGlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + Base::visitChildren(cell, visitor); + auto* thisObject = jsCast(cell); + visitor.append(thisObject->m_sandbox); +} class ScriptOptions { public: @@ -108,7 +357,7 @@ constructScript(JSGlobalObject* globalObject, CallFrame* callFrame, JSValue newT if (didThrow) return JSValue::encode(jsUndefined()); - auto* zigGlobalObject = reinterpret_cast(globalObject); + auto* zigGlobalObject = defaultGlobalObject(globalObject); Structure* structure = zigGlobalObject->NodeVMScriptStructure(); if (UNLIKELY(zigGlobalObject->NodeVMScript() != newTarget)) { auto scope = DECLARE_THROW_SCOPE(vm); @@ -117,7 +366,7 @@ constructScript(JSGlobalObject* globalObject, CallFrame* callFrame, JSValue newT return {}; } - auto* functionGlobalObject = reinterpret_cast(getFunctionRealm(globalObject, newTarget.getObject())); + auto* functionGlobalObject = defaultGlobalObject(getFunctionRealm(globalObject, newTarget.getObject())); RETURN_IF_EXCEPTION(scope, {}); structure = InternalFunction::createSubclassStructure( globalObject, newTarget.getObject(), functionGlobalObject->NodeVMScriptStructure()); @@ -133,32 +382,18 @@ constructScript(JSGlobalObject* globalObject, CallFrame* callFrame, JSValue newT return JSValue::encode(JSValue(script)); } -static JSC::EncodedJSValue runInContext(JSGlobalObject* globalObject, NodeVMScript* script, JSObject* globalThis, JSScope* scope, JSValue optionsArg) +static JSC::EncodedJSValue runInContext(NodeVMGlobalObject* globalObject, NodeVMScript* script, JSObject* contextifiedObject, JSValue optionsArg) { auto& vm = globalObject->vm(); - auto throwScope = DECLARE_THROW_SCOPE(vm); - JSC::DirectEvalExecutable* executable = nullptr; - if (JSC::DirectEvalExecutable* existingEval = script->m_cachedDirectExecutable.get()) { - executable = existingEval; - } + // Set the contextified object before evaluating + globalObject->setContextifiedObject(contextifiedObject); - if (executable == nullptr) { - // Note: it accepts a JSGlobalObject, but it just reads stuff from JSC::VM. - executable = JSC::DirectEvalExecutable::create( - globalObject, script->source(), NoLexicallyScopedFeatures, DerivedContextType::None, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None, - false, false, EvalContextType::None, nullptr, nullptr); - RETURN_IF_EXCEPTION(throwScope, {}); - script->m_cachedDirectExecutable.set(vm, script, executable); - } - - auto catchScope = DECLARE_CATCH_SCOPE(vm); - JSValue result = vm.interpreter.executeEval(executable, globalObject, scope); - if (UNLIKELY(catchScope.exception())) { - auto returnedException = catchScope.exception(); - catchScope.clearException(); - JSC::throwException(globalObject, throwScope, returnedException); + NakedPtr exception; + JSValue result = JSC::evaluate(globalObject, script->source(), globalObject, exception); + if (UNLIKELY(exception)) { + JSC::throwException(globalObject, throwScope, exception.get()); return {}; } @@ -189,114 +424,137 @@ JSC_DEFINE_HOST_FUNCTION(scriptCreateCachedData, (JSGlobalObject * globalObject, JSC_DEFINE_HOST_FUNCTION(scriptRunInContext, (JSGlobalObject * globalObject, CallFrame* callFrame)) { auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); JSValue thisValue = callFrame->thisValue(); auto* script = jsDynamicCast(thisValue); - auto scope = DECLARE_THROW_SCOPE(vm); - if (UNLIKELY(!script)) { - throwVMTypeError(globalObject, scope, "Script.prototype.runInContext can only be called on a Script object"_s); - return {}; + return ERR::INVALID_ARG_VALUE(scope, globalObject, "this"_s, thisValue, "must be a Script"_s); } ArgList args(callFrame); - JSValue contextArg = args.at(0); - if (!UNLIKELY(contextArg.isObject())) { - throwVMTypeError(globalObject, scope, "context parameter must be a contextified object"_s); - return {}; + if (contextArg.isUndefined()) { + contextArg = JSC::constructEmptyObject(globalObject); } + + if (!contextArg.isObject()) { + return ERR::INVALID_ARG_TYPE(scope, globalObject, "context"_s, "object"_s, contextArg); + } + + JSObject* context = asObject(contextArg); + auto* zigGlobalObject = defaultGlobalObject(globalObject); + JSValue scopeValue = zigGlobalObject->vmModuleContextMap()->get(context); + if (scopeValue.isUndefined()) { + return ERR::INVALID_ARG_VALUE(scope, globalObject, "context"_s, context, "must be a contextified object"_s); + } + + NodeVMGlobalObject* nodeVmGlobalObject = jsDynamicCast(scopeValue); + if (!nodeVmGlobalObject) { + return ERR::INVALID_ARG_VALUE(scope, globalObject, "context"_s, context, "must be a contextified object"_s); + } + + return runInContext(nodeVmGlobalObject, script, context, args.at(1)); +} + +JSC_DEFINE_HOST_FUNCTION(scriptRunInThisContext, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + JSValue thisValue = callFrame->thisValue(); + auto* script = jsDynamicCast(thisValue); + auto throwScope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(!script)) { + return ERR::INVALID_ARG_VALUE(throwScope, globalObject, "this"_s, thisValue, "must be a Script"_s); + } + + JSValue contextArg = callFrame->argument(0); + if (contextArg.isUndefined()) { + contextArg = JSC::constructEmptyObject(globalObject); + } + + if (!contextArg.isObject()) { + return ERR::INVALID_ARG_TYPE(throwScope, globalObject, "context"_s, "object"_s, contextArg); + } + JSObject* context = asObject(contextArg); - auto* zigGlobalObject = reinterpret_cast(globalObject); - JSValue scopeVal = zigGlobalObject->vmModuleContextMap()->get(context); - if (UNLIKELY(scopeVal.isUndefined())) { - throwVMTypeError(globalObject, scope, "context parameter must be a contextified object"_s); - return {}; - } - JSScope* jsScope = jsDynamicCast(scopeVal); - if (UNLIKELY(!jsScope)) { - throwVMTypeError(globalObject, scope, "context parameter must be a contextified object"_s); - return {}; + NakedPtr exception; + JSValue result = JSC::evaluateWithScopeExtension(globalObject, script->source(), JSC::JSWithScope::create(vm, globalObject, globalObject->globalScope(), context), exception); + + if (exception) + JSC::throwException(globalObject, throwScope, exception.get()); + + RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(result); +} + +JSC_DEFINE_CUSTOM_GETTER(scriptGetSourceMapURL, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValueEncoded, PropertyName)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue thisValue = JSValue::decode(thisValueEncoded); + auto* script = jsDynamicCast(thisValue); + if (UNLIKELY(!script)) { + return ERR::INVALID_ARG_VALUE(scope, globalObject, "this"_s, thisValue, "must be a Script"_s); } - JSGlobalProxy* globalProxy = jsDynamicCast(context->getPrototypeDirect()); - if (!globalProxy) { - auto scope = DECLARE_THROW_SCOPE(vm); - throwVMTypeError(globalObject, scope, "context parameter must be a contextified object"_s); - return {}; - } - - return runInContext(globalProxy->target(), script, context, jsScope, args.at(1)); + const auto& url = script->source().provider()->sourceMappingURLDirective(); + return JSValue::encode(jsString(vm, url)); } JSC_DEFINE_HOST_FUNCTION(vmModuleRunInNewContext, (JSGlobalObject * globalObject, CallFrame* callFrame)) { - auto& vm = globalObject->vm(); - auto sourceStringValue = callFrame->argument(0); - JSValue contextObjectValue = callFrame->argument(1); - JSValue optionsObjectValue = callFrame->argument(2); - auto throwScope = DECLARE_THROW_SCOPE(vm); + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - if (!sourceStringValue.isString()) { - throwTypeError(globalObject, throwScope, "Script code must be a string"_s); - return {}; + JSValue code = callFrame->argument(0); + if (!code.isString()) + return ERR::INVALID_ARG_TYPE(scope, globalObject, "code"_s, "string"_s, code); + + JSValue contextArg = callFrame->argument(1); + if (contextArg.isUndefined()) { + contextArg = JSC::constructEmptyObject(globalObject); } - auto sourceString = sourceStringValue.toWTFString(globalObject); + if (!contextArg.isObject()) + return ERR::INVALID_ARG_TYPE(scope, globalObject, "context"_s, "object"_s, contextArg); - if (!contextObjectValue || contextObjectValue.isUndefinedOrNull()) { - contextObjectValue = JSC::constructEmptyObject(globalObject); - } + JSObject* sandbox = asObject(contextArg); - if (UNLIKELY(!contextObjectValue || !contextObjectValue.isObject())) { - throwTypeError(globalObject, throwScope, "Context must be an object"_s); - return {}; - } + // Create context and run code + auto* context = NodeVMGlobalObject::create(vm, + defaultGlobalObject(globalObject)->NodeVMGlobalObjectStructure()); - // we don't care about options for now + context->setContextifiedObject(sandbox); + JSValue optionsArg = callFrame->argument(2); ScriptOptions options; { bool didThrow = false; - - if (auto scriptOptions = ScriptOptions::fromJS(globalObject, optionsObjectValue, didThrow)) { + if (auto scriptOptions = ScriptOptions::fromJS(globalObject, optionsArg, didThrow)) { options = scriptOptions.value(); } if (UNLIKELY(didThrow)) { - return JSValue::encode({}); + return encodedJSValue(); } } - SourceCode source( - JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), options.filename, JSC::SourceTaintedOrigin::Untainted, TextPosition(options.lineOffset, options.columnOffset)), - options.lineOffset.zeroBasedInt(), options.columnOffset.zeroBasedInt()); - auto* zigGlobal = reinterpret_cast(globalObject); - JSObject* context = asObject(contextObjectValue); - auto* targetContext = NodeVMGlobalObject::create( - vm, zigGlobal->NodeVMGlobalObjectStructure()); + auto sourceCode = SourceCode( + JSC::StringSourceProvider::create( + code.toString(globalObject)->value(globalObject), + JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), + options.filename, + JSC::SourceTaintedOrigin::Untainted, + TextPosition(options.lineOffset, options.columnOffset)), + options.lineOffset.zeroBasedInt(), + options.columnOffset.zeroBasedInt()); - auto* executable = JSC::DirectEvalExecutable::create( - targetContext, source, NoLexicallyScopedFeatures, DerivedContextType::None, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None, - false, false, EvalContextType::None, nullptr, nullptr); - RETURN_IF_EXCEPTION(throwScope, {}); + NakedPtr exception; + JSValue result = JSC::evaluate(context, sourceCode, context, exception); - auto proxyStructure = JSGlobalProxy::createStructure(vm, globalObject, JSC::jsNull()); - auto proxy = JSGlobalProxy::create(vm, proxyStructure); - proxy->setTarget(vm, targetContext); - context->setPrototypeDirect(vm, proxy); - - JSScope* contextScope = JSWithScope::create(vm, targetContext, targetContext->globalScope(), context); - - auto catchScope = DECLARE_CATCH_SCOPE(vm); - JSValue result = vm.interpreter.executeEval(executable, targetContext, contextScope); - if (UNLIKELY(catchScope.exception())) { - auto returnedException = catchScope.exception(); - catchScope.clearException(); - JSC::throwException(globalObject, throwScope, returnedException); - } - - RETURN_IF_EXCEPTION(throwScope, {}); + if (exception) + throwException(globalObject, scope, exception); return JSValue::encode(result); } @@ -305,12 +563,10 @@ JSC_DEFINE_HOST_FUNCTION(vmModuleRunInThisContext, (JSGlobalObject * globalObjec { auto& vm = globalObject->vm(); auto sourceStringValue = callFrame->argument(0); - JSValue optionsObjectValue = callFrame->argument(1); auto throwScope = DECLARE_THROW_SCOPE(vm); if (!sourceStringValue.isString()) { - throwTypeError(globalObject, throwScope, "Script code must be a string"_s); - return {}; + return ERR::INVALID_ARG_TYPE(throwScope, globalObject, "code"_s, "string"_s, sourceStringValue); } auto sourceString = sourceStringValue.toWTFString(globalObject); @@ -319,7 +575,7 @@ JSC_DEFINE_HOST_FUNCTION(vmModuleRunInThisContext, (JSGlobalObject * globalObjec { bool didThrow = false; - if (auto scriptOptions = ScriptOptions::fromJS(globalObject, optionsObjectValue, didThrow)) { + if (auto scriptOptions = ScriptOptions::fromJS(globalObject, callFrame->argument(1), didThrow)) { options = scriptOptions.value(); } if (UNLIKELY(didThrow)) { @@ -330,22 +586,11 @@ JSC_DEFINE_HOST_FUNCTION(vmModuleRunInThisContext, (JSGlobalObject * globalObjec JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), options.filename, JSC::SourceTaintedOrigin::Untainted, TextPosition(options.lineOffset, options.columnOffset)), options.lineOffset.zeroBasedInt(), options.columnOffset.zeroBasedInt()); - auto* executable = JSC::DirectEvalExecutable::create( - globalObject, source, NoLexicallyScopedFeatures, DerivedContextType::None, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None, - false, false, EvalContextType::None, nullptr, nullptr); - RETURN_IF_EXCEPTION(throwScope, {}); + WTF::NakedPtr exception; + JSValue result = JSC::evaluate(globalObject, source, globalObject, exception); - JSObject* context = asObject(JSC::constructEmptyObject(globalObject)); - JSScope* contextScope = JSWithScope::create(vm, globalObject, globalObject->globalScope(), context); - auto catchScope = DECLARE_CATCH_SCOPE(vm); - JSValue result = vm.interpreter.executeEval(executable, globalObject, contextScope); - if (UNLIKELY(catchScope.exception())) { - auto returnedException = catchScope.exception(); - catchScope.clearException(); - JSC::throwException(globalObject, throwScope, returnedException); - } - - RETURN_IF_EXCEPTION(throwScope, {}); + if (exception) + throwException(globalObject, throwScope, exception); return JSValue::encode(result); } @@ -377,51 +622,12 @@ JSC_DEFINE_HOST_FUNCTION(scriptRunInNewContext, (JSGlobalObject * globalObject, // TODO: options // bool didThrow = false; - auto* zigGlobal = reinterpret_cast(globalObject); + auto* zigGlobal = defaultGlobalObject(globalObject); JSObject* context = asObject(contextObjectValue); auto* targetContext = NodeVMGlobalObject::create( vm, zigGlobal->NodeVMGlobalObjectStructure()); - auto proxyStructure = JSGlobalProxy::createStructure(vm, globalObject, JSC::jsNull()); - auto proxy = JSGlobalProxy::create(vm, proxyStructure); - proxy->setTarget(vm, targetContext); - context->setPrototypeDirect(vm, proxy); - - JSScope* contextScope = JSWithScope::create(vm, targetContext, targetContext->globalScope(), context); - return runInContext(globalObject, script, targetContext, contextScope, callFrame->argument(0)); -} -JSC_DEFINE_HOST_FUNCTION(scriptRunInThisContext, (JSGlobalObject * globalObject, CallFrame* callFrame)) -{ - auto& vm = globalObject->vm(); - JSValue thisValue = callFrame->thisValue(); - auto* script = jsDynamicCast(thisValue); - auto throwScope = DECLARE_THROW_SCOPE(vm); - // TODO: options - // JSValue optionsObjectValue = callFrame->argument(0); - - if (UNLIKELY(!script)) { - return throwVMTypeError(globalObject, throwScope, "Script.prototype.runInThisContext can only be called on a Script object"_s); - } - - JSObject* context = asObject(JSC::constructEmptyObject(globalObject)); - JSWithScope* contextScope = JSWithScope::create(vm, globalObject, globalObject->globalScope(), context); - - return runInContext(globalObject, script, globalObject->globalThis(), contextScope, callFrame->argument(1)); -} - -JSC_DEFINE_CUSTOM_GETTER(scriptGetSourceMapURL, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValueEncoded, PropertyName)) -{ - auto& vm = globalObject->vm(); - JSValue thisValue = JSValue::decode(thisValueEncoded); - auto* script = jsDynamicCast(thisValue); - if (UNLIKELY(!script)) { - auto scope = DECLARE_THROW_SCOPE(vm); - return throwVMTypeError(globalObject, scope, "Script.prototype.sourceMapURL getter can only be called on a Script object"_s); - } - - // FIXME: doesn't seem to work? Just returns undefined - const auto& url = script->source().provider()->sourceMappingURLDirective(); - return JSValue::encode(jsString(vm, url)); + return runInContext(targetContext, script, context, callFrame->argument(0)); } Structure* createNodeVMGlobalObjectStructure(JSC::VM& vm) @@ -431,33 +637,32 @@ Structure* createNodeVMGlobalObjectStructure(JSC::VM& vm) JSC_DEFINE_HOST_FUNCTION(vmModule_createContext, (JSGlobalObject * globalObject, CallFrame* callFrame)) { - auto& vm = globalObject->vm(); + VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue contextArg = callFrame->argument(0); - - if (contextArg.isEmpty() || contextArg.isUndefinedOrNull()) { + if (contextArg.isUndefinedOrNull()) { contextArg = JSC::constructEmptyObject(globalObject); } if (!contextArg.isObject()) { - return throwVMTypeError(globalObject, scope, "parameter to createContext must be an object"_s); + return ERR::INVALID_ARG_TYPE(scope, globalObject, "context"_s, "object"_s, contextArg); } - JSObject* context = asObject(contextArg); - auto* zigGlobalObject = reinterpret_cast(globalObject); - auto* targetContext = NodeVMGlobalObject::create( - vm, zigGlobalObject->NodeVMGlobalObjectStructure()); - auto proxyStructure = zigGlobalObject->globalProxyStructure(); - auto proxy = JSGlobalProxy::create(vm, proxyStructure); - proxy->setTarget(vm, targetContext); - context->setPrototypeDirect(vm, proxy); + JSObject* sandbox = asObject(contextArg); - JSScope* contextScope = JSWithScope::create(vm, targetContext, targetContext->globalScope(), context); + // Create new VM context global object + auto* targetContext = NodeVMGlobalObject::create(vm, + defaultGlobalObject(globalObject)->NodeVMGlobalObjectStructure()); - zigGlobalObject->vmModuleContextMap()->set(vm, context, contextScope); + // Set sandbox as contextified object + targetContext->setContextifiedObject(sandbox); - return JSValue::encode(context); + // Store context in WeakMap for isContext checks + auto* zigGlobalObject = defaultGlobalObject(globalObject); + zigGlobalObject->vmModuleContextMap()->set(vm, sandbox, targetContext); + + return JSValue::encode(sandbox); } JSC_DEFINE_HOST_FUNCTION(vmModule_isContext, (JSGlobalObject * globalObject, CallFrame* callFrame)) @@ -468,7 +673,7 @@ JSC_DEFINE_HOST_FUNCTION(vmModule_isContext, (JSGlobalObject * globalObject, Cal if (!contextArg || !contextArg.isObject()) { isContext = false; } else { - auto* zigGlobalObject = reinterpret_cast(globalObject); + auto* zigGlobalObject = defaultGlobalObject(globalObject); isContext = zigGlobalObject->vmModuleContextMap()->has(asObject(contextArg)); } return JSValue::encode(jsBoolean(isContext)); @@ -516,6 +721,29 @@ static const struct HashTableValue scriptPrototypeTableValues[] = { { "sourceMapURL"_s, static_cast(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, scriptGetSourceMapURL, nullptr } }, }; +// NodeVMGlobalObject* NodeVMGlobalObject::create(JSC::VM& vm, JSC::Structure* structure) +// { +// auto* obj = new (NotNull, allocateCell(vm)) NodeVMGlobalObject(vm, structure); +// obj->finishCreation(vm); +// return obj; +// } + +// void NodeVMGlobalObject::finishCreation(VM& vm, JSObject* context) +// { +// Base::finishCreation(vm); +// // We don't need to store the context anymore since we use proxies +// } + +// DEFINE_VISIT_CHILDREN(NodeVMGlobalObject); + +// template +// void NodeVMGlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) +// { +// Base::visitChildren(cell, visitor); +// // auto* thisObject = jsCast(cell); +// // visitor.append(thisObject->m_proxyTarget); +// } + const ClassInfo NodeVMScriptPrototype::s_info = { "Script"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NodeVMScriptPrototype) }; const ClassInfo NodeVMScript::s_info = { "Script"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NodeVMScript) }; const ClassInfo NodeVMScriptConstructor::s_info = { "Script"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(NodeVMScriptConstructor) }; @@ -581,17 +809,13 @@ void NodeVMScript::destroy(JSCell* cell) static_cast(cell)->NodeVMScript::~NodeVMScript(); } -} // namespace WebCore - -namespace Bun { - JSC::JSValue createNodeVMBinding(Zig::GlobalObject* globalObject) { VM& vm = globalObject->vm(); auto* obj = constructEmptyObject(globalObject); obj->putDirect( vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "Script"_s)), - reinterpret_cast(globalObject)->NodeVMScript(), 0); + defaultGlobalObject(globalObject)->NodeVMScript(), 0); obj->putDirect( vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "createContext"_s)), JSC::JSFunction::create(vm, globalObject, 0, "createContext"_s, vmModule_createContext, ImplementationVisibility::Public), 0); @@ -607,4 +831,60 @@ JSC::JSValue createNodeVMBinding(Zig::GlobalObject* globalObject) return obj; } +void configureNodeVM(JSC::VM& vm, Zig::GlobalObject* globalObject) +{ + globalObject->m_NodeVMScriptClassStructure.initLater( + [](LazyClassStructure::Initializer& init) { + auto prototype = NodeVMScript::createPrototype(init.vm, init.global); + auto* structure = NodeVMScript::createStructure(init.vm, init.global, prototype); + auto* constructorStructure = NodeVMScriptConstructor::createStructure( + init.vm, init.global, init.global->m_functionPrototype.get()); + auto* constructor = NodeVMScriptConstructor::create( + init.vm, init.global, constructorStructure, prototype); + init.setPrototype(prototype); + init.setStructure(structure); + init.setConstructor(constructor); + }); + + globalObject->m_cachedNodeVMGlobalObjectStructure.initLater( + [](const JSC::LazyProperty::Initializer& init) { + init.set(createNodeVMGlobalObjectStructure(init.vm)); + }); +} + +bool NodeVMGlobalObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSC::DeletePropertySlot& slot) +{ + + auto* thisObject = jsCast(cell); + if (UNLIKELY(!thisObject->m_sandbox)) { + return Base::deleteProperty(cell, globalObject, propertyName, slot); + } + + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* sandbox = thisObject->m_sandbox.get(); + if (!sandbox->deleteProperty(sandbox, globalObject, propertyName, slot)) { + return false; + } + + RETURN_IF_EXCEPTION(scope, false); + return Base::deleteProperty(cell, globalObject, propertyName, slot); +} + +void NodeVMGlobalObject::getOwnPropertyNames(JSObject* cell, JSGlobalObject* globalObject, JSC::PropertyNameArray& propertyNames, JSC::DontEnumPropertiesMode mode) +{ + auto* thisObject = jsCast(cell); + + if (thisObject->m_sandbox) { + thisObject->m_sandbox->getOwnPropertyNames( + thisObject->m_sandbox.get(), + globalObject, + propertyNames, + mode); + } + + Base::getOwnPropertyNames(cell, globalObject, propertyNames, mode); +} + } // namespace Bun diff --git a/src/bun.js/bindings/NodeVM.h b/src/bun.js/bindings/NodeVM.h index 4cee946713..721507d11f 100644 --- a/src/bun.js/bindings/NodeVM.h +++ b/src/bun.js/bindings/NodeVM.h @@ -2,6 +2,7 @@ #include "root.h" #include "ZigGlobalObject.h" +#include "BunGlobalScope.h" #include #include @@ -10,95 +11,52 @@ #include "BunClientData.h" #include -namespace WebCore { - -Structure* createNodeVMGlobalObjectStructure(JSC::VM&); - -class NodeVMScriptConstructor final : public JSC::InternalFunction { -public: - using Base = JSC::InternalFunction; - - static NodeVMScriptConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::JSObject* prototype); - - DECLARE_EXPORT_INFO; - - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, Base::StructureFlags), info()); - } - -private: - NodeVMScriptConstructor(JSC::VM& vm, JSC::Structure* structure); - - void finishCreation(JSC::VM&, JSC::JSObject* prototype); -}; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(NodeVMScriptConstructor, InternalFunction); - -class NodeVMScript final : public JSC::JSDestructibleObject { -public: - using Base = JSC::JSDestructibleObject; - - static NodeVMScript* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::SourceCode source); - - DECLARE_EXPORT_INFO; - template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForNodeVMScript.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForNodeVMScript = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForNodeVMScript.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForNodeVMScript = std::forward(space); }); - } - - static void destroy(JSC::JSCell*); - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); - } - - static JSObject* createPrototype(VM& vm, JSGlobalObject* globalObject); - - const JSC::SourceCode& source() const { return m_source; } - - DECLARE_VISIT_CHILDREN; - mutable JSC::WriteBarrier m_cachedDirectExecutable; - -private: - JSC::SourceCode m_source; - - NodeVMScript(JSC::VM& vm, JSC::Structure* structure, JSC::SourceCode source) - : Base(vm, structure) - , m_source(source) - { - } - - void finishCreation(JSC::VM&); -}; +namespace Bun { +// This class represents a sandboxed global object for vm contexts class NodeVMGlobalObject final : public Bun::GlobalScope { using Base = Bun::GlobalScope; public: - NodeVMGlobalObject(JSC::VM& vm, JSC::Structure* structure) - : Base(vm, structure) - { - } + static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::OverridesGetOwnPropertyNames | JSC::GetOwnPropertySlotMayBeWrongAboutDontEnum | JSC::ProhibitsPropertyCaching; + static constexpr bool needsDestruction = true; + + template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm); + static NodeVMGlobalObject* create(JSC::VM& vm, JSC::Structure* structure); + static Structure* createStructure(JSC::VM& vm, JSC::JSValue prototype); DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + void finishCreation(JSC::VM&); + static void destroy(JSCell* cell); + void setContextifiedObject(JSC::JSObject* contextifiedObject); + void clearContextifiedObject(); + + // Override property access to delegate to contextified object + static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&); + static bool put(JSCell*, JSGlobalObject*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&); + static void getOwnPropertyNames(JSObject*, JSGlobalObject*, JSC::PropertyNameArray&, JSC::DontEnumPropertiesMode); + static bool defineOwnProperty(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow); + static bool deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSC::DeletePropertySlot& slot); + +private: + NodeVMGlobalObject(JSC::VM& vm, JSC::Structure* structure); + ~NodeVMGlobalObject(); + + // The contextified object that acts as the global proxy + mutable JSC::WriteBarrier m_sandbox; }; +// Helper functions to create vm contexts and run code +JSC::JSValue createNodeVMBinding(Zig::GlobalObject*); +Structure* createNodeVMGlobalObjectStructure(JSC::VM&); +void configureNodeVM(JSC::VM&, Zig::GlobalObject*); + +// VM module functions JSC_DECLARE_HOST_FUNCTION(vmModule_createContext); JSC_DECLARE_HOST_FUNCTION(vmModule_isContext); JSC_DECLARE_HOST_FUNCTION(vmModuleRunInNewContext); JSC_DECLARE_HOST_FUNCTION(vmModuleRunInThisContext); -} // namespace WebCore - -namespace Bun { - -JSC::JSValue createNodeVMBinding(Zig::GlobalObject*); - -} +} // namespace Bun diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 7ac2bcf7cb..42060e503b 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -3078,11 +3078,6 @@ void GlobalObject::finishCreation(VM& vm) init.set(JSC::JSWeakMap::create(init.vm, init.owner->weakMapStructure())); }); - m_cachedNodeVMGlobalObjectStructure.initLater( - [](const JSC::LazyProperty::Initializer& init) { - init.set(WebCore::createNodeVMGlobalObjectStructure(init.vm)); - }); - m_cachedGlobalProxyStructure.initLater( [](const JSC::LazyProperty::Initializer& init) { init.set( @@ -3348,18 +3343,7 @@ void GlobalObject::finishCreation(VM& vm) init.setStructure(Zig::JSFFIFunction::createStructure(init.vm, init.global, init.global->functionPrototype())); }); - m_NodeVMScriptClassStructure.initLater( - [](LazyClassStructure::Initializer& init) { - auto prototype = NodeVMScript::createPrototype(init.vm, init.global); - auto* structure = NodeVMScript::createStructure(init.vm, init.global, prototype); - auto* constructorStructure = NodeVMScriptConstructor::createStructure( - init.vm, init.global, init.global->m_functionPrototype.get()); - auto* constructor = NodeVMScriptConstructor::create( - init.vm, init.global, constructorStructure, prototype); - init.setPrototype(prototype); - init.setStructure(structure); - init.setConstructor(constructor); - }); + configureNodeVM(vm, this); #if ENABLE(REMOTE_INSPECTOR) setInspectable(false); diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h index b1b5d8f6c6..dc805895d2 100644 --- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h @@ -57,6 +57,7 @@ public: std::unique_ptr m_clientSubspaceForHandleScopeBuffer; std::unique_ptr m_clientSubspaceForFunctionTemplate; std::unique_ptr m_clientSubspaceForV8Function; + std::unique_ptr m_clientSubspaceForNodeVMGlobalObject; #include "ZigGeneratedClasses+DOMClientIsoSubspaces.h" /* --- bun --- */ diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h index 6d8792cb6d..2d4eb091c5 100644 --- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h @@ -57,6 +57,7 @@ public: std::unique_ptr m_subspaceForHandleScopeBuffer; std::unique_ptr m_subspaceForFunctionTemplate; std::unique_ptr m_subspaceForV8Function; + std::unique_ptr m_subspaceForNodeVMGlobalObject; #include "ZigGeneratedClasses+DOMIsoSubspaces.h" /*-- BUN --*/ diff --git a/test/js/node/test/parallel/test-vm-create-and-run-in-context.js b/test/js/node/test/parallel/test-vm-create-and-run-in-context.js new file mode 100644 index 0000000000..bd746cf2df --- /dev/null +++ b/test/js/node/test/parallel/test-vm-create-and-run-in-context.js @@ -0,0 +1,50 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +// Flags: --expose-gc +require('../common'); +const assert = require('assert'); + +const vm = require('vm'); + +// Run in a new empty context +let context = vm.createContext(); +let result = vm.runInContext('"passed";', context); +assert.strictEqual(result, 'passed'); + +// Create a new pre-populated context +context = vm.createContext({ 'foo': 'bar', 'thing': 'lala' }); +assert.strictEqual(context.foo, 'bar'); +assert.strictEqual(context.thing, 'lala'); + +// Test updating context +result = vm.runInContext('var foo = 3;', context); +assert.strictEqual(context.foo, 3); +assert.strictEqual(context.thing, 'lala'); + +// https://github.com/nodejs/node/issues/5768 +// Run in contextified sandbox without referencing the context +const sandbox = { x: 1 }; +vm.createContext(sandbox); +global.gc(); +vm.runInContext('x = 2', sandbox); +// Should not crash. diff --git a/test/js/node/test/parallel/test-vm-create-context-arg.js b/test/js/node/test/parallel/test-vm-create-context-arg.js new file mode 100644 index 0000000000..c07079cb6c --- /dev/null +++ b/test/js/node/test/parallel/test-vm-create-context-arg.js @@ -0,0 +1,40 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +assert.throws(() => { + vm.createContext('string is not supported'); +}, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError' +}); + +// Should not throw. +vm.createContext({ a: 1 }); +vm.createContext([0, 1, 2, 3]); + +const sandbox = {}; +vm.createContext(sandbox); +vm.createContext(sandbox); diff --git a/test/js/node/test/parallel/test-vm-getters.js b/test/js/node/test/parallel/test-vm-getters.js new file mode 100644 index 0000000000..af27eeee64 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-getters.js @@ -0,0 +1,24 @@ +'use strict'; +// Refs: https://github.com/nodejs/node/issues/2734 +require('../common'); +const assert = require('assert'); +const vm = require('vm'); +const sandbox = {}; + +Object.defineProperty(sandbox, 'prop', { + get() { + return 'foo'; + } +}); + +const descriptor = Object.getOwnPropertyDescriptor(sandbox, 'prop'); +const context = vm.createContext(sandbox); +const code = 'Object.getOwnPropertyDescriptor(this, "prop");'; +const result = vm.runInContext(code, context); + +// Ref: https://github.com/nodejs/node/issues/11803 + +assert.deepStrictEqual(Object.keys(result), Object.keys(descriptor)); +for (const prop of Object.keys(result)) { + assert.strictEqual(result[prop], descriptor[prop]); +} diff --git a/test/js/node/test/parallel/test-vm-global-define-property.js b/test/js/node/test/parallel/test-vm-global-define-property.js new file mode 100644 index 0000000000..0b9a4dfb88 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-global-define-property.js @@ -0,0 +1,47 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('../common'); +const assert = require('assert'); + +const vm = require('vm'); + +const code = + 'Object.defineProperty(this, "f", {\n' + + ' get: function() { return x; },\n' + + ' set: function(k) { x = k; },\n' + + ' configurable: true,\n' + + ' enumerable: true\n' + + '});\n' + + 'g = f;\n' + + 'f;\n'; + +const x = {}; +const o = vm.createContext({ console, x }); + +const res = vm.runInContext(code, o, 'test'); + +assert(res); +assert.strictEqual(typeof res, 'object'); +assert.strictEqual(res, x); +assert.strictEqual(o.f, res); +assert.deepStrictEqual(Object.keys(o), ['console', 'x', 'f', 'g']); diff --git a/test/js/node/test/parallel/test-vm-global-non-writable-properties.js b/test/js/node/test/parallel/test-vm-global-non-writable-properties.js new file mode 100644 index 0000000000..771c9794bd --- /dev/null +++ b/test/js/node/test/parallel/test-vm-global-non-writable-properties.js @@ -0,0 +1,15 @@ +'use strict'; +// https://github.com/nodejs/node/issues/10223 + +require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +const ctx = vm.createContext(); +vm.runInContext('Object.defineProperty(this, "x", { value: 42 })', ctx); +assert.strictEqual(vm.runInContext('x', ctx), 42); +vm.runInContext('x = 0', ctx); // Does not throw but x... +assert.strictEqual(vm.runInContext('x', ctx), 42); // ...should be unaltered. +assert.throws(() => vm.runInContext('"use strict"; x = 0', ctx), + /Attempted to assign to readonly property./); +assert.strictEqual(vm.runInContext('x', ctx), 42); diff --git a/test/js/node/test/parallel/test-vm-global-property-interceptors.js b/test/js/node/test/parallel/test-vm-global-property-interceptors.js new file mode 100644 index 0000000000..c80ed04e3e --- /dev/null +++ b/test/js/node/test/parallel/test-vm-global-property-interceptors.js @@ -0,0 +1,129 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +const dSymbol = Symbol('d'); +const sandbox = { + a: 'a', + dSymbol +}; + +Object.defineProperties(sandbox, { + b: { + value: 'b' + }, + c: { + value: 'c', + writable: true, + enumerable: true + }, + [dSymbol]: { + value: 'd' + }, + e: { + value: 'e', + configurable: true + }, + f: {} +}); + +const ctx = vm.createContext(sandbox); + +const result = vm.runInContext(` +const getDesc = (prop) => Object.getOwnPropertyDescriptor(this, prop); +const result = { + a: getDesc('a'), + b: getDesc('b'), + c: getDesc('c'), + d: getDesc(dSymbol), + e: getDesc('e'), + f: getDesc('f'), + g: getDesc('g') +}; +result; +`, ctx); + +// eslint-disable-next-line no-restricted-properties +assert.deepEqual(result, { + a: { value: 'a', writable: true, enumerable: true, configurable: true }, + b: { value: 'b', writable: false, enumerable: false, configurable: false }, + c: { value: 'c', writable: true, enumerable: true, configurable: false }, + d: { value: 'd', writable: false, enumerable: false, configurable: false }, + e: { value: 'e', writable: false, enumerable: false, configurable: true }, + f: { + value: undefined, + writable: false, + enumerable: false, + configurable: false + }, + g: undefined +}); + +// Define new properties +vm.runInContext(` +Object.defineProperty(this, 'h', {value: 'h'}); +Object.defineProperty(this, 'i', {}); +Object.defineProperty(this, 'j', { + get() { return 'j'; } +}); +let kValue = 0; +Object.defineProperty(this, 'k', { + get() { return kValue; }, + set(value) { kValue = value } +}); +`, ctx); + +assert.deepStrictEqual(Object.getOwnPropertyDescriptor(ctx, 'h'), { + value: 'h', + writable: false, + enumerable: false, + configurable: false +}); + +assert.deepStrictEqual(Object.getOwnPropertyDescriptor(ctx, 'i'), { + value: undefined, + writable: false, + enumerable: false, + configurable: false +}); + +const jDesc = Object.getOwnPropertyDescriptor(ctx, 'j'); +assert.strictEqual(typeof jDesc.get, 'function'); +assert.strictEqual(typeof jDesc.set, 'undefined'); +assert.strictEqual(jDesc.enumerable, false); +assert.strictEqual(jDesc.configurable, false); + +const kDesc = Object.getOwnPropertyDescriptor(ctx, 'k'); +assert.strictEqual(typeof kDesc.get, 'function'); +assert.strictEqual(typeof kDesc.set, 'function'); +assert.strictEqual(kDesc.enumerable, false); +assert.strictEqual(kDesc.configurable, false); + +assert.strictEqual(ctx.k, 0); +ctx.k = 1; +assert.strictEqual(ctx.k, 1); +assert.strictEqual(vm.runInContext('k;', ctx), 1); +vm.runInContext('k = 2;', ctx); +assert.strictEqual(ctx.k, 2); +assert.strictEqual(vm.runInContext('k;', ctx), 2); + +// Redefine properties on the global object +assert.strictEqual(typeof vm.runInContext('encodeURI;', ctx), 'function'); +assert.strictEqual(ctx.encodeURI, undefined); +vm.runInContext(` +Object.defineProperty(this, 'encodeURI', { value: 42 }); +`, ctx); +assert.strictEqual(vm.runInContext('encodeURI;', ctx), 42); +assert.strictEqual(ctx.encodeURI, 42); + +// Redefine properties on the sandbox +vm.runInContext(` +Object.defineProperty(this, 'e', { value: 'newE' }); +`, ctx); +assert.strictEqual(ctx.e, 'newE'); + +assert.throws(() => vm.runInContext(` +'use strict'; +Object.defineProperty(this, 'f', { value: 'newF' }); +`, ctx), /TypeError: .*readonly property.,*/); diff --git a/test/js/node/test/parallel/test-vm-global-setter.js b/test/js/node/test/parallel/test-vm-global-setter.js new file mode 100644 index 0000000000..a8e390bc2a --- /dev/null +++ b/test/js/node/test/parallel/test-vm-global-setter.js @@ -0,0 +1,161 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +const getSetSymbolReceivingFunction = Symbol('sym-1'); +const getSetSymbolReceivingNumber = Symbol('sym-2'); +const symbolReceivingNumber = Symbol('sym-3'); +const unknownSymbolReceivingNumber = Symbol('sym-4'); + +const window = createWindow(); + +const descriptor1 = Object.getOwnPropertyDescriptor( + window.globalProxy, + 'getSetPropReceivingFunction' +); +assert.strictEqual(typeof descriptor1.get, 'function'); +assert.strictEqual(typeof descriptor1.set, 'function'); +assert.strictEqual(descriptor1.configurable, true); + +const descriptor2 = Object.getOwnPropertyDescriptor( + window.globalProxy, + 'getSetPropReceivingNumber' +); +assert.strictEqual(typeof descriptor2.get, 'function'); +assert.strictEqual(typeof descriptor2.set, 'function'); +assert.strictEqual(descriptor2.configurable, true); + +const descriptor3 = Object.getOwnPropertyDescriptor( + window.globalProxy, + 'propReceivingNumber' +); +assert.strictEqual(descriptor3.value, 44); + +const descriptor4 = Object.getOwnPropertyDescriptor( + window.globalProxy, + 'unknownPropReceivingNumber' +); +assert.strictEqual(descriptor4, undefined); + +const descriptor5 = Object.getOwnPropertyDescriptor( + window.globalProxy, + getSetSymbolReceivingFunction +); +assert.strictEqual(typeof descriptor5.get, 'function'); +assert.strictEqual(typeof descriptor5.set, 'function'); +assert.strictEqual(descriptor5.configurable, true); + +const descriptor6 = Object.getOwnPropertyDescriptor( + window.globalProxy, + getSetSymbolReceivingNumber +); +assert.strictEqual(typeof descriptor6.get, 'function'); +assert.strictEqual(typeof descriptor6.set, 'function'); +assert.strictEqual(descriptor6.configurable, true); + +const descriptor7 = Object.getOwnPropertyDescriptor( + window.globalProxy, + symbolReceivingNumber +); +assert.strictEqual(descriptor7.value, 48); + +const descriptor8 = Object.getOwnPropertyDescriptor( + window.globalProxy, + unknownSymbolReceivingNumber +); +assert.strictEqual(descriptor8, undefined); + +const descriptor9 = Object.getOwnPropertyDescriptor( + window.globalProxy, + 'getSetPropThrowing' +); +assert.strictEqual(typeof descriptor9.get, 'function'); +assert.strictEqual(typeof descriptor9.set, 'function'); +assert.strictEqual(descriptor9.configurable, true); + +const descriptor10 = Object.getOwnPropertyDescriptor( + window.globalProxy, + 'nonWritableProp' +); +assert.strictEqual(descriptor10.value, 51); +assert.strictEqual(descriptor10.writable, false); + +// Regression test for GH-42962. This assignment should not throw. +window.globalProxy.getSetPropReceivingFunction = () => {}; +assert.strictEqual(window.globalProxy.getSetPropReceivingFunction, 42); + +window.globalProxy.getSetPropReceivingNumber = 143; +assert.strictEqual(window.globalProxy.getSetPropReceivingNumber, 43); + +window.globalProxy.propReceivingNumber = 144; +assert.strictEqual(window.globalProxy.propReceivingNumber, 144); + +window.globalProxy.unknownPropReceivingNumber = 145; +assert.strictEqual(window.globalProxy.unknownPropReceivingNumber, 145); + +window.globalProxy[getSetSymbolReceivingFunction] = () => {}; +assert.strictEqual(window.globalProxy[getSetSymbolReceivingFunction], 46); + +window.globalProxy[getSetSymbolReceivingNumber] = 147; +assert.strictEqual(window.globalProxy[getSetSymbolReceivingNumber], 47); + +window.globalProxy[symbolReceivingNumber] = 148; +assert.strictEqual(window.globalProxy[symbolReceivingNumber], 148); + +window.globalProxy[unknownSymbolReceivingNumber] = 149; +assert.strictEqual(window.globalProxy[unknownSymbolReceivingNumber], 149); + +assert.throws( + () => (window.globalProxy.getSetPropThrowing = 150), + new Error('setter called') +); +assert.strictEqual(window.globalProxy.getSetPropThrowing, 50); + +assert.throws( + () => (window.globalProxy.nonWritableProp = 151), + new TypeError('Attempted to assign to readonly property.') +); +assert.strictEqual(window.globalProxy.nonWritableProp, 51); + +function createWindow() { + const obj = {}; + vm.createContext(obj); + Object.defineProperty(obj, 'getSetPropReceivingFunction', { + get: common.mustCall(() => 42), + set: common.mustCall(), + configurable: true, + }); + Object.defineProperty(obj, 'getSetPropReceivingNumber', { + get: common.mustCall(() => 43), + set: common.mustCall(), + configurable: true, + }); + obj.propReceivingNumber = 44; + Object.defineProperty(obj, getSetSymbolReceivingFunction, { + get: common.mustCall(() => 46), + set: common.mustCall(), + configurable: true, + }); + Object.defineProperty(obj, getSetSymbolReceivingNumber, { + get: common.mustCall(() => 47), + set: common.mustCall(), + configurable: true, + }); + obj[symbolReceivingNumber] = 48; + Object.defineProperty(obj, 'getSetPropThrowing', { + get: common.mustCall(() => 50), + set: common.mustCall(() => { + throw new Error('setter called'); + }), + configurable: true, + }); + Object.defineProperty(obj, 'nonWritableProp', { + value: 51, + writable: false, + }); + + obj.globalProxy = vm.runInContext('this', obj); + + return obj; +} diff --git a/test/js/node/test/parallel/test-vm-inherited_properties.js b/test/js/node/test/parallel/test-vm-inherited_properties.js new file mode 100644 index 0000000000..92cd64a6df --- /dev/null +++ b/test/js/node/test/parallel/test-vm-inherited_properties.js @@ -0,0 +1,39 @@ +'use strict'; + +require('../common'); + +const vm = require('vm'); +const assert = require('assert'); + +let base = { + propBase: 1 +}; + +let sandbox = Object.create(base, { + propSandbox: { value: 3 } +}); + +const context = vm.createContext(sandbox); + +let result = vm.runInContext('Object.hasOwnProperty(this, "propBase");', + context); + +assert.strictEqual(result, false); + + +// Ref: https://github.com/nodejs/node/issues/5350 +base = { __proto__: null }; +base.x = 1; +base.y = 2; + +sandbox = { __proto__: base }; +sandbox.z = 3; + +assert.deepStrictEqual(Object.keys(sandbox), ['z']); + +const code = 'x = 0; z = 4;'; +result = vm.runInNewContext(code, sandbox); +assert.strictEqual(result, 4); + +// Check that y is not an own property. +assert.deepStrictEqual(Object.keys(sandbox), ['z', 'x']); diff --git a/test/js/node/test/parallel/test-vm-not-strict.js b/test/js/node/test/parallel/test-vm-not-strict.js new file mode 100644 index 0000000000..8a72158a8a --- /dev/null +++ b/test/js/node/test/parallel/test-vm-not-strict.js @@ -0,0 +1,37 @@ +/* eslint-disable strict, no-var, no-delete-var, no-undef, node-core/required-modules, node-core/require-common-first */ +// Importing common would break the execution. Indeed running `vm.runInThisContext` alters the global context +// when declaring new variables with `var`. The other rules (strict, no-var, no-delete-var) have been disabled +// in order to be able to test this specific not-strict case playing with `var` and `delete`. +// Related to bug report: https://github.com/nodejs/node/issues/43129 +var assert = require('assert'); +var vm = require('vm'); + +var data = []; +var a = 'direct'; +delete a; +data.push(a); + +var item2 = vm.runInThisContext(` +var unusedB = 1; +var data = []; +var b = "this"; +delete b; +data.push(b); +data[0] +`); +data.push(item2); + +vm.runInContext( + ` +var unusedC = 1; +var c = "new"; +delete c; +data.push(c); +`, + vm.createContext({ data: data }) +); + +assert.deepStrictEqual(data, ['direct', 'this', 'new']); + +assert.strictEqual(typeof unusedB, 'number'); // Declared within runInThisContext +assert.strictEqual(typeof unusedC, 'undefined'); // Declared within runInContext diff --git a/test/js/node/test/parallel/test-vm-ownkeys.js b/test/js/node/test/parallel/test-vm-ownkeys.js new file mode 100644 index 0000000000..47938a176b --- /dev/null +++ b/test/js/node/test/parallel/test-vm-ownkeys.js @@ -0,0 +1,26 @@ +'use strict'; + +require('../common'); +const vm = require('vm'); +const assert = require('assert'); + +const sym1 = Symbol('1'); +const sym2 = Symbol('2'); +const sandbox = { + a: true, + [sym1]: true, +}; +Object.defineProperty(sandbox, 'b', { value: true }); +Object.defineProperty(sandbox, sym2, { value: true }); + +const ctx = vm.createContext(sandbox); + +assert.deepStrictEqual(Reflect.ownKeys(sandbox), ['a', 'b', sym1, sym2]); +assert.deepStrictEqual(Object.getOwnPropertyNames(sandbox), ['a', 'b']); +assert.deepStrictEqual(Object.getOwnPropertySymbols(sandbox), [sym1, sym2]); + +const nativeKeys = vm.runInNewContext('Reflect.ownKeys(this);'); +const ownKeys = vm.runInContext('Reflect.ownKeys(this);', ctx); +const restKeys = ownKeys.filter((key) => !nativeKeys.includes(key)); +// This should not fail +assert.deepStrictEqual(Array.from(restKeys), ['a', 'b', sym1, sym2]); diff --git a/test/js/node/test/parallel/test-vm-ownpropertynames.js b/test/js/node/test/parallel/test-vm-ownpropertynames.js new file mode 100644 index 0000000000..f076195257 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-ownpropertynames.js @@ -0,0 +1,26 @@ +'use strict'; + +require('../common'); +const vm = require('vm'); +const assert = require('assert'); + +const sym1 = Symbol('1'); +const sym2 = Symbol('2'); +const sandbox = { + a: true, + [sym1]: true, +}; +Object.defineProperty(sandbox, 'b', { value: true }); +Object.defineProperty(sandbox, sym2, { value: true }); + +const ctx = vm.createContext(sandbox); + +assert.deepStrictEqual(Reflect.ownKeys(sandbox), ['a', 'b', sym1, sym2]); +assert.deepStrictEqual(Object.getOwnPropertyNames(sandbox), ['a', 'b']); +assert.deepStrictEqual(Object.getOwnPropertySymbols(sandbox), [sym1, sym2]); + +const nativeNames = vm.runInNewContext('Object.getOwnPropertyNames(this);'); +const ownNames = vm.runInContext('Object.getOwnPropertyNames(this);', ctx); +const restNames = ownNames.filter((name) => !nativeNames.includes(name)); +// This should not fail +assert.deepStrictEqual(Array.from(restNames), ['a', 'b']); diff --git a/test/js/node/test/parallel/test-vm-ownpropertysymbols.js b/test/js/node/test/parallel/test-vm-ownpropertysymbols.js new file mode 100644 index 0000000000..f943b86049 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-ownpropertysymbols.js @@ -0,0 +1,26 @@ +'use strict'; + +require('../common'); +const vm = require('vm'); +const assert = require('assert'); + +const sym1 = Symbol('1'); +const sym2 = Symbol('2'); +const sandbox = { + a: true, + [sym1]: true, +}; +Object.defineProperty(sandbox, 'b', { value: true }); +Object.defineProperty(sandbox, sym2, { value: true }); + +const ctx = vm.createContext(sandbox); + +assert.deepStrictEqual(Reflect.ownKeys(sandbox), ['a', 'b', sym1, sym2]); +assert.deepStrictEqual(Object.getOwnPropertyNames(sandbox), ['a', 'b']); +assert.deepStrictEqual(Object.getOwnPropertySymbols(sandbox), [sym1, sym2]); + +const nativeSym = vm.runInNewContext('Object.getOwnPropertySymbols(this);'); +const ownSym = vm.runInContext('Object.getOwnPropertySymbols(this);', ctx); +const restSym = ownSym.filter((sym) => !nativeSym.includes(sym)); +// This should not fail +assert.deepStrictEqual(Array.from(restSym), [sym1, sym2]); diff --git a/test/js/node/test/parallel/test-vm-preserves-property.js b/test/js/node/test/parallel/test-vm-preserves-property.js new file mode 100644 index 0000000000..0846fd4f79 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-preserves-property.js @@ -0,0 +1,25 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); + +const vm = require('vm'); + +const x = {}; +Object.defineProperty(x, 'prop', { + configurable: false, + enumerable: false, + writable: false, + value: 'val' +}); +const o = vm.createContext(x); + +const code = 'Object.getOwnPropertyDescriptor(this, "prop")'; +const res = vm.runInContext(code, o, 'test'); + +assert(res); +assert.strictEqual(typeof res, 'object'); +assert.strictEqual(res.value, 'val'); +assert.strictEqual(res.configurable, false); +assert.strictEqual(res.enumerable, false); +assert.strictEqual(res.writable, false); diff --git a/test/js/node/test/parallel/test-vm-set-property-proxy.js b/test/js/node/test/parallel/test-vm-set-property-proxy.js new file mode 100644 index 0000000000..2e3293bf62 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-set-property-proxy.js @@ -0,0 +1,16 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +// Regression test for https://github.com/nodejs/node/issues/34606 + +const handler = { + getOwnPropertyDescriptor: common.mustCallAtLeast(() => { + return {}; + }) +}; + +const proxy = new Proxy({}, handler); +assert.throws(() => vm.runInNewContext('p = 6', proxy), + /getOwnPropertyDescriptor/); diff --git a/test/js/node/test/parallel/test-vm-symbols.js b/test/js/node/test/parallel/test-vm-symbols.js new file mode 100644 index 0000000000..e5a4e9e756 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-symbols.js @@ -0,0 +1,23 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); + +const vm = require('vm'); + +const symbol = Symbol(); + +function Document() { + this[symbol] = 'foo'; +} + +Document.prototype.getSymbolValue = function() { + return this[symbol]; +}; + +const context = new Document(); +vm.createContext(context); + +assert.strictEqual(context.getSymbolValue(), 'foo'); + +assert.strictEqual(vm.runInContext('this.getSymbolValue()', context), 'foo'); From 42f23f0966e1e1d33fbe33bf6c4b98e477105119 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 18 Dec 2024 19:42:33 -0800 Subject: [PATCH 052/125] PR feedback from #15865 --- src/bun.js/bindings/NodeVM.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bun.js/bindings/NodeVM.cpp b/src/bun.js/bindings/NodeVM.cpp index 336f88e09c..57b76bdd84 100644 --- a/src/bun.js/bindings/NodeVM.cpp +++ b/src/bun.js/bindings/NodeVM.cpp @@ -200,7 +200,6 @@ bool NodeVMGlobalObject::put(JSCell* cell, JSGlobalObject* globalObject, Propert } RETURN_IF_EXCEPTION(scope, false); - slot.setThisValue(sandbox); if (isDeclaredOnSandbox && getter.isAccessor() and (getter.attributes() & PropertyAttribute::DontEnum) == 0) { return true; } @@ -553,8 +552,10 @@ JSC_DEFINE_HOST_FUNCTION(vmModuleRunInNewContext, (JSGlobalObject * globalObject NakedPtr exception; JSValue result = JSC::evaluate(context, sourceCode, context, exception); - if (exception) + if (exception) { throwException(globalObject, scope, exception); + return {}; + } return JSValue::encode(result); } From 10990f5213384581a9ed97c9fb44d96aef53169d Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 18 Dec 2024 22:54:11 -0800 Subject: [PATCH 053/125] Fixes #3554 (#15870) --- scripts/check-node.sh | 3 +++ src/bun.js/bindings/NodeVM.cpp | 3 ++- test/bun.lockb | Bin 427354 -> 435666 bytes test/integration/jsdom/jsdom.test.ts | 14 ++++++++++++++ .../test-vm-set-proto-null-on-globalthis.js | 13 +++++++++++++ test/package.json | 1 + 6 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 test/integration/jsdom/jsdom.test.ts create mode 100644 test/js/node/test/parallel/test-vm-set-proto-null-on-globalthis.js diff --git a/scripts/check-node.sh b/scripts/check-node.sh index e704b7c893..39624e8278 100755 --- a/scripts/check-node.sh +++ b/scripts/check-node.sh @@ -3,6 +3,9 @@ i=0 j=0 +export BUN_DEBUG_QUIET_LOGS=1 +export NO_COLOR=1 + for x in $(git ls-files test/js/node/test/parallel --exclude-standard --others | grep test-$1) do i=$((i+1)) diff --git a/src/bun.js/bindings/NodeVM.cpp b/src/bun.js/bindings/NodeVM.cpp index 57b76bdd84..4cc8514f24 100644 --- a/src/bun.js/bindings/NodeVM.cpp +++ b/src/bun.js/bindings/NodeVM.cpp @@ -133,7 +133,8 @@ NodeVMGlobalObject* NodeVMGlobalObject::create(JSC::VM& vm, JSC::Structure* stru Structure* NodeVMGlobalObject::createStructure(JSC::VM& vm, JSC::JSValue prototype) { - return JSC::Structure::create(vm, nullptr, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info()); + // ~IsImmutablePrototypeExoticObject is necessary for JSDOM to work (it relies on __proto__ = on the GlobalObject). + return JSC::Structure::create(vm, nullptr, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags & ~IsImmutablePrototypeExoticObject), info()); } void NodeVMGlobalObject::finishCreation(JSC::VM&) diff --git a/test/bun.lockb b/test/bun.lockb index 3ebb88c5a69b5a0d1719913fe3d8be9aa2b7faa3..5d98fa37535db41d2de17bc87f16664cb7ab71cd 100755 GIT binary patch delta 74606 zcmeFad3;S*-!{JYIXPsT=ZKaVYHEcVPa=sU=9uSsXhbB3Ofn!!lT?c+ij75!7By3| zh@q$&OI1sYR?$|`Qe#V^>bF8wo8`EF}O8Z>#r0}sUOY=h}j6WuFXhL|z zNNp7|sR%v;SONGW5|;*^0G0)&A~N&K!k==$C*UY2EqxAzY7kO@e!$YmpcJqfLYd(P zU@hQi=;eVAifP&lz)L{3>ZrnZfG>it1XcwOL41aXN5m(_p~CIKS&`((#H7eXO)G;! zN@*jt^qc55)+`AETXdp)rwZ+9E_`2KRw1xE7jE`~{o^o>LiZ z1+swM7zB3D79jG<rKXgQ7L~=>&gwE3Z&lV`7-LpyMGe^*w}9jcBcuF>xf8YFEG;EL+gwwI zuQbEF`~t5d75h4JY-B_@Txwx$$=?OCjuU}aF5$`1{v#t($AYt~W6dRAKE4fKku@(+ zN5+moDC^qaJmuw+=JC33mG>P4a{RUe;S%YQaiiUF!{fC@;Pk#JK)Um2w_FzP){}Kv z@v7|ABzKe*{}OcO6ANTrz68=AF4UK`Q1iZhdSYaFM6$m-X$B&A8WD*`ehSX6d=JP* z&TJ@oOngcL!^<{OjYl{O_{`ko@Nq9_ELlwau<)d4P1}lCEOsr>07fRIB)emhw55s{ zc1k_LKgJ#FPS)N6XKq_n>0?#y$?mw+q=Zy0B0AiS!nOTo{Q^E!wg<@AD}lw4Y9(T` zt`R`l#qI+2(!L3jYFv0+ynC3YMJ5eRamNhPIy94A+8D?Q@2AjEcrQfiKLFX~$AD#k z+Z8TVI78t$g~Jtgm)Ih`nG#+B(vQk3bSS(VEcHu3j@cIqcPm_D_ABTY`eJL@RT1%V z!-vL?)grl+sTr8 zhsiF8iH{gL+#M6y9GqR@)lqt1P6ye+Yr*LpNy*{KDM^t@i@@m|?zrg4M0ax1u*d{- ztfs9)zFac}kX`nQD(6aDnco>8+@VzZ0vN>+!Bfy0Gt=9z_D@}9M|c*?;o(Wi{waxW zpDwZq1-i>r1I$z2HPhmd2P@$OvVnCKMvhHLj7&<>%J-7F6$ElBJ?JTY@j8&{z6a7< zz64s0i;S}x@tNZDfb_-4NdMvP#H8eR6dwyjdFB`+Fi_d)J5-vKxCA$+$2!HAs5BL^ z+A^544r*EG*%Ud?AdsCl7G}VcY-zo zoYfnkicJU~8PD_%r6(n0WsM!HVePik^#`&Ohc@CRMAN#0BYlJP5--{%S_ot=(^M?aK6?y!S?G3kx#{_?jOSU~wwl+A`vtCr z$}WBnXt`^0qP1TBvwN7Gv!pvVHA74IrFo`6F;mvuv*M?Q$Hbs}w0d)7?w+mv1q>it z(s!=JI=~mf+bKS1o*bA?K*k%xnStXp(y^BB2wBTFf#8MGUzsnvxUzY@grDz!-K)pB zlhCc2cHOK}(kJY~dot4+z{1F^1h5=1Y=O-5&-bO5wOA-SDkeTA5)P>KM>sopn0xqe z<`!mVl=Mkk_JQn(89;XP1Ry(5d?<5CPKt34MeIoE<)MGOSko#4JAhXJZUe6hbb@n! zF92s(Q~_tLUI(uPEUfq-#UB6>zkhlt3?_I9SP|#|`T=h*k`+1!FkdPQ3%L`nS4YHF*#zdx|mS*wNM&NB|#Su3lJ}Eg0JBVzg zVNK6&lq->Er8^AHu1`pbO<)U-ncYhJgna_lfVve}h@onM^(>s8h19dadY1L&D1`%( z5XHPS%;inUt<-i|h6Bh|@4+_Nd)E~vMESepk^{5~;H)D!_k3DWaK_gZzHgQ+Q&Zn+ z29{}?=E#tF&D_5sJYL=wDb{4L*o#xdDc_U`ugw_Ia55-Sx3g~N(@$ne@uK7 zcDmsa(UDs8r!rnYAP1_z0onL23b&$x?2Il5w}!w!Hk>0A{2Ak?VeNv!mdpZLKA4o~ zW`&|+;)fEC9hCZ3ASZ=q-?Op0p$%kv-^nxbi;Im*|KL zJa>k7cSx7I4rIo$sY#<^aMfOUOfE?CfE=1GpUVnO2WPyu6xKDv%K4?uJ0YEXJdkrd zB0hekJ5tl4!Rb=HfTe*ios{uP0ZW13JTCjE48qxut$-}8p~4@(l+{12(9_KQr(|t* z08yK?^mQ;e(zq*&8HxV$EQlW}{bv-!YR?2O0Zak10>gkMfz?nTb%&~mXJ`HZ>FAN3 z<<^r=6t0EQqhhpotl5kKUH+}6)kDNFz`DTpK!0E*U>)GyZzLX4xB^%idTe}LR6L$V zO#4nQJ5k@u3he@Nx%p>T^s$J~o_*;D^qd!rRP(w|<+P+>@v&&W{gTZ6_lt5#Tn}Xb zeh*}`KL@he9>3qM!aZB0d8R4?`+Vdl#JZqB4*T36D$l9~z#N7U_mSPqY6b6BhYZR%if_%Wqd8TT<#bIpEmR zCC86!sLcg03SC#>e_ogIt^w%)Q;{Egt{sr^@bF-G160Jb*$#$YgflxKF3Q^0)>9Ej zBt%B}L-Da9a2KE8&%Pb6D*7pOwxB0?S)e;MJSx(El;(NN)&e>Uo^@Md29TcWc`WL@ zBh$q}FP(;ffhuAzm2rJ!zygXZd<31Ia}CIz`WncBHv(DELKQwng%1ZZeKjDbSbS_$ zlzTXqD)(^i2(_Zn3qddTCnh2dPY)zwZm_E^B7pb}kiOx0@U#Ab)E@v@fam#-8=J*s zbZvW;UdxdMKX@q9H;2x0K85ZBbb>SAIl1V62At28!qCL<2zpt!M>2r`axAX{nIJYY zF)9*+n2GrG3Eog~{XPAcjGqdfUCo>SQK(R2WJ;2Ic&gU#vFy1Df6Iyu2Xc0~bDc7Q z=f2-_zwcR1{_Fj{=U%;{slVWp_J8Rq&_85I)u&k51Nty>+X1 z>j2qnr7$e))l5UTMkO^oHU`nOWIhE3wkRa^DM0#FLm+!Ge8gx*(>#|v&!d)Og=PFS znO|DEJ1Qs2|zBzeH6NYG2L2}egU#TxR2GM?PYYWGWa}& zqZRf8R)ih`d=XdySPl57v~F!FzgPGPuoCnoK*pa8tiY-6Rsp}FAa?m2U)`F*9{+nA zoLxGng3RD`AX}31f^N;YVG8>KIRsG%XT@U^`G{Q8uDvMp`x?k4Vn4>5;k&@o*ma4O zWWrB?4B#VG)J1#UPZn?!$O;UPPxQyr-RN#u-~hpTQ1)Kefe$``!5ZCCcv0bT zAbV~XkUg?SVP7D7cs7tDmK=>6<7yk#tRiD09gS~ydS_>!Q%>d1Di0x zG#JETK#o~rbYwWn(k6h@_kM0F5m)-Slvqt0(8OF*xklQmVA(N6LZl1*1u zklA4;lbnhNsWqF)@Nz(QC_2%K*VrXpcp%$RJ5+VFJ2@Fi(=>qq z_I%A2GQrT4;lue_FgZNYe|VCnU53u9)X?z6NPn!b79wC~OF4&LL^#)1pH{Mco|~U{ zz*+IQ$mH1Yq>);c)-qmXQbHm&7usrYgRb+TWnk7vT93B#X8Uh#WWh1Wh$D)dAKru} zl~e_`Zzl^#4Nn;tgQgr;`~Z*@PEb#;J+GIt&`?&?zy+O`=huKGLtxfbR%wF z!JO~geEj~HfbriJtZT16u==W3UXOV&$l=aN^(xiwyAI(|7e6lPdr*}BGT@u0!!Ms* zuWax*M(ea_P@6 z?)vqm(v5!iJz1|vl|6mhjz0g%gsR(@)+*=~Hett%;Lo>IZt88@@@jDTf?K+_T&3$T zn>npqdZroJ+NB>eQ}H*~%x>*6hTCy@MaL8{^mHwF- z*v@4XFMzAGl@=xG1I+ApE?t;82swigj$mQdK`&*dhPjOP1!cKjrjC-@n>k@F{h%4x z-lf+xQ}Oo?GrPUZ(HNf4%G}dFNS|m1c5pee!P{88h?x!E4zBwexnmWqzLv%L)6ARz zZ2+vEmi8^I5tbE-+1B0)Ersdc)v|`dYG+w%@~peCx?5T+%JQD-t}eZynT@}*%^dtKZ3cF8Ifi5I zqZVz0^o?eAHS%Ge~!sfxTTAqE!5S$IR~SGA`mG6NH$$8Hz?$ zFa!Iz^gd=P{w_1K`?!o7FKAj5gxgqoy{Z}5*JXs`Le>VF-Q16|Rw{-Z+BuDzV62B` zHKIN)eJ#w8c0ooGEH>N0`Z*4P1ygs}D#87%7{RdU>xhAl8EdBYcj<E`pzi{w@F5_`!>C85kZa8syqHCk>V57j;y|Uw%n}LH| zw!2l#os(VOxJR^}gGA`6?KT7H2G!nqr*LG`4 ztTF?KSoOo-`eybJm+`?%*r_5MwZ{a*2)yRfL(SCJT*f3^YFHyoQIvZaj3rs_W*9X* zb>H8?X$%LGPLt8y>AeYz4)t{EKT_dvF--lSnsUs%Or{-`$B@?81IDyy9b!IGOr{I0 zrMyODG|&UQ!Q{wuTvvi|(XcU3$2qVr=AQmRMy=XXm*ctttTR2$@fcPM`l{i2S=L?l zXBwF7E&6E|7;A$udCh73p;$pPW3ba0_==}Q^p0Z&nU(WCSZ!!|m#!mw>}fyrg2J&Y zVD4WK;0>aN9|QS07@OnZY9E!5oO4s!eotECyzE6DIiKeJOD*6@u43j{04-1Lvkz!;bD3p5Uf1UA@NA8F3xJWQhP{ zZ%L>A$jpgjZh`SG!xwTpt87k>a4@!2PX717m*+oV$+{x*QNyqC9#+cF# z-vwixtSRC+0Vdm12%h3(dyG(6GG`r5JO+#t)>}aY~S56Rb{_ z^>?1t!R68B=UG=^budFxgZ1X-xKx)HmV_`X*{69{;ZTp(GtXLNSs`PBz4D}bXsS#) z7FJs;lf8LXftDVvQ=T;kR%;X7?>O#och~l zPMQmC2uybw*AYU8C}dr>U+I8}VzJQnPRAH9EFUOk11v;DEG{2q5rs^yl0(3-efc?< zA2DezLh9Un0p8uP+du?sE*f*dST8KlSbdJ0*^^vG+3udpA65W|8w~rp^}*gSL63}QctHb84MnkUewIMXdVOOcoa4DE>69GnKOk~%fL(* zrdevH%Si1d8wk%D?4;iyq_7z{)n#<;oi~BuSF_D*XkSCax(YAS4ZxB{ht{6L2kX3;35KK8M*762@(L`%LN5g7hWgObWslR9DOmjJoL#xBJ zlzYYLF1?nSJssDEexBU1E;wd_HMQ2;W3YHhN2%?xYW0`HB740Vm=z{MOJd~&V`UMB zuG|fVWdJOrt5bhuX1|N350LR~LT`rnU~CUux`)$o1gwFzKgBJ@OqUUixx(CVb;61` z4h)w(P9?X~u>}krlo@1H9^|=JW#Gab3C5{_8l*dIy9SxL@3_37HMKOZr40vr7;<&Q zl9?f|1sTU-(Y4S@Opi80u(Ov8F0vSmJ}uk)E7+@&!K*5~#y#&IY#c|xqC=oHuQ~M{ zX7(JHaTglP#^Qin>x6q&e6Ger&D6OrV<|MILM!2LKY-Ecu_>MIG)fKil!W+33&pUO zPj@;J!8)5Em`VF!aSRMI<9dL1gzPjg>!Pv-3`-C$1{{#vV4N^uQ=PWv!_1veT;9Xv zMG}`J>=3_D46D~*r=wgXQd>LTfw1Z#B_>w~r)_GaIWDXjw)3eATt=hea#53GJ`+q% zP;Q=o0PASY_LrmNJ)oRAtHCfkFm*z)>Hiz79eYr3V+OwOGTw~#ctyqpr?C?ZE0>&f z`U_^x`z}YC8!^m~wn4@rSoCf*7vuC0jLk(4&4tH|kQ;oAD8fE@%5b%{jg;MF?XisJ zVC)!dztK%I!MHrg(LMym-j%r&i1CDBbu(In(Gz64H^ExSm}ySqGZlt(xUk#@yk({?br}^CRGvcbrU#fgOI;2VlC@|%?!)TK0dx!> zh0iru?sgd#7AsVctEV&3<6)S>#&ob&vYDvTDKq;cmtiEyrWY_n4+MCDV2_D~Z9FVF zE76nQ+rhY3dwRJmo-CJ7hgC0cF!rCkQJ4e3nG0w9uZqcCplh5b z46BEpW(Kasa}8*$gY*HP*JX#x%lH7Wy5^qFL5@sVZLGV7ldw1=t!FVt#qn}(VSPbO zdVxL7OMt1t!yQEfGj+Yo7&pPwx0plvPBRDEAJ77C#=~ zHarH5LjxbgWZnm6Rb1>3z(pm)Q$3_}1cS9OA9o2d-hf3HvNj0DX0SjjcU--V-@thF zMW?!*#*1%y7Htl5Z!o%uT)H-baob{br^9O^YHWt!-my6?=x~jtPJNP@v&CiXRhnGd z3%?~}Sa-0FeqbHVJ#oR_FkVGMP3YCJ&jM>@hP)T-^)||}HclyK_BKBB$=T*Id?u+L z68r6XKtV7ret8b6n`ZWQm+>?7Am~_L*2AeM%l@z&hEGhgT*kZ5WKZ)Z;Ri4^6>)(t zKSeG%)*`BRHdA-FxcA-RG7hN_I1g^T{sMENl!E5|9ZqikvRy`GrmPW4-r)2WU~HPI z-wwkJ-03pBrb?%?u25L=vv;~2uS3ILczTer3l^t?TwMyjqxwwfT`{s?96@X?F|yx* zVb2;9YzFRjIR;GQqq9BHLEh_OwaY6tVVU6#fmzCnTI1=wQ{v7c0T#OtD=n^7OTpyI zbQV@C=(r?efqQXA-moom>V3`BPh7?lXblm=n@u-PgV7n`(s0`f@5;`^jeU~S7!1aa z_O|Z7J~6ZRx{TkHh7QL3sX0?N${HTW0I(+3c6}Bsb{?)RQ=P_sFb)ysIm&nhMkmBX z!GN`%B_~mFYod$;V{5Iaq{bIuEFTXlx;t%!W}CUKn>pIdhDTeQ!+Ee=2rk5`d;bVl z2Q1H@3|~_!7;#*hS}W#|PhG&+Y}|Om8?wOUj7LF^Kfs!r6S9MhfH`^IgvQ2!DNjS! zt^#A_uz+sE-4Pha4c(6U9zEB?u#t0Y1nb4Eq2ZV(^#W!_rqdA*CLapyQaXGCPkrnH zn?-Za+d)PzlnrD4%O>@))A%h_UiwVq_=9CkU@LJP1qzdylhWYtk$ z=rnv5NSBfKbHl*sD0uu4?ety+#%1wo?_GkzA(VHM_1{ygly%Wc0c#@j#g=0&7+ulY zj_5bd)MGBA&ik@QvErexMu2sY@v-7<0}BPS_G5-)p?uVhOAlPGBN%%X?%3L?Pcd^o z#{*)eAuqJzPcYWYx>Px8EaHP5KK6-%#kN}Oul~Lnc*5n#`hYzgaw5oK|IpfS!s-SK z`@$1J`U*4f3zu;PoV7=Zu}+8251gqd%st7`PyYP zS(WE-v3TSPMyEi>W0+Uvu}}=@B`|h3ToV&0Weql1dF&)u-#k`xZT_$fu@wiF2%+Mu%=*gV{jde z?ZD*;<5zu)%-68i)?Q#Ote9Bj3<1{0iV62NE`W6fv({aQ|5lW4EwK|}QO7!tyWp?Q zoC_`^Xq#u>#o9~&WADhG+XP0BkvqC-+qn(Eb2&#WEWDt=o$3ZybU`_-?vYv3*O?_- z1s%Q?3&vgs>xuw`7g2^WG0=P^uxi9(-tPv~YU3`~} z^>j$PL*XE!i*b#46U>TfY=_0Q5l>=J;mF;x!{r_DHZXaq#C61Y0w%kTPTF#hWM~Z7 zT*a{Sz_soi80&}&C&Eg8B0Egp==A_=h%l@H*gH-FldaKn1H3_+A_#o||MlG~3&+(T zkANb~?5i$gEwtu{A@5{<1EaUWzfes5eV#eQd%svPHdk(i7O5~i4uj8}17ovLJ>1h& z+b=JQ2*Wsx1PekKF6yYm3NY44dc`F$R#ui?{!_VyD`ho#ELb~)S&j7G2S)FH+WjRD z$nlkf*k3W;eFk_d0{7Zx5&EdXya~pdVU*CL`@mX($@@O9qcTj+ffiuwLv#dknX1C%igg6+ z>1tN)n8#BXvn!bFGv0D!gLOnM)-wQy<8!V7c)x1&hsAner9hhbVA9uk+5bv0+-$&; ziX6{t8{Q$c0mJqhw<+Ub(WkIwffsED1 zJ%RcQ77LM25SpKnTQQ6fS9UPYL``JqxQ;4@xwpir-!oGmxs1Wzc>IMUdiq;@wg&Ox ztzhlW;`5w&Y$sSk9((y5zRQ)z=KljLa6W(7d9Y~2#MSn-0PpYQIxP3Ej_>ikCj{XV ziboG)!CHc0I-svlgY^JI-(fYZc|kS{AErRh4+HCHh3)??pdiSrAWzqcOHkM&@ZRxw z-ugq{jK?Fzx52QHiViXk!eTmX~b4TDc=(KF3u8CY-Z|3+AN@pwV zcUX9io|3gkYG5!m{Gp7XB`B3!-1X zgd$sA{+8+&$3R$k5{?{K!D2h4!~Fop0V!ebpMwYPw^bdDWw1Izx1LSdZrv8ShThER zcqji#oDRkbU`+?dS77)+LuQbp@?DliD+ZP|E{=_P*8Myy;2y6l?2$KN$r>MnW!2MB z?!KqL2Evl@R=|?+eupJAR&xo^L{ACl|aXYJ(OG4 zQq}{JH^De>F^jh1UKxx9U|WMhE|S9qh!3DU!s7Kq-iAy9V->ARd7lI84VLFfM!j4a z8;*)cE{nk!8+**xoQ|IuW?i5wK9U0@Z+ixSF_zr2EeC4_hFW2ldKZkPOUJ777t)y% z!h(#~U~vk_jmKiJCSbV6VHN%XEEo)zYdo;3@R*mN30Xl#3@o-6&hoa?@d228gmea0 zYb$<6w$oALZ)@qrE8G-VTq`Z-a_j=LE@igdzeQ6Y^k)4ha=ny}^*R_{n~o2%?R_G0 z8P3(PKGNeVx!&oh4`#hkFh;?0$$XbMjg4S*ZPd1x(|%3UMUbx^;_%aTt+NR6)p1J$ zv!gV#pPCL^p4#oHxd>)^8TTs8cG9e8&ojq7HTOO>3wq^6=8$k`mMLX$I|gw-O#NIiS@Y7_N5_msp|Mvf}BqokMQ^hj7}o2q;tTm z57Zf_VR6u*FNE{pn+o;J$DM6tp1-m#R|FREMDJZy{bgeV*gFZ@0W_J$E*C82v4 zDW+Rn4(qw7ZAdXOt~%Pjv6$EibezXG7zT?y)!{b*C3LN?G-p0Fufgms)n+C0%sDW7 zO7+@PGZ^3e=q}Y6FuO|g2bdi#(|EbGbY;{9&t|^Cw;sY}J;9u1^RxN?z;eI_wzj@v=PT%|75Gv` z3$f=FJ;-*=S2V2y$q(O~2(~0+GfXaS*8P&h8(*wI`w`ce1e5zDYd`4t60Es7VSSKM z0$**ABg+?(?hT>lmFZ z#;`ZQSORw1*|?Pf3j@OqM`x$)1wWBn4~{U+Pc(fMzWJA*bYyuG)S|NVGsI1D+TN}# zauLUI04knA;$cbsD!TP}%xbJL9gKAc+v;?D1=d46E{djCuj;7)w~vuvyxPdS)K&SJ z<2Nwe7vTcZu$oMRWe^+5B(TOvQ$U2)(ebDcl>RR#{UybaA$Ho0UXo!J^Ns=Ilvg() z8HN`H>u$|a-7_G#ZaTVv1(teLsztzhpOa@JZi(AK<$Xxc=7 z!?vu3*aiW_!7ua5fX^m*yd$j>o3g@VfK~gLzu5gv+paMxmMimFb7JrR2^L# zF3qtpRSsXl>?ze6{+_tDUH&3B2t)rOzWKpr2^USgIW1mKGWmR@!#}XePZ`GM09XsF zzvyg^SJ7W&@}-i8SqoJLn7lM{Ob>&}T^Q4qt}k=J^uWzwFEHh@xWk?c*3SB<#06L( zR#|*FRJVbg0@h@)r8E#bUFhcB4MZ-`;fpVxbQh0Z=*1$9bZvw*N5dR0&F`O@EgI`u zv{cu?jIm5xxh7&~C~|D*6uCfSGQP6X1*M~osQ))$Y65~)48WkunmxpusizE^i4VZ= z`9XY&jO(xnd{7aFh;`TuLVxqcOjx_I}D1m87|kH zX13U7VkZ>ahGrrcXxv8#Q_F{L_$asKj6Nc?7$&^dT-UlG5R(t%-VKa?Bm-@txfs_T zIb4NIN5m}++8!J#yBd$Ua98~fnCc{~onL^lZn#s64)AV~w<|!hR4{oF=8LlRilJ}u zoa|RHPHQB?6U3KV%AE&BC=DMM&trVj{yrFI0qTn2yeyzE z;rExpII@_7sAiqkc_qLHhJrCqxy8Mx!r&3uL^N;1(Zn+-+qgDjTo-i4HYnT|VT*vz z_udD?>l?mGZ!6n?6$dkG99Vy`ryUmQ(=g?Z(%LTIyF97^$i6pNQ+XMi36tAlw0e-! zcD9|^*$t)n;+s0`8OyI7J-}X-&*x!rO_85r-V4S|4QohBx6dCo3XJ`Liw9mw?gGOr z!lgmRJy=YG%@X!(^*e~%9&j4bK{V}&avyi_%mm*1wC^aHwd@*G!RQXw#nX1CqiEVo zZ<+?bq3>t~apDqb9r@7?1s76H#|e+Kj{gLiz9&v%ADqmmuR`or&`CI8SWgnLnX!)i zSPY6AXL+0%R;a`RBBZzOm&W`umHaHUA?zKTEPsZINA$)y4=2Ot9OcCvlh3iH!FN zPU?I4z>gI;poGtWJpLWDi$#5OpEO24f|L0jCBZ>tJwGSGK_ovxf`dqYk_5+pf=qYH zN@Zc1Rq$6zAhJE*;ABJ3;pFkJkQF~~#gfPZzE?ayGQW#Te~M7;VtrrTM;z~~dt1Hn zvx-Dy=2vhsF`heFM}B1Zb(};zPqL2u$jaQn$?%(2s6=u+xv_fjw$g#3Wk0>7F9Y#t z#5(e$Atv_^;*x6}L~pUDKN|Jd zc)dhPint(HhlS$tc(nvzJ+}@b>w=Zl$_lHcbr8A4byGY)QtFOB#2zY~NVBKHUO-Oy z0g4Y~AP!&}zs#vcDS^lej8Hs3mV=(I^#3`u#`^z{j8R)vVb(bVe>iAws|FC+&?&gA zSjUwA0IMU#dc@}{yiKJeI>d#6I_^is<2TgOv>PfT>{0j$kj}b~qC&3O2NnNMun^Ln zROyHu;4?rr^BkR+!bKI~Um+9xq~bjbb#Wn0uNlr5S5-73ll`W6e)NN02#sV=VK(-E zgUqKm;uRIKgLRj6Nvx!j{X58cQC-D<78XHxeT1_*4OBcLi*2Gfk!FBR&3zbFfni$E$_n&q9W`MR)lpz^CKEDkB>u31(Lh$%tulNT((6a5c!?_BvycOmYD4+-!!$%>+zgd~$OuyuC$iv7 z#s3wuqSFwMQD>-h?<$;05eJb2H-`oDm;+=&p?H2|!Sj_)WW4u*%-{p16B+MA#h--? zT8ckRw*p8{sJ<2k1J)~HGmsf=p{UR%)=$*yRiT`vz;w`lv-c-TA zE4&3{eeMC->wf}yp|F6``SpAr`H}4` z37tV@@P~f<0+9K=Nb$cQ-Jpv71xttV-_a&+M(93nrhiEV|0l@$*HGz*%%`TpT1wB4 zSZIe~ZRg63$2}v3LgNZIapyhkm-j4neQ+LS}4oUC&-#ctB501L?Q<; zUh(|M3`aqy1B?Zdj{~v?-cs?2tiaof=V2NICY+`sOji+zEO55cO{Ei=(HwMNcfIW?LHb!e?O-(P^5_9~Hx5 z#AqTG)auusDs^v_IzKXcAL#7IK`P!56_3d9*OWd~=|skl2C`Wr6~?LXd?*(!3T#G# zitsGtE^RErSzxNdaVq|Qg4{(+Q|YIBp?qdILuHg7*@8JrC$fU`6n_>ne7*`Na+)s( zvIkZv{l8%m1Tf(mpe`!TQ1{R4Rs8=i$hCN@%I7~oIZc^>Q|c2S>$gwgrz%4t_0Pz~ zg&FE?QM@Bmeo&9he$R+tl6_3dN|4HG`N+(jk0%ZEDN+;@~Xsp_OT~{)Z(SBnv z@P^Wf)PGm{ErqvLcz$HMJ4z=q-8~?;ImIwZ$xCpuN|X=EN-BY9tu#P(TNR}f+3uHs z9FJENuM1>>^?=N{K9C2IyrJU%9O1Z(6M#P~APC3|gH=Kzb(i8q@)n8{+1NIU6WM@{ zO799}MY;o-Zx0|3A{#h}E#ff<$cRG}hAZ7dabhM`90m_(u(%1zZGsjL%81GM!(zuV z7&u%l}=>54-|f=aES_kifYAKsv;~?5s1uixzblCok)F^(pM`zKl&m3h|=>T zd*C>9u0-d6^uSAHVDK7t1IP%sf#pQeQMeC#aTM;u{%`$BV-1;i-W(U z^!$kWYPD6mIx0LrvQe)>=Wx^qviBOQc=-_HpaNKdCMp7v2?7-VcaZa;g^K_0qb&bl zCS(tFRvG_~V_Lq9d2Q_t&YtK8q(hAbQcqX$h~!fge-<))rV7uG9Ew>=CzAWmhQY3$ zqXLK=+XV_21Fb1V6es5DHA|8%17))1mi&0Gx)iJe<&hs*osEnJ+@!*ZIGP|un zmY%J`cPiWkWIhLgJc#V3Ly80CrQomX9HDqao9uJ#8q;j2oo4`hZ76>kLO@hoIT8mo9s zB&KOj7|gJ#N|+y+AV`HbQ{m4-#&aQ@ozz;zBa(MeoXDQ-qPRqiKMi(OA0S)OPvHO{ z6AS^efY*RLh^%mg(uV<=K1N}(3LgVxeyKnnM5Y_BIFWm3d?Y{?kf9>Hr6T+*WW}ba zbeTXF^o~kLWQC_GP9&cWq%X||GW|TD<^MDoK>&FWS=09vC$fNriW3>1|6QEtXaj>M zrA|uBkIe5GFW=?-`*+^LGlPHe_T4J-KY#g-T%W&vfByE}dMi(te*X3yo$&naJJvFI z1DBlVZ{O27FL3-%AhUY@_TB2vXTFW+W%*fe-I;>=^SAHM-@bDvhQkfyw)6Sh_YYN% zdtJGPIzT!l2BzkQbvH=e(Jr&m0G z`)=I@@+CWud?=q>QQ%(VS#RB$fI4?+&)>eQ9{hLS%JUiGfAH3w{ml5!-@ePY@bt&$ zZ{MH4eOC|lx#z|4{O$Yy)C>COZ{ID4`d6>(pTB+Q*7^gye|-M-{a?JDmwTvZM&Neg z`P=vBZ{Po)e*2E!yO6Kpxmx_kZ{H^`SfFPuSYW$vYks%x=O^Yr@)}ZiMX$f3sx7bP zYTDW1)sO@;UM28=*eA+nV)ln@f z6&5EJ+RCTJ)Tq>|=-S>jjzwNv_ucyJboU{jN3R!sdE%DIU2eSmxxL@6Y0J0#`d-YJ zJNwo#$G7~r;P!}PHT#Zqrrrzw>g^KC=4A2(h4y#xzk&P?kLU1;h+WlrX_+5?dpEu9 zinL}YiY&|x{PBZthu+xrvn}_;{@$YhZ<#%&9J2WyiK+ZcyB)g+4r}ODF?HsZb1VBT zU0ykPfSDmCEJF2uT{iYD(Q*Hu`qoZo9gPl8n*4G1jr&6uydS!*x9y{J{~^c6hMl?^ zGHT4hLfIE)*+Qe6g=OUW4n5PP`v0&^aMwx#VsoPp8fpuqD{tjxqqq3(X5J{N|z~LuHQ~A zYC@Sx!hf-?e5Yl{KAhA&xbdvh-*i9u@%-&M?RU9%j4dB={WW{!h=Jc6uD*V(`R3-m zCvzw6x4+vXU{`k8CY>)|IC%f)H`O0bTb4d-e!kv&U=!yz+j@&@i)}^ILYHou+;)0Z z{}rXrkKWxjX~L>vwGtM-+du5;60aAB73))B{DzA^ZfS73+u&RGzMl}(KdsA8ksZJ2 z{d?n`ImaKCTi>^LzI^%3DbL|mw$wVGtcDNPwX5=z@4cuc)BNuY2yYe?zv0^fi`F%% zw7<=bFUFRiwEsQdd(Gx|JfOi1nz!;*?@|8h-J5e^ZoLEk@t1mi`{%McTh=VPHp>70fb!?-W%j=}OZ#}p zz>2NX7T5XFcl?KjD`4L1UJIr*>3*wM;J15!ynbZPxV52IM97Dz-XHd1Kd-a*uUt+3txWu-5`TCPIdR)O zd+W`{!*aUhtKQ@M)$6>e$jHrYQu=M}7SOVKo!3*o4_wqQtLvOS%f5WG%Hlr@4*2Rw zo9Hhp|LW_Q_+a4Fs!s+je|dAayPKTTFSl)w*~I5w&CTK_t2d+1lQ$-Lzfwob8lN_3 z=z=HX?%n=5vsv|zwg-N6??V4MbG>F%A5}Z8Ly23XS53IQcT(n85o78{+$z6s^W8>O zA1rKdy%SVZj^AeU9A4WyO}bKXYFlkkj+uO7iO-6d3$Ik0Kl|YA&kHZFl9u{v>50?p z9IyIwP2ZNOyK9zzVN&8B{#T-Z??3b9LlsWnJiLAIv0ucZC8%D{68-&8bWH!G&&mLA zSN7d2i>Dt>d8JK@vYBDUyL}h=$GZ2ftls>+bK9E-%e1Tb+QpkUN|!4-t#TcE;4eEn zZZh_?;WyhoD+0e{=Q+G0C+74ldE@O5_ht4THGONZgzoO7-|JWKx*xOt)=B@ibuL!x zcbXtn)P5yY^nO5yTDwF-% zr>;H+?hd|xysWF#&e*thJNMUE|t4zCLJK6&u|)W6P8zFOdgeobGU6(Sz9dVShO_)Tup%&+;f_mUgD z)%RN25n0-@$;~!YoBj1|Tk6kgJ0@OyxM$Oy(=*0S@b}3++TpGG`_|pJO*wMlP?LA= z+`BV5U-caMtLM|*6<2%Wijb?LmbHBQuW9`+k657X-}h>AxhXH6U(@0HvKwX<9$d!t zmv6zwA6M}m|HIC$MaTSdr^@=jMuq#2PMp{1+ficuGF0y~@1S)U8v&}SPHIykp>59m@i<%4&_-#**E$5(+{qGwO(yX5mtAI%=&d~hYJ zeE!}mn7?|}7aXXyK|fVu;(;$5jlbMibzb|2?`IzPEvTNW=Il>{+PyR9LhGY7j`sB3 z{zBE?Y zyHuvEg3{|lC}r(p>4#7PRzqma0j1fh!9PoeL62-TNEs3t}&hv5A&gfkSXiz+K1 z?4a=W3J5jDDGJdWAT(YHp|;3a38DN(2v;b)BI>V#aD>9#RS^8eWeQ_AL1?`iLOn5S zHH2E5A^bt1z6f0d;VgyaYalcfcPLER0-@Jh2#v*(wGaZfLU62u;1u1~LAXX?8-+lj zuZJ*y8-&R95Q4-e3hlN-DEl#l5E1?{gohLkQgDfq8z8L8f{?NSLa5kJq3;d|)i*+D zDMoFC;GGTO429OB$|eXqD7?K1LR)c)LiA1ujW#r zdkU~rj3O)(M+qN^DqjJXi&TKvaUKo6@D&=oQq=w$`YMq@SS`*G)`S?Rgo7gW0)!nDE>JiuYX1Ns`WFb(e}HgQoTE_wDuj@W z5Iz@~7a<&>aFfCb5qJs0*lV^TV&NrQNByL@PNCLy2pum&I3*TbhH&;el03eQBwvfL zAJHwR#S+39kwf@Kbo&YLtyoPsEA*cM=R`lkd9jJ`oiMHdz8B$y3nCjJ9^OPbFaCmZ zE(-TA5LW%}5iSegs}TC$LctTRqTrvzQ3~F-A^2Z|aD_imi4LG}fx=ZOMBjlh{W^r} z;@ou<_N%D>E8sVgNw^^{6K;yY-vGahS%h2SI^nhmy#cr*768QA`^f0=4PiE!V6uqp?_2?#dbOH{av%VghNC=>2Nv3rSQRJ=0rfL8vIQDLkZ5@h=E|!u=P7RbCKIP^cn& zA4BNtfH2`Pglgg_1@8h7{QrhfU8MdEVF!f^6l#jvPas4WgfRUHgxca9h4S9^qH{y+ zxW>=Tv}0P3-URg*vvlyW2IBvL%@VHgp*9G$3PD(IgHT`Gp>UQ$FFS;WVu>BXl)?}k zUJx3KZe9=qia^*#!6|eHgliNc9S{P=CJOV5LMU4RLXZeA0HIwm2nQ*Ih>`^%Jfx6P z5Q0nWr?9FxgzDZ9Ld7U=2z^UHI76YOsAAar=&eL5p|vDX54jv6na95L!u`|HfgXjuclAA+cTvNrkJhv-FHydsP52rR*97a48di*|3gMa9PU zh9Vet(VV(ZYk4=T+l%&iU9Xz8zoLDEUbKHb>*oQ|$KjU=i;60Z?e)YuKUBCfereAt z*=052FKFeeElb%)~B`U@}Jat6US!hM9s_V_gqDJWV+F59PmM(jpg|(FRs~mv(otcf6 zW>x87$N$C3@kt1=_m!1?8nb9ZqB|)zT+=?@fbwMC*;(CO_8~UkB|FeQ)eD{hD2HD% zEb_F?aq$Vsyp3&}HNA!XC!5|sYgB9dJ>9Y9IHIwXc&qV6U&inL;p@-ot%1JQFpGpH zx>r_od;1Zq#zm83h9$!%G|SOg=_sqxMT`9@`=dOt81-s)t2^_CC97f&`(8((VElR> z9kq7dtV%uXQ>{pjt2K1gc9xI*s<>3qK8*>BzKI_ME{BNofz?>W7i0zgo4!lx!^b9s z(~s}rN9-(buP61!F5MdLX26P8ldSBACdQ9J?4(_xx>lOm7u2n$ic1mp4;>}(!>Wbz zDzr+x;^#Fqi&fK~|9##A|L^sHfNu}Wf|n2QDYT=b{Lss)fnt9XuaJs=KamI5kArw( zg6BKdhl4CGsyMw$ha6HepQrGv=R6K8jhU6Q6nsNgX?(fwqqL)96tYM=rh@n>nkp*j zbEWa4NVw2g$8n|c7i9dEc0y_Vre{N?eW5h0HT>CO>o}=2zUOr+?MtbpS@mwNME+J! z0oeSVoKU5G3l0Cc(rPV~c3vjda4pqZD(yR^@y9Y-EA4xwS^dBk;<%u+(y;Y{>Yd^b zO2jo)^HLEnDy=LuZ>3#=#!EaFNX@1+&ky;qV;{5jIQU~e954QM?_Q<-tTbO}`;~Tu zztO;m6>#zk&^&%o8h;OCkJ9)nK#cby&K^p;291@eh_k!WepOl}XkDOzYBy9`KiHlx zx8GD+T4jj6RN~*2SOr>TrQL$YLaO34ly*nOs|Ky8(mX#ygnf#(1AazVQ=rJndV-*p5CCyuDp5IEs9!V>tH2!W9)4qzcn9?*L zwfZ>sA)GTqS6Tzunb3IHpwVo|_9w#PbaAMNjbNv!i2MO2{Nw*app8))E5L5$^cti5mOAi4r@(uAm|Ys0=$pE3GvC zW);mYIE%pGD%n(N{IWEEADJ3|%Zl;%J?R%{;0RV)ci4rL76L7et?PlaloDMkVozv^ zIC(TzS})jxECs`(wBF!tl-2?o^Xr3?J;9~8mD2jc=C1yQBuNi_*ej&rmB@SEUVwHd$%ilokQ4ztXxZZ5TBExDSsWN{fWep5p@6lN!f= zI8Ofh6IZKVDq<9D&re_VhQ=8YjdL|@u3-ICJU49qXc&+FN*e*2;atE5C~YL{fhr!6 zJrjd7jnjjN=NHFfVOLZde|3!A8i$iJfk!xyiQ{qBP})$XB|zgm=MkZ_QLxJ@ZJ5&N zSL4wlEOcpFq!M{^!(T$=N;h0-$*|qfxY9)_Ed};SXk68zl{OkSf3A_Mnpq2jR$`!jlW^7rGf-0F-Aok2kmP#ovT``(q4yMOvU2|x!DWjaef8E1&mkP z1latEXCC}OH_bP2ZiEpE9Hlf4{Ss^b!AMkMI_wWoa0_4(H2O~l&Lc?N639=6bMbi- z=eN+>(pG6F!p?=p#cHC`-hzEwX>Td*ZD_wME$wZHC{LS&lRu5hc{>@JLB#pD(q^i7 zQ=oa?yw6q{Wo0gcB-XsqB2oPD8jvDyrc!SCYaCl+{YQQAz{CoM&OES$l!aPG#*MQxjkHyidI zYyE|>U5O^_l{k51DQynyKP?428>P(!=knScXSUMj!Db_$sfPjJ#hFRF-JVIRUt2fd`UZLpud3b&>kPYMV&a^i;{^%wAcOG(m2WU4{;(f5`{T~5u0U2*U zPA6ts?T=S2{u3h8u$wtQ*`kLk z@nP8PR#r4eX-8nQTdCzL?I`To$b=Pm1dW9p!+9GgkH1yC&tZ>axn*%afyjc-stfe@ z31UTmuc}%1+jy1N(^?~>Afw{caq{-mfs?nS1#t2<^hp6^jnfW07x)*>hdBBBPmgf& zwloJPe<$h&PX2(^cR0Vr`3=r5aejsKG|n?P&*D6V^K1U(7JoMD6P&z{<$Wt}Q+Zpu z8)r|PydCX|leeJVaPk(Dca$A)w#ONUvn9@UINRXth_e;W);K%iY>Shh4iCi1AAt+S z8G_S=vuObgP!NpfIGf=NCZd)6ou^=&AvpQtQ2e1N{g1u##tO^37iFR@}9Q{&O$gJV(rxb zS950_U&Ylm>YQ*+a0n1Wk`oB-aly3|_d;=(5+Jx+(4xg*;Z|G<6iF%W#fsD7&=z+o zwCH`-%$y$Hmh^k?_q%^wemvPTd#~-jX3reVKQTQppJRGrzQWWG{=J6ZAqjR4c*C_F z^DX8RcmeO=DZGc5@C??&9*954pLMVwHp3QJ1v_Ca9Dr|OBkY9)*ah1_H{H8oA8dl{ zum<$)ju|i$X2ERG?=b2&8mGYxTBL)v%f}w$J;q?69p*Xw4%$y%g7yvV3)=Rzt-pb{ zplw{6w60xj;0Z~<4i4~wq>v1fLkdUTx}sPMy4qL+qhSn; zfWe?kqAwvHbiLIN27s=qbgeZAM!`VP1zs=c2EFYxitb$WkeOBN&RnUuOao~_RUxYR zcmt~0P)&wvE?&#|D)s{Ls%6oSN1ugrpo*}c;XJ4UOchzGw^BXTbvO;GKsyDh)l=o* zeo!r)YV=eIcnDM*r`k7F6slHFHFo;3?A@>j=E3|V9x|+|y-f0T+{}hKa;&P|S!OJk zJ)kS7ib7Qqs)A?@s$x);f@%=zL49ZdwV*b91|=k4HG5=y6qmU{6$YvxP=$c*|8>8w z`+MEbuL9k}e+`Ra8R%Ah0SJtNsW1_ifNsSn!+4ki(?Pf5y7kToK@bR;bmX z*lz3gT7UT`IrxD$qy`^I1Gb8iH? zTi2zAE-h|pPuGQvE^KunyB~H!5hx1NL0}3@g5}T`>Op;I2)g^$Nj*DchCGlJazZZ1 z4LKkXoRAKDAtS_R;Ey+`p3wu-2A+@vR3E82X4NU{uY;^txZVoeU>1yr3823ckP8OG zFo=UXP!dYPCr}i051a?|2SE0FQvV0I_yG>V5jYCR;72$CXW%U8ruZUtb_I0f`weV> zg}C*E9*`ZGY>)%8LJ-_QMz@k3p#yXVeu>lgh*lx3|H|A{0sWz+YM{rfi$QTH0VSa{ zl!d0CTSnau=7ap8tFh6bd(jD?+dy4Z>mqs@429t^0=|S(a2n3QS?$ut;RNV{R~NI( zU!9|faf42*^GFahHAL&xj6 z(C-)Pmai7*Ht#dgtzA{92D+u22;s;^KtTwG5D10*phx+OKv5_L#bFuYE`iA~5p)-* zU(GHEeB?Ub_~5iI?+?IkC-0$2#mp#?-kMW_m&LKO&xf)EN}U?+ zxCyu5DqMr>u#DoL2>QM1kyO){pgXT7&=mA@nUg^`Uell~2`UHi<@r+zN<$e~P5}CK z?Fi7Xm+Nk;4SWHgK@HeRDb0Xt@EAW&;3-^#+wcqMX6aYB2^ZlK=uZymhG`zmfw|iM zN02)kJR}#7;8&PJPA0eoc|Q>MC!>IN-AU&7Lle(Ebq`fFBIpem@wtq#!gZa&={SL00ev z)nEI7>Z}J7;eI#a<)_%|j`hqG`)m;^+?Ln2MO`tTyz)9j! zy=OB0k)7iRs&ex@T!ss<9@fDEgbrY;Uh)vse}GK`1_$V` zzNvyF3D;SOSXGbjpbO}?%7S(L4?&+ z;P>B(|2=XZB*qi8gu@_Q7s;XS8{@hg_x+(e^n*??0D3@s=n0)+AZYLD1%seBbbv0< z2RcGu=n8SLhWJ%0qa`#1PIA4Q_zfl40dC%dtIq0jty&jX{i&zn)aeLl1MQ$5%m)4K zhgDRE$}Yuh32i~!MIi`*8{~c^tbqS0J=GNnj0L?`M^~|Gq+S$PQrJ!42f+h7S0XzR zd3VrHC97RWB2rTurY5Ex_pXd+Sc-mlO;tz3U<4HXl0QQUU>K+;SKuxIb$^2W0Nmpt zneIFFeuAMsDx-~37n!=)%nCt}1yX`ey*7AG2JV0!CD8rk23QKZ<@-{GbhBs3r%~&$ zp+iLt(5Xcy7RyNR4Lz|iQ^0)8?{sf%` z{s5f`G)&zE+=1WW8R+z-2VqoB<5T-ddQEUTYP<$*!s@34C1C{Sio{NYT1nPXn)m6s z)-`WVC=S^nD`bWU&^55Gg#)1o6b4-r7Xlq0qd_;XX(18{Kwi+!tQ*=ix@<|sMG8dd za^*IHYn2O!FbIZ%pt7M50vV|1^zdPLdaW`anwlu=;tk6Wh5w#P^{93l`G+b0FhF(J z0M*p6bgxtbG$U$$=uhX)GEfda(fZfMrhBAMu=o@fk@||5b1=(eR)DHd1*$`HXb7q_ z`5bCOZKwsRG||mkU8oNYpb0dB#-M(iLNmBeRsWfcNOE$~My_|Uhw>s&x~{05+Tt95 zZEH-`d+3Cu8x>WIwB%ZKAZ?^pS9^cn89LV0p5ya)YzM(W7y$i2R}#94(A9)X^V5^- z9?%`SL09MkouL!NK}YBS?UTqiUF}(tP+Ng>PUDtcF#v5>~)+SOynh6P$t5NeZZrgY618 z8=)W(>$SEW6*B4)JF_YmcBd+b8dVwp-&Ex(LO2O0KttY!`5h#H#-JM>U5#z!{ygUQ zm|H$@KhE`!up4$-_QUbBL;KfuEOx;j*av$-H^9d*kHQhy4~L)#o(^K_Zv6me4CW7* zhe2i3PG!{8NHsDI_dL`F?GitMHvMyOR{Pg(BCEyC&z7ZL>+U-n0bSzy0Om!^KulE$ z+~itw`Wt9YwIs9@u3}z+U*S4jgI}y`^`o*kK;`uM7SygraXsVWDLjG4@CY8l1Go?O z;4Wx;)D_(CT$2t%(fgk3ckmWoCy{x*?7s2kaZ|ZB*!>Br;ZaS`-~BtVO99Ct86*WS zP``$H2~!tPgF#hFx*S!Nk}gSAt)$wdw4mxG-8ra+31xJ=M|v()Go6P3)PqY<=VV=z zsKz?A<*qV{>s|wNUAx@=9*)bu#-W+@v%=EEwjh2Z#je!4BG*85l6MK~wFVr3y(-Hz zASD~uIjsBan7ZcC#dsdb4f#PA>$=*j4#A*mhyq~P>q=i0zUrWs$*6+V5XN;VsJ*)D zO20f50o?&a0M;H!_!G(XkC?+ir(E4`>N;7MnW_tku}obf7v@^m%({xvaOFgAyFFgl zKIynq-J*_(y6*gxYnN16u3c*+)xxMY#^t6zX!`k=7Wg7x6SFqd0qs5wu&c-Q z=TINkP2dmz7S(mg*x_Ee<}W?0zz0n7s(^LGK(! z3ddlrMe%0TvdKUH*fpc!FG~GQ!9@#`w{4{9krvMlm++8?LS%0Jb-QntBCI@+(PVX= zaXjsyQB?(*sF3g|DtM!m8BQ*CNh1vBQRK8Kmu%{}?aZTOSCOM^HJ0--LFI1Bz46H9 zrRiyVDZQZMA^$%*{%*(_ZT`7j)_{_bR?TL+M;jm2j_Q#Q0SZlvJcFbgK|r~r0EV*= za;)nI&ngm=;@!#%?~se65z}WYOEUzbn<1cW>BWf6&BIH?JuzY`qABWyiytoYp3Nzn zspNn;hD&%jc^WTkG>YX?rl`Z$PE}=)>uS+c-hYWPRgS2UAfaj;lLwhrVk8=Uw8wQxI~KV=UEgW8dVBNRg&VC3iC)TM^PS2WReE?P*$nYTlSA-EEp|+s$rMlaik{$%{PEt z3@>%YS^2~d6^vXMeJWU5j3c)>Wv$AEQfAsmk0iU3yK?ozN8NJ81 z#N3n`c;!{{*zx4OsT`kb_w^;nzYjg$OoxZY+p}3iiJ3kf!WkoPOV9)gWV*ynAdDrl zaDx4d=yo}cZQS6m+xP0(_g$mRM!AIR;M@xr9r=c>YjZq*ks4c!#Ds+u!b(a^B!us! zD~5AvZgZwu*uK!FgMapWkDN6hJ(8U&uq=-$@OiBx)mwOP)B@4@h(YFCNj=Fvgb#E~ zm_)g>%4bHH_sNw<-7`H-KrY6Vi^D}H!N(oLq| zCP)D_=E$d$DS}9uqK21TpG-c2WZ)FLzl2P&2e__VPO+y?Zp;=8XDj5i__A&DxmDw4sRhUtHm4$^_WYf3 z2xzA24}E+7+To~92oQ{}3d|^9JRp&@8z9_cqQVRh-i_t;l zmLaE&=$pNZu6$kU{x`_!>_Q{iDDx4B-h%)`+ThKre=a6Da1icKe`G*q2t&8y16`KvEH>hELA&tgme`AKI4qO&8Q zS$oqo#dpuLw_4#A2*yQw+0eohhu+ALy06=%h-}9zFPQ(NF)fvp!d;x?67H;wUY73M z{mc4hi|kfk=HMca#9riIO3y4dX*|Oo;Ji#JY1w(t8!_eZkW;BCyNE)pVZuEo%A^?t znNe1$u}JpMAO))^d>uObtt&IUdhvyIjiNSYtBsOjrm=?XKa+x*No8s|v`YS}yx)ud zl{HvhG>7r>?OFtE!{yLS@@LkxRgn@li-x#Ns?0)Qv$UCoKt^%Srip$#%O1tYJ#4e> zzIIm6#+9ZG$0@YWwX^NT%(1~g!9K@sw>fh%>S+Qdg*N;u_ofm>d~794WMyDRu_Za? z60q48`25$B-wdmOlu?V4(nyWkQp2)uD-*DY?uX(@$G(fh+LjNW zeqpyer16$Z{`7exZDW63=yq8omo==-a?%Rxu%w%h#T6-_#xn^@XU3genqd(gRMOZ= z4PI3~wn?{AdFHr7ind%jHedAq+@vjK+%8pQ&3tM!Fd^dt`xcusR|T``7gb5Wve}gR z*F0@bY_vCoNcb`$EhJr6Vw9H5i)aCrEyv)ieorr*vkf;?1y0i_I9z?7H&vd4tnbXCpAclAUR}jH^-Aui(K2=iDyKEtdt) zvq#o0Q>dLgv;=uTtToOepdG%schzG-+kfcbX**~IdIK{ZE;Y|4i^v%@wy-pi^nZfSpT3Rl#Rr9V{d%GW_6`d+1yf%e83@2?w zK66WZ`#t`eHC<0^v|t5OHz~dkmi`uAc3~@baI10A1=aA)9$&x6cqzNv&weRIzM@N4 zGF#2|ahEPFJiWIV>p=D#I)8nRi!PtD-5J;J@ZyO*4Hp($sEo8oW?R#*>|A1Z@YR}6 zme7!l6@!mj6>;{l=CvKQWA}Q#J3W!{!P?LKDYe$pI#}c^WulrZ4^lY%W$ID}hE=k5 zDRZXT+Ts&$H;K27|4rp5QiF16nZ1@RlgwRi_YeNRicwlDXRtDTX84FtIkenfm+#X3&_ln0sl~`rT)yI!5eT}C+V`$cbac7Ce{9G zWqG#b%rKl=nwsOyJfeqaPC2`Twa>2>(yPQnZX*@3I zJakuHTjKD_hww&jX2^OdkM!<43I84AlvGi}vNR3pl0eHDEISi$G3(m-kxp&RF=Hh4 zcXs~_{~SGMNs;g9^$wX7F$UN{Q0$^8a?=Yb5Emkn;9Y zU<(D^Lz-=2)J>2zdRJ1e>s@6D{hrc%$RwgGs%#fSo91bn?Uu1kG#3V9 zmv`Sd5*O@sGUzA+@#;*(E6u*RtpA>J?#XutiK(Z2v6XleWH#GxXUjOV2$nBf(D`8= zZ>C+NE8xr8pBtWiegGjG+QQ9_he}H z+REu|_G$qayO`79uiZAi^=j6Hm5OVfp_Lm@;isf#`%V6S(){KRj$KK$%hJ>_>+;dKVq@u(UvcglUARql{$Um9@L5{AcoZ7a8}I@ZGqjl`0rc zzrJSES`a;H&Bo)Y(D~4`4E1DgiQi2jL?V!Z#5i}PF7e>`pgl&bH1>W|cpXsfey8b4|GZ=*jiH98L{ejqA*VfF=Imj=kzY>YhduK>_4<83Gbv9V z=i0d_GUk|3JVq=3L4x)ocTpB%NbS802*!0aJ}CBRFM+m^9Q#OXr-5eVsXV{^xm%;9 z>j=S`&D%&<75L{|qPr%o0W)kXijT+{1EwLDdOvCH#1k)FnMeK7eWjz1e1ARNt5K2;$?U)DgtzAg*nx z;*w6^{2b(!6!B;p6Qlc5>3)RJH_C40=+qb0Ff>&$TW8@Q z=H5q%+0?l5>DB$*Mc0{NCg6FTW8IkK6AF<4eIOLgsSaGU>9ntN`E1K3xt&IbGTQkn z2|h+ZEv3aV(vVjAtFck09b@skOfvmwKaP6z`e}QHq=k(RR#a@qk@#Mm7|zDlbEM4K zujkm6Jo^^H5RoMx_QUijL^I%9*-@ehhIw~O_q#7V>rxiA@d zl7(qC*@>02$#k?FdjzY&(x>e0oI}N&(Kh@r z`(EgjW{mVkJmk-cXDlCvwcl}Oong)#-zP6$y-d&V(G1g4D6j|=brhbzt$@5%!%T{$ zaOM+0tw>PvMMX|$t~5+66hTng5kW3oHrGpt3}W3HM@43Ym_UBQPm6`Kg(j}V*)jGU6~CyX*uOpPYeL@oPEXYQOc=W$ws)Smse-NYTU@07IvwTas# zX;tng*{*Ugk<*Fw;iyrUl2zzB)E!q!d7{B)laxOrS7^Q|H{`fyp3jDP4s^>^kx~dm zw?RN3VFfz>9D5@&?K!u=KwPxPT-%-T-SD5={pNNVFJEccUt3{U>20fA>)9o5w}8m* zpQ!;et$fZ`Q~obmGxP2$39DSJQnJd-dZe0Et`bzVzS*ne%*pyIPgHt7|AtYg#`5E{ zW#-JA)TfzG|2t*Z8m+?E2`rJ|3#2JXT3ldiI9JSEz!W(9b+?lpzHRKubM>z-*o#H` ztT3NvZT0a@-(yAG@ zL(S*%I!eMXQYWY@F`NgG%Z}XG32)~l#b+8*s00vh{4ZIqXNBFO9*5C&x7q zh~Bu)EXYhXLNWi0I|%AaK+0C2t-4!%^k zv2WCw9~(YDff~m(NWYZpD(8^bYNVHp*H!#Gvz}(vJo&WYkJD37$~1Q!-k!?9>qKIx z((sjVxPGPZIp2G<;q?IG6;7cl2raJfT{U>Lm5YS2^74$&W*%`UYDAn)UeUtkfF!z zD<|Lc&3I}Aezgn(oDjcRcl%Oiwi zk8rE4v~`2Md*-EG;PA9<#wH^+A2~2%uA4j_AfYJ;Px0hl{_;L{PuqEHbQaUk2&lfG zdgz`-{)hMakhU1J7K}vcVH}Os+2aQ@)&>V+YTvE=r*2Oz{ZLWad5=6;a)~?&rJVXm z>icxL5NULu@P;2Y3w+&+TM5f6AL7^);Tg-tuVexO=0?Id3k_{LqT0SE%a|hhjvuIs zsIG)*oXh00h80r54D0c}fnDbObo4X=v`U>iYDl^VJVgHOs41{JeX-x0Rh@hUfv6DU z7|8=%QV{m$eD+4!FO0p1i|$;hngVdbpr!rd*c2&MD1QY*z-Xm+Nv(tSbZYO1@`nKm%mG z-c6SyYNV1I4{6jNO|7vcGoyEYG<2hta*|DhHA8piJZ?^?*(+5F?R@;?EF%@h&}9Y` z{n40=9sQXTW`V4%J2=P63ZZ6WHm3Psq}F3fto2DV@9k^;ay;jm`_V>;86$=%fR3eu z%KiP>pQmjkK6T=oDDx5EM-sL?riZSU2P*!Z<>))LL8|T}dmJTLJ+?r@+AZ0hAl^rc zsbL--;|D1^>s_KJ#hf2$_*QtuIr$N@lYBWD5AN^I5a++jlH=TmqG4Hv*g` zxv0hx`TZ$L>2uNStXu1bohr~f%|4?@jl7SOPoA+1ULmWVF*IyK&YO78oC#{!a7FUe zKH8cMx#PI_<1+nW+b;Wlv5)kz?Z-x2{%uTM*F0=6e)GoL8)xH(zEzk3YQQj4BAx$! z@jFrYoW@FE6!{kt{G8NT=K!`!i|5o+1(}B7%z4Eecsp-ed}e9YU-WR8=8b;bSAJEw zf6>;)_wG&^@h_>p(!lS=7uSx;2u4~wy0_@lMjic+ho;K5y`J_%OP$rJclQ=uVma0w zxb<$%3{ekp(P^0NkMTk3Xifs}S+yidzp1S9=r~=8-*O~j%_^%Mqg6r39!=bY0mmENV=WTkz;$sD-3hOWr z!H6AF2iG6LK z?)~*7icX!3h}$fe`(G~(n_KP8*SMG|NNlpFFwDt5o`O1p?{tLQwdiNFie_289p6^o zD-1XHuZ#0v8QZf`K0PU5E%7elCp~_o&6(WC#(xv)_VW-IotC~VzpMYq$c|myX-RU; z>^ak~m#uZYV!$uBgcl=kWS~`xPQ6-C(Ql(y>>8fmk&os`U23Hzo@w)hZ8l@^?2&kS zK3I>`aD7I-{5P|E7as7Fs!Md*i;VEt_KR7)AxUyI&b7Qif6FDNut$$>Q8C&$i?+S~ z^UO`dKf%RSI@ zqM~}YuO9o|ib7A_E;(+>kNEWry(x|VwEG1XwLWlegkh?@n##e$@_JRo}JthuWw4$mq?_& zWrlGn?%v6>-rY91C9>XeNYZ{IPO5V40g z=KglZ+c)kq`5*^c7BMf7)N%9s8=XsfUAw?q*O*Lbw6?pZOXY{X*{S`uk${U*Q9S*tq$9pf2e8sXw3)ZRlrotAIPRP}4E&JtwcYkOp1`g`U) zTIbgMx-Gt4ZZ38a;U%$qa`ZKgCvgd@ySZ}wSGE4FI$iFv@r^y|AH@{-_9JE2{v(#I z;N{c@j)94HkB?N=hfT$mDh(F%OwVnz#&L@Q$h8+O{o3TCtlu$1U-v4T^>*Kc0_m8&0k+?FPSYcZQ@t>Yt-QN|6OXx%rM?24t zgk+2rX17s{5-F|kaKoNRp-?g=6{2M(z2_Ve~awL%ReNIm%}ec-?G#B!lzTJ zh{%Qd+=>b`b`N`S(XHx;8r`1t@j9#zC#{|p`$`()H?Z$3vubx1oPD8KT|Zq&sNYDw zxbaFRdXbl@uVf!)%mpNMH&D0v{r9gXws@iGF}HoSUYj#niD$dkANG#s_?WS-qfyFh zDVUU$-gzzMlR6>-&%7}uQ_Q`7VR+JCBaJYOF`&U)nVQs5H89pn&)C*e*KfOU=&Gqh zVlCtm@J`-nSZ&`W_$G6-|LcH?dD_OAnFnGzG!;C2_Wqg^89voPjMM2P;-e>6K0N*M zkpnmxWRM=sG0(Z!PRM*cn)9zmZgijVks~*HqEV0ANS&09sQ)}uBim9sPW-2p>)eZV zO2|59lP0yJ-QVO)0oj+D5RB!P>lg()RO5h=d74Pxq;dTHFwM&1W_OR>Qha%oSKLk2 zRkNh0GaKhP{n6obh|@O<7KxnW#O0|ROUtV~juPf zgjEtzRdD=}w5F859k<6VY8>tK=O+?5*J+3*au`CU=S`ejuofaNV0h=2Z&*I4>O$NGcCf;+?=M4=qem3XLxIr0= z&cIeFEFu(_09+Eje%B$_JD*clH(_s3DY-PpuV;tk(kp|bt!I34xxzgM<6dTP3<*r+ zA#`N4$LQoT)yEML9mzY^x>fml^RSCfzgv|ET2=D|T^1MJN0n(-s)Bvh>_>)+p{p=o zH?uP)Setos7au(eA3E;*8c{lB(Q_517|Aqze9EIh9e4iu&YAfd#(x~Mi*$O`Hup~r zc0P2>x$=Ouvlf}YI$)f<^LHNRB}Yx$p|1v{$>e#qj~<3H`nL5}l~nR|Wah}h5MQdv zGUm!`?gDS7u^H`dMUiP;YWqK(uaA+;mkD2`krTeugLhh+k=XNhM@f#!%a6Gw^5CL1 zG;ht7j<1^6UE+2rl~%H3!f!n!bRVBNVE&y|TeD_yOLVbZ>ZZCgqD_N-72GbP(@IDD z27Zl%*7C;LJAb-#^Xpk|iS21+frcK-`~UhF#rO9#%MYhGlfup!8rDpVG$V0QzdmXG zI@esEFU;+-FoQf)zdJ0y;}&fy+I9Vi0Jp>?T!QeMujSTJCVjn+QVAu9CF&sjn)(fege1yN*NUx2^Snk2#@7Nl#=QMN{ zQ~hPUzr!!uhxI@I2T%7NTqd%~H;ncyH+lai{9pX0O1S9n81Y}u8+3^OKjw|7%#Hxh zMgdYYGsXV0jyYS;-c}%?WZ(5gt&S4L(3)t0d=Vh?@ax$>Ksx5coEjh{gBUVW$-T^u zNb?+oPg3J8zxqzef(WCw>RLTpJEc<=nnO>g&DhYJ`?eOyVV-csZJ7;3q!W z9Z`X!Uzwe6-j`cHS^hT7Ql72p15u*z%PFn1Q&hQg%8cx+$UeI6GnCxVb574eK63Lh z3{}Yw@M3%PB@uiK?cJ{hlm+asZ4 z@y!DpCnN;yigQbh!6guvsKpzfqe&k*s> zLjy@4BIVSqA0q4WIx+^)cH;OnTzWj^%2)B1KAp}wj3#Zgs`wCDorhp2BcTJpthRkm z&rG{(g(X3wUl}6TkcioeL^>qiKf5_*)bF1>FeHrra}*aHUTzm|)ji+jr^(!YuZBoS zUZ#adNNBsLI%`bP(#>BCbW6OqTvB%Ew0O^#qb|B#j6*p-G9j-c$jXXeOyV)EV)E4- z-m6lx;^;3+>o8?#jw3w+BIF%u@cf{7s^)V<=m{x7b_r{l(d}~7a&atM`=)Y^ za}O*Rou%*Lq;=V~b$`D(Db{axdy=qxj*JqT-x258C`RVxr-oYdF&JIdb%_~Yy!MQd z=<;0Mxl4>(2_}aFW8}U{jzdyQ`@k3RS3;u8Z9~%1=*)?ctOcmc)s{s6i#5VGKT1>4 zDs?*kHp}I0?7~@>zI(08Tk8PU(HQB3-@q$KXi3kwcly%x=i%KAzs4i4$1zecgmfe+ zB-@bm3@9Y$3eXU(^aakb!hWB9Y?qm}?{m0|5!mp#Iz~zsboe>{hbQg+ogo2UAQB3erR@o4`b}MnnF-1G82kNWaJ#^oVTNy!q9gzGm*t7Y8ruza@m zJnnHxNGa(UPNG+qvKd|E{G)1(ZoDmsvLTEkbQG>fLMd5*M9eWHbeKq6>4)a2FYQ|H zY1@O1Y5=Za>U=cbzu>ENm%L`MdSn%%+lBk3q)P+^X~p8XvXo?xAU%nPW%`Ja^fpI& zxgFui?wPNQq>3brW2Gc_B#kazS!t+dU|AWjW}dRLC(<$4JZ>H$U85X9<_ijup4ZFD zfhZOq*ZDBAPC}E%2b3wde%@Ml+i%<1oR!=3m=}L>`TIg{mx-T9NHle0JT!?+tO3(# z%%?|1*sLY~7(P=ubBVHJOvS!UH#bg6H2U-i-`3tVI+0^0G@6e1)d8sQ^_F`Ze388h zevKJ4i~}f~FNu^vF^+)5(nkfF>2t7A9$QX+jG;3o5*KSR<48+2&upJc%|cYuf=|tI zTletF=#fbqnTvkjJ&*EO@u|#1f;Ul57IIW$O&e6$5gB-|yeXf$=dTsEB}w3wK;r=s znP9=#sW1x5RBV&uO zs(4#TmKLExlk?FT-JZ6KZniYE;Dc#KM1}$`m8YrjnxAWM!2%=NwA2@B^{7L%M~%vo zrYK1^zKh}S*}SqeE=t2+vdnA&FFH*h>XTw=4zqZ*YI;_YiAXsAxj&4vOFqhNss-==(eiS$49TJh$`U+U)y&|%R9XE~4$Y;9J*<`V?Dm zuGY-~X8Okts$XhKjwRh5bFY2t{hS{|9!>Or^3HPK*=AifuOq)bPBzeV|Mgmn@mor^ zUGK}ip(6OH&bFFu$92puhl)8$rF%Wbv>skK`lzi>ns-aZzqlhPyvGF|4iowhwzab| zPhK>ACigl~-l~20VEc>7doSfaANM(5_+)Gq^V`GY5{tL^Z)q3a>TS%oZ}!%#wR8{n zS{=Xk7#i!{y3)m?-0QkwNry&b+g2zOn2~m&?tPD~eKWMrt>_@`btvf{cdp#EFCtQ| zu-e&o4|Dx6&GFx)l#w9RT|$~&X{sRi}SLRzaIK1Ruzw1i_(!pahk`&Z)iLqeg! zp~eS=g3XTzh4lEMU+Wer9?{+PE^!_5aO{Z3!TgP_#!n%!%jce1RZ3((#`u;ox91CJ&wREf8DnEOBS~_mIuk!+mSWE-4KxZpjl7^ zCr>$YI6r7K2z+oC9406FdKpFOXA74}Z5%n}&TdC4lBh)-;BI&LbKeAqhsom&jvSf( zYM|=uYOGe_q;s9lz|Fjr`0QSJ(wfIPurx1Z;UA7%8C?&^v36ZjWG7ZTa%40QhTvdc z1RJM9|eZu}wudt#L z+ukcBqR`^0hvK%5(#sF5CS0yNkF1Pf})@ZiX|37 zQE>!C1r-?-6-OLUQBi}U2S=PmMZxj?t=hXoJP+qQ=iJwGzn`d!)ocIPp2ym|I$gZ+ za-%(0H@fbumZ9BqXSS%_{K@YgKG^W>yk5%}l(awTnMEHA{dr1x-?~$;>-f@wDj{9x zEW5Dj=uI6H0wWYE$}B9BvpAz5s}PKV5PU2j}u^(oP0`3mm{2lFdJ?P*CT;Ca1>u9 zxE?+oz6iY`eCYU4s4=_`R;^yLd<}de_8RzPcmm<&pD`(~AeRCU#8yFyG7Abb3viQ3 zozV19>9;hSN>+rR8ttoUTI4UGHB{;i%#cpc$zmflS+O6NPv z+aso1uJ(q+H7z-ds0vjNRy&2^n(!R5Qngo;ieh&mOKMU&HKQ;Kb9rkTdmc?$PAc2E#l6@39#IyVr$8a-V)BYQ?>^5lu3#Ry99 zGRv8>Gjody={#>)e1n!>B$?#yrZ1J;^z7Wp$$3*kKDLURU6?mY8!3t#WwY#?A+qQ{Nm80sTtX19(vkqTcttLrc@Jp4P290 zYY45fPKHerXIE)m@=lsjb2D=DvL}Z^nS~Q)W#>!|4eDl^v?Htu-^_9~%RhBB`iHQZ z{AIWvyvgz%manyZiRCQI!wmNB9b|33Bo#O`npTli34XO%WbsM&GXkO#`pP*5D{C$|#yum|1uWwgyLb?$peJ z?4rWSnfWwqD0DyRYRy~$tI1l~d_L=I(t8_bIMgX!iK8X~Vj11%T@`8C@{_@)A!3W= zl#IfnYE64Ap!XE5ltQam6B%$S#xPi&7lq~D#@fwbP4-%r9nY!WpyW-OL!*8RtUKQ% zQk6Z}ayL6hVqG_A0a4Oc7Ml%{BELEfyasqN+znSR@hu2RjI zW*Tq2;YJlV3ND@#p;DctgJKUgtAZ-Z!{b<;@P@|ghE5GiQlfY zHV&5nzc73?OyAEpbLiZeroCQ16q-mIs=gyEpM9~h&xBR*7hxs%7_8ZtUr2*<^(A~w?6YAF zlk7s%k}a?mJ`p}1pVGp@srl21kT=&PJjGjEqp9=0_hO9}ZSzV@?TcX*vKEn)=}&B8 zmH5M@Cew_<;@nBovy0-rq~n{Ge1)$|E}Sg+)EA|Jw_Vznuc1)4apSN7D~oWm;%f?&R!A+4R7y!ijlQeEroXyBgdG zlzQRp%$y>|`mV*MII%l_Y@@p!T|K!GRxx*a%W5|0aSxXIX%(zgme^3SefAve`sfMv zc5}hCCR}W7+vt5!vuUSwsA}Sy;9$5G6$I<$zdFM_w#*F2G_OakrX{f{P}4IdkFEH{ z896yLPpHieCiU3X{sTHtHA!D?I2k?>yT7%^-Do=IJXql_(#+u6O+1zI8sC)iau~Z> zX{!~ciIco9YBf##=e>Gvb|K9g3VrD%)o#%LgOw)H7I1YEs|}w34=6K<{&JHUW#`;% z8Y(9*CzAmf8jZgicyjiXDN1dCH@|j+k~?oT4RI~3W}XMD0ax5+QYk9T$(~5)Dd-K+ z-@S#i8axQQ5&S6j$#5#R=J!f$HO0x;D%GXfC&9;Adz`fo!Gs@G+7pK&G>4nORp6%Z zfmNnJdtfb7ufeMBq`aIw)}~P89y5xD!x}$#!}2f8;1@@D7;m-3)#SvnD0yM^$~sRDQ7KjZ{#LF&O`#3zBDK zsE4{ftMDbPT{u*e>)~Jw78YcyKv_9?6U8q-XY`G*CPi%Dxei+eN_fE(;Fsr3Iu2~A7gJ!&J2aJu{ESdz;)r~ubFUl;X2sgzGB*^KK^RQ z-mr2z+w#Y+o8s@b9INKjyG&`ez?7z>^nM)bX-;K1(`mohg1Fl1pOTS^y$rh+JR4R4 zGU3|rsbna!5^!AXebJy< zNw!%CTJJOMQvg@P^HghJoHtpcD|9@zhSjbAFu7&q7AH^4D9qfCt$w=fLlbZD$EMl# zz*@XsgEd^2ePWu64N+0v^!A~8pPFGuVrn&&bHiOr9BvJ*C=? zhcd49rQr~)j*dN5d=#6ArQdvEYW^Oq@Nbc!5?*gJSZeuVSnZw#tEGm*ir*TpqnX_p zhXVXe0t)b{P3U%8gS;78S=ro9`Ot0uT>NZg<@;kK%3BuKbR(d3RXfr(3SDxAI z#w2YD8yz(I1Xx}A5G?;0nFU#y?Ku4tzC?o~n{$blu~k2t2tDyolj{sUlY$jw&MM5F zQXD$@7t=x?!|MCihs+|-&W4Yjo@1xx*qr?5Q*!LY%gMGR7@Y+f7bQ>3n_T?=^Wzns zu9TR*{~teI>0$=oYJs$dCf-6=@${&YvV?jin)DxqYhHlI zl)Qpu9-B@*r;!tkfZOm;Q~d*5HR*`0$(jT!qx!H4G?R?9I*qd&dm?peJ+E5R(@MT; zVxsM{yp0j4MTYytjEtg5Q)lEAWM$-rLa_%^S2Q)_g_}~)V8LR9dr~teSR-QgdhB5Q zS^XZ%!(cVE4ObHCYXin2a$64S!Tu~5xYwNGgp!Dm2dn3X!RqPua5K0bte*b)WYa-! z!lz(A3M>50u-a#y^f!fVs3I)mJ5Dzx+H84^<>jy%ZUL+oDYTpftAR(u>cM`n z!gYj|@XI8u8s17qx&eNCrs>&O#@C|De@`pYVHqjio@{D(JFJ>qZg~={8uoxS>GEvJ zzi(rPU^%Qw^E|8qTm}bCYq<}s0>r{Sf~^AHZuxq+qasYiA?^&T&kCkyW{_8C7`E1q zt!Eo%50E=+Mkv&_jW;prv^w)TnuhrZ*2sIKqqj2Yq>?{UOln`lYB$;{NWFR|GeVw* zHPRn}6)koEz5`p~OJNneRhp?5kLZh3ni=S-<{4c~yos}>OwpHXMHvOjQwl?&Ptdtb zm6T4*D9B7^^$ZvvudA6cO$ng2vr#uwo!A*-DYmMen^`m?qi}lY)TjxUS(snICL^>C zTerVEEN5i~4~Q$K_P5=Qe;(;H)rjH@p|f0JJ)7aVJxvD18M7|Vp(d|c`*~Oi=i7(C zv2SUXP*WB3xL#(iO@h@j9D=k6%!wUmhgyA3Z!dCJlT z4_}uSiHqDhdHmel2jvZWctzKSRU=gs`p@0Gw9Cs6ukW?SanAJ8`$V0qy)r&u_R9JE z%}eYXb+h8xXp?XiFJnw<#2R5Qqi;&&3#<`%`Ku4bwebe`iMUZVsohW_UPeZWI~QvJ zR-CuGPm1$`SJp4;)bPstMcv+E9z~jPeN)_0tj<_f70Y?fE9)P1YgGw_dIoXH$sL2G zLO9;OuT#DB0a5pDl&&b%RT8JJSB^HYs>waU%OJmjUi!eO^SoEa=jmQKpFewvgQDS% zv~Mr3$)Gf6fmepT6}wMh*YFb0jfVR(ASTETuf;Voa5;?1ZrAQr4Na^k1=)Cs?@$;igVa2$LDM>acI=>ymUV6d1XVR;VfnrrRbODZ156?MV(q+ zI-euFGCntW<-?-xuM7~SL+=esaZ|a4bjOPKR`*YFZuH8AN1eC5^5IdpCriuO_#}Ay z2Bd^%W2Jhl2Bx_W;2Mk`3iLm*#&~;&r8%R##1T>FHZPse&%Ck`QFj3M$zFtvsOR0K zSgApJ8WqoDDc`uDx2t$%7e?u;az3x|5=Tbef3Rey;qQ2>scmDgY-H3K>6P<&r zb-&?^($T~pmg1b^m7z`Kw$KNS2dj*hHP#}9{weOaSSpJtbvtehJ-t=^)7&ClDn~dd z;|o|CVF_N+m8l6QF(89LU2#b!5RFvqm5+`()x5+pQMZ8gT0TxN03Yzm#zdV1UOAuV zc!^^*lhXNQ(2tF}e>O7%JWdVgrgBfyaHj#V3b54JrW@||%Em?AAJNocgrGWSo*W9b z!J-Uw+h{CPQ29NK)ia2#X>iahA0KtkP*ny=ygW>2_J1th5q;pf;EG#pq z_6$V*^Sd3$V<9 zPy~1fw$m`) zjHMFMQJ!T=Qm>V1y^1!88_~)e)wi2_Jsx&g zko7BAs#I8WJ{*@!L4pEy#%0z@HCd6h80iyIoCmz}Y~}}=Rz}Cq80xTCPK$80mH z!>iDGcul6Kg}=gej<;$=ntK-Qt_BJR-Khsmov>>ANrNay*^FrTbEJ0O*lk@B+Ed0L z_6S^QayhqpWw}x36R$is>Yl=A(-1QQE)&b7s{#EE)}X*ojoYS!8JgTXSgR&ub@ZA% z+Qm!HS6XHHQMVBl=|}irqPi2YR8O-u+>B-FsZM;u`o((;t4RG66Y|K!I3Go!gCQBY z4ojt~@DIO=Vro^LQIn!txjk{295NUfbFeg(gO%0YiKP^<7+%$BEQO?GSUs@t#xIFQ zq8LjdnR1kK6P5-P*2k$43^NHziz%#ogf2E(w(9d~fVUY2k-(og29R zs&Ea8#rNZ@j;MzNxiTol zxzbCYAEg>)^P}#U_^2DJ1^4?_1I@gt=B*w`Mp&#UBh%dVxClrnttcljwPXd$r#k^l z<1V;YyPL7JxSN@D2+Ir{mdbFObAw&gx!hNA8C|n=9hREX-0k1@$`)wvQobPSE@15; z3EkF4q=a9`V!yN?%}Mggu3$HFzS6@EZ^bph-`mCMQgyHy_ohjxx>t5()SZv2@mbYd zotwe}m$)$M{(@$fHX1e3dx+V$R5Yc#97SbhDQ897=_M|Tx+e^+Sf*Kjr(rP)s4F4d z$Fa=J-#08J?uVh?o^jF0u-MdMUbthhS`nUh8)#Zl)tuWWJD9Wo*|5m^)1?Im6lb>Bi`$z^C| z+So?>k zI5&CeOQY^iG*cf2srH;pqfSdN@mg*h>9LeqFx+KWO4E#xm$A$UVT?tpk1{=Tq}`(^ z*1unhTY{w$oAI;_izNbU-;fmNcQ0`n^&f4*2Mdb!jE9lN{iFnq_MGk**+%U6fDgUN-&>Z#xmv6D*G!|=fF?a z+2djssfTlAd8;zg+?}{I(rD*FDQ@5KoEVJ7xVsfgBixSHhusK*CPPr+aN`L&EHoLA z=1#|@0Yb%S>@8m6jqCx@lszj5(=s_Dc5~3mJ;^I4#2sjgMTHrFA7W`5u+3eX;?|uQ z%Zc#rIo6^Xm$HOoo#(Aukmhd3rS5QpK|W)WseVFm1G*1OHyN`NI)KHTlC_wd(`4hv zdPdVM#L^9x+ZYr6HERWa;Rcz6^t9a`i|Z^xG35rO#4XPB_6+F8X`y^&)a@|EEP*u3 z)YJ%uow|Ke!XIJ{@>V_CC6Z;%nr24bi^Zg2My+0u68;OTpBmEX>y_OcbuXV98z=kb zrMQn_vBa6V=$z=KuZo6CvkBp?>X+uefJX;3~x?_>32rMH=qUU zdiWr&k->_dHIr}ng8}#vE|xQ@#JcLH7MMcN7sELR z3-`sL<<1oM zJ}i@p7J;vf4!r_oqv7QsqU4pkGg3krbo?LVF4D008Nr{ zDee|5wHy}rgo9X0hP0V7?MuzL33l`D3@r5zBe73PWIL8heWYE&^JAqXZn!H}PjBpy zG`9qo##6A9a399%6y(62-u)U&cWUMXz1ZZk*n+P9z7R`e#jIx=u(az6+B6)#oKkzM zxTp7!3!O1?M~bu1OWzoEpR$@+_K#a&LYRZ`D6Bz*4-Wh8-B@j~7*pS*CSaHiRjVt= zEZAzz_7XSgfm8aXsN3+$il*Y$H5^OJV#RQEZtxN}N8L}+(}E24J&+PH_e{JwEhswPSAlVZsH=d8U;(NbG}!;C8}NY)@b+z`FN`?=n}z^LMBzcq^&91 zEpCmvQ?4=vV!2zN5?O(znjI0bGhQTKMV_JoM23EbUS8k`Jq zhH>L-O?y_+iOn64rM8X)Wqs01+#Yqmwi<2Bq&)pPQ@4s<3XehQ7;OHp$EAkk?!$fk zX)N^=lb3lS#Zu!kC^?&4<)!cBNww8Ti%R^0rDB=8Sc_FAEmPg8SgLNYGCMbW zWv@oVn{N#^d#|R26K)H(sJMpWVgvbVnsbj=_FB~a3|loISDr>RT&<_^_(pPYO+r61 z$X`Pl8ThrhoxjBRo8M9tww1)&gKPBP{5ssBaVx(oaE*`o`PX%K+=L3hv+u0r=hfQm zCLow3Kg9L7BqN>g3WdhT64DnX5g#R^vJyUo!mgYu_qkgu4K8;DE{%8QBMUf2JFiLK zv~az9bpLE}W12e=mj(v+0!|+ru+069y@2zbm%cmdrmU$Lnj8{lVrl5mKWsMFR#>a) z`F&XG5e6|+ZT7wF(JHLhu|`%{r{7oMcTH*pV`zofTUcW%tTyXHp~)524OrtUtRMbn z4Zgo}ymeSdLRNdAa^@4UM#NGHZ^q(L(#AB`c`&vHXz2C8(%@uxv8kAgr9s0g@>^;I zL-jNdfJ#3QZ#Ksyn z0;^{bQfuW3EUlGhL-PUFV60$;4xjZ11qc@71-PU$4LN4N<)wcZb-Qdd>Cjq~W*(Lr z$h6%-ZpW>ra3*>VmZ_}vqIX)$bj$l#YL=iVky?+Lkfx7o?RO&x z>U7$hzPKE#BCxv&ON%NGfS7hu9ydJ@Y*O4uvCLgok03(ZD%Nfa(92rX2J6NOKb`UR zV5z9wbMdS5L`6H1!*Hzj_;D{`8@dq7R*HB}Vs*xk1(ZSE=t+}1yNB^9&SWp~3+_v3 zy0@Dn($`oTe~dWtY4=oYUg;&rs4;qTG`r$_p@a^+@YnQ_E)!LCSa*_^c2my9jg}>sqp+L{G#y-W`cVTmKu^-M=Fc0pIORY z#5%IfHFzmDS`=~!R?u#KMg#K0(%y(&2M=(oysVW$UlWhUrE;)-5T^{wj5lo>-n14s zEJjm}S1RhpzO6478+DF7m*CR4V!y*^-h`!DY<9m7?~LWDx%3y7YGPKJzOS0{QRitq zzQNK;M_waR_?w3GpQCP%*Gx~C9$b#q-Gtzw-fpZe-q=-X;o7fj)4?hicj4<=Go0mK z`7crT0J0gWs>+$WDhf|?@3a=1@^e!nRo^g8aAYCtjiR_gBkOzp!%_E1w01_LF%Dp< z!#MTOVIAI#O+wwvXL;$rMkDLddJv-GzTzH0>5am+l1bL_Efa_7$V8uwrKVx%?oUm? zhz1Y5{=lVd%tMMEyX}{SX647y#5B(kw^)m*$l>!Rul)C@JO1t1$Whkv}O#2OU%VMR7zwZS^liu+L1Bn;$vDRF0i z;EgJaCVW6!>bU1Vk4xb>5O8k)8B2rFEC{E57#o_T95?hsZ_mWD?ZVT!;!+5+ z3(3O@VutU-#aX{JExa!lHm>o0e^gDH<^27zO8dBiW(mKCYfzA4i!V$)Ob3j`QghYv zl5R{1FUJbX=$`y#Y?WXIiOc=cA647w=Dv)2HlfY>@E6ultl-8I9`cnsgHwC>R$PMu z*H^eq{;j``xe6;>n{e?Qg%)wXiIuoNuArRZ<+x0Hy@$($YyNF4+zebMgEU49oXjUy%neYX!wZE7Y(-S1;P$q)=r$KuQQT>e-Gmxf7` zVAy^kJ!XYF9bjZARNTS?{+s)BVT=B4Zx2+ye>6@(G!CO zmoDFpWxjo?|D##o%s%>jEEPB?V&rzL5m*(&$~|O5GirIXkoA)Z&4!37ti$5F6>cP- z;Zk>*oA#*(O(?Uy$i?b~A4TLg@EDd>S2N5GVsRtki=KKbTg-Gct7%a{@7+tTDaqH3_at#?1=N#BhE&@R|J@XbASoE z9%nz}Jaoj_{f`QD(GlnCN1P4+tOzjSh;z*m=l3}K*pmHK;k@*S^XVhbNXQBGGGPZD zab9=C`BsI~ZRqf)t2BfeXy;jrE*+2(x4`jNp2iG%#_{*SZrwQ24Vqr7+=X%es22F% z7U!>o-7)b_us#NlrQ*us{YIywzJ%J2I4t+Sr?~YKoM4dH)doxZ1+&{&g{6+iZ&gb8 zW31NRSRR$v;qU61(f!im28I1SElG0~N*6-1A7_Y^%L;~P{VGl{z^MzJmtiOZdzG5u{$R-3#wRp$Q1@p3lz%H2;HLOSlZHySMj&G`C!?K-YdR zk-yQ`>S6}dGgxPPV=wO#!J(}SJ9S3EISrgpUo3mx!Wta-X*>EY*13VD5z?366ew{* z^8ENFto~Ts_XelLebUfxl)^B$AkiNMyU!(>acssqIBG1+nH&PK{I;ls5bb zR=?oOyx(yt3X36I;x7C$p#xSGKcl_F(<@9B%}o8Z){6I6M>vecEbR>=9r!6jFBLNO zm&xH`DZ%05Ra~Y&xS56s$D38uljB=BiRn++V9AJ!Ci#21(byL!`HiB^yzn#l_VAlTolD$=lTD&j zhizx~ll@WMY3chCNqt`i=V2K4aTDq4P}{srEW7I}fpb#L}^h@qd`z zQo9O^zh9Vz#b4sF66z;M9z(5T zwnPK5bRRJ1uS>ABz>)*c{olbdcPFi)O*)u64P8U44#8rJ#kU=cap`VnHe%asD2`O? zIFMou#4mXK71yPs-{?GA;#z+4p`9e(OwCIPe~-nVJW{{plvt^?;_#PPK`0*FtW1g9 zkm8RzpMI&4%Dr2YE$*CDe-BFB6{&us!KC^UKB}{MTGW&G2LoU{gj|WGrHQ9;%!E&{)Ytf3o*Ic(WI(`7EG21nzaLpYh6vk> zbGirHk6~$XbG!SaM$j0WQM6@Z^FXq{U}^GUJ)RorVQRq|#JHG?HOk+6K5O?oIL&@j zd*zxvV^v7HGc^H&@7Hv1^KiB&Evh{(CGNeR{>qW$cj7rF(O{^DM_{!H9z9=)OWkVz zKKN-Y)xixq<%C|9{fe;co|!M_p1?}=#@?Cc{)|g;*hsOVJG-~PXB2~IWpBUHXz~s9 ziA@e2lg_nPunxORurwfoU3lEPef&maoX#aoK~2L@RY02rS7nYzVbX>iz^yj8{u@?& z_Fo|}8-yU83oVZfjs+MvLUCXe&{dg_$L4W}er-mr%_Xh^t~6%Aj$dP})3ij&A}foP z?A1W|F9Ev55wIM{-v30Iv|1O|QtnBXt@_!I0oelf|3kn?n2P?qC zK)f;V{X46Go2@QZhFdIewYpg0wpslNSOs|6+Rtbn>w3n}zhx!#JWxh2*zf`S$@85C zB`W7jRu;>C#oA)ouUh-RVa0ph#uF?1UDg(>KD*VBD&M=-Os^nF0-d}RGU3i+3fck1}VFLP>TE5PU0qcSVPejw(tOK??Y6@4 zZ-D&21G>bHzxOhyK}(rDR0uAy3w|@^-qm8dNJh@x2iZB%hp?7`Nq%#w!i zAs%Y|#c~d_JRH{49%b#(^5ha%ho@K@HX}6K3YGZ;0+v|)e~-;l^Zzs>mARA;&A|n> z0%EoFLTgv>n12?IVmBw^I&}5!Bi3IW#@+%;+G_Q`vA=4Pdi_c#5;Wj8!f5C|X~T+@ z#h8B-Rr+0Pe_;LL0mv*IM}!Jn5k9i|(O6y|^CA93AO6^dPKy#n z`%>mVaZ_xUO3JI6D*Jz7rE@&tYQT+cc(LN2XzimgK7Nx-Ct9Lua;gn?G(HahHa5Ms zHk?@bcCfZs&J=5lm47O%a9yk}R)6)dHhePX--IAQ9|EXD2EmU1%_43@8hk@B`4<|l zkAK1P8e#qa9V^I4J~R#{+VKB|%``h&0L7imhYFYltKw5_f=6Rbf_xiprVV#AR>#c2 zU+pk2j{Ft2)J701z(Q+_mGL5L|2tMe7ZXlFm)LkqEnh2;FGtb2@SUqj>f@0$NGzyjTTTVC~AR zc#Ez7HP-(c-6xdcGV5`@^$;r|&+-jcugogIjp*_!v;O~%mEKAlPOJ@I^YvD!%nG;x zUHp*z{kb!oEH>w>uCudutBoaAF&?-41guz3T7R*ePg`3o|7WZ%)&PCo+W!HYQ}%xl zkYtaZunPQ!&9E{%{?1(Lr=$Bm>n&D!KeD!1(Lb^LnbrRtYb8HGIHmK04PTj+-cMGC z2L#LMA65`6;-9d_Nj$?=c7lfQ|Bd~z*Ryle_|!}26s?wxCe}nc!RiexH?;m@m8+4p zkH$)`vGo^g=hed6V)>t*U{~9g2=Ys|9%sqm5-X!N)~?K|ZwGWWMXC+g*@hDNE#;(lDW(2z0aSW{DjI-gy z@*i*Y46BP3J_}a0rdgh0{g1+Ch0L=7j>g)dU4*|foMXAzhW~F^+lIw9{xz1DB$%CK zXo*cwtQvUM7OUpVt$j3>zi<7;n(=qSYJq#Kel%9RwI>olHM`gHeKtbC{>}oYslRSH zx5U={RCSeIB8>|kxN!li`m z-MN$XI2x+}U2KGImb=5!&w-UuFKhRO`4<|*hYB_nRz|}ukAPKyQLwI2s<8r$u^tm( z$6vL=E)tU^``a*sNs@!9t1>HgF1k41`d4NZZ>H77a?a*M;pbRgtZ>DaFSdM%^@q(Q zm7su^TAphIh?QW8)l01|mVTMlFSmMSZi@fyR;LtN<^; z+GYF$*7d)}s@eZ)2BfcweGO}5eP{EFadSCp;_;{TsLYb||0c!zt1e=ws9~yMs;8>M z>VX;>j{ky{pWdpaORVs9to@&`rq+ozJZy$aB|+&{4)7n_YLL@y!v8s&{Qs+ny1}&} zBeg_(SYuNE0hRPowg6(;6RmwTmjAS1O_jq26ss$yTU#tU2Ub((T3xK3EVMiaR=8rz z7sI;5(l4>LSoWosOXlKG!YYV7O09hvtn1&gYH+oUx7dakE1hesEmrzVVHMc3{x=vt zA+#Ka5?Tf8636>XE_PbD!K{|-FImMNBC7g}4ag3h+KSn1D^t??&^A{5&IID>D#d&80j zN#Lr?O7MK3c>m3}-UJWA2Q7+Qk5P{H^|!(u`}UhQQ2QMF_S=l`W8Z#jR&X8r_WRhk z-)1BP`zM@7*zPEf2>&YJf39nhFXcmb8GY-mORTl2;#+U4FFf|`H?4BCZ@txO($!GM zzWr8f1mA*d3)4gU5yL0P92Kkp$G-hGTd`x`ejoex``EYN!O{?X8?LpXnQlXW<5P|Z zT3AlD0V?ycZ@+^!8g84WGV8QG%Iab{kA3_7@4od`Q_5d=_La8f#K*q<{`^dkeOs;v(#O92rV);P`#pgT-LY@KgKxw2u;tjd-^afF)^?oh z*tg%uzWp{M;lKHIT#LxDZ@-Uy`+e-&@1uVEtv?E>`1X5Y`D$lV`Rcfz;`|!-#|`uw z-W6BF&%_n?W1Roc{c$7w9a8E)fO0U-pZEaEoV!t;lk!WPU*|!T)9*o<^&raOIR9xW z?@DRD9_6<-X4*F!FwcyEY31RAk2pc8T_MOcL4c8-NZbqoigxwOF_(_i=q&|Xh#p4J~ z{aq6FOX#o-A<3V=4PnJbgij@$;}zD_tPcpkg)9;gbu#@EW(_}5oSD#km7HVaQZfcCeI;s^0S{qcvr$s32A=f^9YNc zK$!bHLRbGq38_yaB)@*Az|b*2zVi}L)#qI`eIyUxT$e_*Z>M%q#tUqJ@5^e?W`; zWumM6FGN@SJ@!G1{W8%t{sGYvzyC+jQh&ARTK}-p_LU;LBLH?nSsPH#mQsI02PG6y~@t29#`d^6d^?Q5`-RGBy z*7*lS_xt_7fgbQziyrh3i`M%?zJ)gUYef(F&Uetmemdmu_?%3(eMcr6efN8WIr|Z2 ze2=in-y-4kFA$m>K-l7EA3%6l!cGZ~`H4RuEcy~*?hgpt{1+vpeua?yBf^t@@s9}m zCG3^3-Ea95!iujEmi&b9j9)IH-!}+d4VcTB%U^pKq2UiisqrgO z-t^OdrCHwcH;8uo?r+fBeun5Be~ai{zxMA?xt}fC<8K$e=O_LFz3qC@4tlLr#dLfF3Ml={>3iJekprVxY@U? zM*UXAAuOqe5bu{u=ogRBwK_uBzp8rtg-#WJpQx(e={P9jFB7@`7ouu@j~Y;QzYOvt zRfzgW4WicY`yY?6S;GCtBh>T{OPE>}VQfu=+Wy*_2n{0$HEJQ$_0wx1?2xccLVe$@ zjWEYW*tm`kYv5-{IK3LebF~SP=+~};@UDbebr2f++a)Zjj?la=LKA;xU4+!*5Ozyw z>L=Ah*e~IVdI(AWE(t4YAatmYaEd>_K0?3a5k8gB+;4jV!XXLEPe5ql?~|~mCPME9 z2rd0(4G>1wLO3YlOut7%gh*|KyBZ=S`v)X!mT*BLLTi6@BEr-<2;oKuZT%sQ5E|A+ z*eIdB?=(i(AtAFdLI;0?ggNyP>Ys>^;%A(QaC&`&=OlFUYd1l7SHi3&2xMdwAC6Z11BO%HYD?^loClrc2E#NmIGNbuL65+4a4uEp)Q z(x2M2@09qg`1)%J&sMl}Qcm_+(+bUBhyJu_Y>Rl`3AZ?veEeO7@g;7r(|ANlu#ubQ zw~Qa})HsLVy(#N+;aYx=?(rW6xxId7e8f4!pFb_WbzmRYDn3%<*Rzfk^T$m|t>W_> z=afy$lH(tAYK(3j{Jy*NlFt17v45afd~5&G)|5CYO<9v}G)U(av=dI_B~ko(GN^85 z;lx?lIg>+EyKEXaH2w)w*XzzD=GtETg|cF9QcSl2jl)mwN_YEn+r_sC=k}*8YM$zG zfp=l%jM-|AQ~d2`$KUEauqmTM{P-$Ptxen0;x9>XayNCQYVk<}`DxmupI5Upy+hfj9xVSkp|e*tatnZ$F#q4J;xOE`@R(P?dz%XrrKlTqv4>A-Or65 zX-a=2WDWkm`NA0)yiMsrGB%lP-IR2G{P?)U+xgQ_eiITjN31&<@N%T%j#NH3FTaSf z5$d;T?9lj+JqcU{%tMe2M6sNu513|`ZG2$Ca#SS zuW!bGNbhH~i2qz+t_e~d*uv4*rKK70DJoUtpp|O;ANpf~UTw;p{0t4^7th|bv>?8t zQ=>ZX&QTxNgPW-M*9HwbxQJ3c!F$~5D$%M=P$z%ttoYl)^>|BL^@?Jw*>v+o@eQ{4 zd`{eSX@`WvC#Z1k+!Q@R;fHj6{E|TlT?Yn6=+D2*CF>#k#jpNmTvyE2gw**`*TXi9 zz8luBnRGqkJLe|UE!k+j^p^|`0*_GWQLE|EpMJHcYm?RV2ieUeaBa4lvThzIygbHg z`iW^Pt8KNKzG!J@wa1KB61=>pgBA4~Yki5Wa(A@aHmj-JQLE`U*eaZU$K2g&&!X`! z_=!>vtG!_3vh?uABXjMrT5Zf;_NPLj7p+(aagS2wddX^aaldD^m#xM!6#BqwuUM@< z+DBH~iKY%R%?k{Z6>|0itE`r2<8rqT-DNesL_p~c08ON+{hL@( zi+iFC*wiLC2(6CQnpy2!wCZSD{gSM99&X;G9B3z7?R>OGHts1_({E*5tDTA#{Pcea zVr?s)W&;jIn+bHau-Y)(V*-WgX0_qiYB61U1A=OI0Z^^A#GYxj5xDj1FI~wt?uDxV z=T_8f5>$qfU_Y9c)7Dl?$6b|4tff=0Pf$3$B;z_8x2@Giqv;1+y4sJ1vaL2AP48Ve4c7Y^l<@>G#V%5vtd@Z`-fDVpgThS&?W~q& zwMl6DjkqqQ>!|-HgV;L-^il_n{!Fk2w^pm}3J6aDdK-hT9#+f3JrcJTtDaVyihHyT zcaGJv(KJ?c^@7zh(?E&dJ)onD?xz+kxZ3bF>s|~PPE?PaS4YXPw z+9lLTi`pQo<>S`tWmwco%v&iCG}xvhYE?VW1}wlm4NWW9`Bp2$JpoNCSnvu9xClhi zv{((X;b!6Pgr;k#)n?=FY_(y5M*Clc_=ehpYq$+K2X_q{@B*t9qwS(Ow1TM{)G`+X zy+%*hg;u)+_k(CrSY0FUOTle6k94ceMY~n=uRD%Wh#D93zzf9a0qe~gT4*#z-bU*U zXWPi7xDTWCf%S$BoT2&PJF88%+GS|pSS<%lWw;#Z9aCDYN^%ih91Fl7R=mgtyaMf4 z#o*E{Q<+=|c!hPaf?aI2g=oCXI?ygbQ^PF+yl7c(X%5Y^+Euvq^9(IQ^U+RF-LA%% zh^Wg)RDO%Wg=kus%FyI}4YCsUpjPmgWnj^83Nfsa$Mt{}Z^5mm)AgX$ZpE!yO@`N7?Ka$ZSZ#yVR-Us!PVQvTQ zacdEJ#D=>AH_NfcHm}>Y;+?p4!_f7p)$YRmfl}exWVO3--)XhYXmZ{IG$S;Fw%TxO zaBD_Ld(3KUacf3Mdt9%6QRI7pe%qky2^;V}+?QJINvo|xn`^bFtad+|GS;-(ZnXz+ zD-&r?qbbUR;4d5t;Ad^P^{T(ae9=_nO)5da4Y;=fjoKG%z=z}yG-`KP?P1)10u9<1 zt@a3R4N48hm#nrCw+5iJm#y|F?%s@rp#5J#R0%hMJUc*MwE;Jy-G%!$_%*9-!JUD7 zHT=5Ow&I?MTh}gF>1i5Hw%VIEoTgzWZpD2o_Ua_nc8U$S8&>2efJXoA@H;TA8F~`v zcCEqluGOBx{h1~=pQz+ znqJMSg6^~0^SITl(mt}<3%Hk&hzjsAnljk|z5}{Gv*BLEJwo}`2cIJ<<3oLLaNRu0 z|13Y@%arxLGTc`58MxUF+xdb1r8lebrjXnQ%B7k!C62@%rk(Fm1hE- z8g)u+4o(H9fF|H%&QSch(%v2~`_8TvCnJTc)+zT;{;F`;p~o}BCj zdRp=iphrD=_n#gE>ABQ%;8~#OOnN4zhgy1w^(xRarRRa3OX-=DUN-m?*bY|tcTG$f z=&rnP8gU$fKRT&O)=nC@>m~0b{{<|E|diO-r;_ zO9#C{AJ7+QpFIF*E36~1PQ1slX6b#o4}({*cY@c!tKc=T32X*iz*g`WcpPj4Pk<-E zQ(yuZ4{iagv|5kAF$`P=E(ceDE5Smr2qe;r4S*2`>v22atz&*(U-H(l#(sU6^MNbx#oe3Ko-#P`FAGC zUm%3r0pmdvFcPGLL~sJA1Jc0p;1J>4z->W0&>rYGtsRkeK+kH5KLNIZRL}`52RDN2 z!FAvsFb9kP7lL#!3XBFx;6!j5XbMgNr-J6-WY8Ei0<}PWP!H4rH33hvLM4Ck5yEgl z9MEGgJ;~IQOT907y?}cwcnp+*C15Ggn^R8(CEzkp406CQ&=qt8JwYd+Q|xKr8Pa;2#%a2tL_pb#VxrWrUHGzBMt zPY9#);B+tz8UkN2m+v3ZkF~7z=dn)0ysc&=P2? zv`+P(&~chgSuZmK2I-?~6 zoy%GSoyATEErHHpIiNaWj{{XeRS*F#NC0{#bSmfsI)gMYUm1XDU@FkDEgmF*x`3Ao zmIQ|golLfar$J|s27FKkZUQ%hTfnX0HZUGc0B3`~U?AuP27p%JOmG%x4dQ`bO|F-E z>#(|wad87!4wl9DHE+}zkI@hG2O9~blZxKHy%*>#r#E%K3qGXJ9|Ie~Ca@XkTsO!6 zBRio%iQZhk0+fMXc%1`!0{vePI-OkxUk>yLL5~L(f+xXd@H_YeIQV}Je+51PpMuZ8 z2jD~S4=|qwp9YF)#7T6_M8M&wB-9BuP(AaMuIHQ+z!(q(9rWGQ z>m*zi<5dFa*`xj&jQ2q~SPvcqw-V+#SdR^NfDzdG-wQs&t;dGDfu2ts0D2hm3kWG) zkO02K*0YK@+)c22|R%U?>;^MuQ81j{EWOV0Z`^1ay$r z!>;bMMmM0iH_)PbU0OSk1WpACdp?kVHZ3{8x(&x;;8Cy@{HM*R#99$v zC72(m#D$OV^zd0-Zp z3uc39AP-ywrh_>kALM{_w1}Q(sf9{Q_;?-TDXZZq;0%xnG%h-VWbg^KUklcNl7DW(8xgMt^ML$fO{+}9G+7n! z6p23%{sOUr4j}XMf!<6fZ8{l=H8@q6EbLfiVwK=OdFUHF%DIe;7Jw_jI1(7I#E2A2 zyt4oI=p*qT4R&Zx$+d1y@HD4H+e946A7Aq=Js1J!l6snA^f<0PZiF7SBw$zfOs^Z!J)c1KMj=0}-I+ zYXnXK+VUlU*cPxR?${Pk3&e@w7t(3`|5f+hVO1Po|J>_d1eK<=%c2x}RNAG8G_e;% zL5UcHB^pcY8eT&NC27J$D${=5#r^Yo;mrr=kmX4>%s4l1u zh|eaSLRr492U>x~dmv5bCDjcV?w~{fb|b?F*WMsM5W9IeYrmkcQ*F8B!OJvx*K+#hQ=K%-5_q0R46RXw-DU9p6askj4HtL$(7Pwu62LG3QlCmxGppxQ3>vSq1G| ziTf)^Q<1JHk-rVsIiPi*HOh1Lv(wmot;U13p!J}Qpba42NM<9=0&N9t0&NEQqfiD? z-u0#<$tcE zx(d1ix(vDmx(K=eIuAMrdI)0Q=_XRNLpqc72d*E0?t|`v?tpHC3PAawTcBpZa=ClB z=Da7M#~|hxTasZR9=rm*1ib(~2R#EZhNH7JkxoF(aUhP^@^tu!d=ASLBmDq+5BdW7 z3@QS>1APL$0daZ8>v40{ICC%u4;l1U0WgS3f6ol{*ZRDgYMM1eu#IJ=+&hj9aUM6W zJMOuG`o`%iV;*cC^;o{edxsv45K<1N*aFXi72X4~_sSE8qrRcIZU|}w%I6p({(Tcbza|LzVgjx$ zG1%h*%N~wg;M-2Ent&(fc(Rlx%oeoxW@s@Ikw+S$imQ6%`tsj48V9LW9&Vm)zCM`3 zbQ%C3j!iM6E$PAUN4+ULtyX!td3w0%Bz{J7GQ1Vhdzs+di+@H&GLJW_9&RlQZhI9j#V*yZK2q6;k*4 zDD|G^b0W|&PVk8dCwAny0F8F0*acwKg;az#4Iq(|_vAx@&WCpo6~H*C_nDq!r~Xt; zt?J_C2@!irMz=h2p7i`K>PFz+CdjGp=HcdnsYVta8ZEvB+~d`rECSTDMRVcfr+H$3(?jSG(<%9Z}bcWeNwPzutVi*7oTeo zaQNG%sN55kdt+TejumoRUVqtYFk#PaddY?a8`X+P6%wHuhrlN$P$_u&s})tKi7$HPJSFxBsoZe}JPm^b0u;ki(ND zIzKU&lT#9ot^%BZ=NKW zkeH6F;w(v95ABeTP5Vuknj%RugcdJB6-rGRbQ*U)rMIZ`D&)>!N(Z1RdVXuDA37i& z$5^qbx&---eBl_CF11`y$)()G1RBIWd=H!m+}QY(nUO_KI}A8QRR3l5|5Bk`lOlS3 zGyh8g>r4H$kH@LgGR&4~)P03uSJ}g8Ic6u@jae}R`U-(}f+1@!KPab_gzi*0fq zIZWBv58Pqx!Q4o0fS-@iZ3WV;WsmZ%zeQaIL#{p_GqH%jVT%HmC7+Q zt;sVLMct@%DteDE=E}p|c~HR`JPf3hso)Vps+G7qM}0Udqly}wBCmR(?S}9Z(w^o+TQ}_KYhng?czCrcg5D)ski}IM;E_#eaJW@qA`?@(j zM(I z@U+GFX<=lEWpB$W!9^_HN~O>PXWs+k7(4*Gmd(9+Lof&)H6PT-v9w3c($&<(!ZLhsUq2|k@`%ObfL z-Yo5LLV>r^6NscIa@bzfdU5mFFuUhD$nlj|xPi10!y=9XfK_>SWZwhoFXv_hfOfDI zRmN>HePY~f;8=F67Nk7UICl$`o6J&QLhftPLvI?#NmH`f^F-D>ag+jZsy`|G!obPS21b*~Wdj%`(5>5oT^SFf#iYu_ z{TdpC$39so$4k%s=dEvt*N*CID0e`~$=-0e{^YUF2MsxSvSa4UfoeaMt=y9k-y6ji_7;0FPLD&oy0EcKfu}0H}%_ z9;%`)<+iQYV(x<&Fkz%lEPqiVRuRC>1fOb09X>EGeRea2QH72L?ta)S@by_v*Zu}EXxaa zlfL~)_m-U)o}cK$B8tsG6&3ts4xbO!jd9%);Usa808?m72C67s0i<^8#5M4QSz=|n zYG0kV*Z|)f!zG!#9BP{hf!NZdO!Rg?<*|N9iR9SXl4i3oSL2W2wj`JHf(===*O<`u z&5(nvo;ih^1wkcN*UE#I=>FZz8d*X9)~etjXP6koipXp$YLLi**)@MB@a~{KFB%2ZRe`>u8w@o@hzQm{ZpGU1KNXr(KWl*E z3+XH{uS<0}384a|V0-F{2V!p&v_`@GMup95JXAL{6dXhDb>!wG&_;%)D$pNni%cz? ztlt`-IaI*RbLkT&w?JYi*sSJENtzDl$_(q8?#0j|LAMTF`cOU>cFjH>4qv}X8J1~fHXKD5hVIqFu11qhq zfFzfxsJ#_0RIBCdk7iM@0wK)ibH+~l;@CHiSh0Ua_UVTef zl+xAV|1z@D@bqqO-&R(4C-v>xO8ddfsPx@wLF_7(`uxlpuLjZI_`z}a-(>@yGt>=UoJ~~`0jgJk2`v~SLmb6 zPKVMPPlIb|Y^eCMprIK@1P3y&s&S_m`-Ers6`O+n;5LyyaZ-i4SA#9WFwY>D!+4+! zAW=j;RQ-&`9f10;=pftMZwm^&H#T#dFSi@3j?qTS1OUIHlFP{<@~n<{b4QEDCs5uNo@b{!R5^b(UoHd=aHTjQYeqIz&K#d#)*NyTsPbjj@wzhyi& zZ*E@RMr)`$0IJs%5(w#I#r;gGTs$zQbS_vaMm7LVM>SfsV_#D-)|4VnowrdE4LE_`N{f(ARP~T&S=OtJ z=ks>hzC^9cUdEE1aTU%0u(GW;i=Q~PprgA4kb*=WO3~5U`yo10N2sjcaSx%OlaN+> z1yDOFqqci}6^tl&OAgo%G~^`Aq_o512_aU1GM>Y4Xh~X&ZJ)CH>n%>`EvrRf#Wz(a z$JF(Z=LMW5#dCEkteoeBH|=*N%eL{4hzyM zs^jX_E_S!19LeGBO}owsZ7N+KEHBr0hGu;>?iw>03prIj58H8>_MI2B^-3S`HbdlC znEB|9u4Oyz`V9*`O*t_Mrk^z0RIkLfexiigX7&BrHS2EJXtkIfcBj68yfb)b55 zr!^-Eccre!lynJt^O_!9LRZU>cp0oLN6FSAA*p$vm*P519KjQcY{gIVw`Ib8vVAISfTK1WNxUO`a54(&jW=sj8<_o7R!)J;2_ zlB228W@`sMW56*0*#51^EH3wH^u^YaVo0sKPF=6VGYY(l1xdMHc@>ItQVPG zLo$d$ub~CKs59R+r3Ai{;rgU0-M~Zf`dE2|uHkxn<=)jn&@jDcF^H^C6IQ)C*TF+B zEQVkXvBqXkUB0d9plPdRIQncfh~@$(z8)#hl(r+jS?ZIQj@YVX;bEktpfm?bJ~6*E za=(GOQMv-(FV*Rerg12$`b2aC!#a-c-4Jy3_}CRI-m&!H?L9jLI-_0>IZXb~^|y$c z-ozYgLA`GZZDLDr!vDo@EPY4dFh$-9vID$=dm2`N0nV5%YrroLPtBe+H}el^fF+wXlJ*s#vJZ5P6Zx$ImA@@i_L&(kuRgt2 zkIgx=^BzYZc){@087)B$4_k{>12dME$&2~z&pqYPZPZfBErNvx*2I9`XX{F%oe{qP&)MNMD*)*D_xgt<=dFa=H%yp9ElOeWyyk*6iI<>_(*cA*5wN z?eD{KC(#bzuzk94AF|s)%K}-O$EU=va=+Vun_=CRa9aF!S{+OD zH-M}j3KPUhB%9kUM;AYKpWC$x;J%2qWBe5EGw8@e;i1ZfGQnMzOC`GbNH7-bE|hKI zBWYa-&#R5R#f>38d8(|o`C5i>c`1VT8f80`(e#k*IGQ; zn)>~tG6eD<=etU|V zuF|fjfWKHGFL?Xk*L|OU^yvzY)956)F}(l)eJ@{#q!D%JH=A83gzv^uJ=}?lQgA*1 z&AhO=&+Ofc9|jA5n)Ym($+*jO>lu>ww2$v9&^08Y>r#2Q|1mza>iBa>!wpr|Ckw!R z!T{j6Y|o-^%r|e9WoH2NLXJIh9K{du_jDE)4LRc}21UgL05~o&cy;i$iDMowH2_vp zA~$6rt$&8zD-DyI`7iyDJF4%tA_PSwih$&IzCI>tvenwIS-w&@mX^r_gWUn-&Zp0L zPUS_fJJa&@(tA>lH0e6fXBO&evU`CxIaBKw*v(xEkhQVSh18*W{WgEE#*6w9FN6Tm zX080HXNR?I#h8Soi2{^DdO?cN{YjJ*!vJtXMG=b%3mY!W`(gm}Bh^b(^c#st#5D@8 z{_`?Wxci~iP2Mzaa?k)MyH0i&L&`?<8anM*PeYC~En(h4 z0I*6}+|Ki?Ta;U50Cb|fm#`In>9RCdJRV)==kH(1wgLe%obe$icw#=6%gPhE#LI3D z17lZ^l_3|kYwNb9@%tN|5F{cc{O)284PYluHiWe76Ps1!4Mtwcn2f@ zh%(=y)O*TBA{uAQ-0y`Ku05MlV5IDEu+ghT#WK9jd%#~&@As%gIUayT(KsjTz2K)( zW#v5mAe2$5)b!#ba7k4D6WEsDDYI1vN4qv?V=uj8m0N93AprPP2Y}7({O!BKvK>vs zAz5X8)+sqjwW^%k;k4CFlDVW&p)?ak@t!H|6IR4&RJ%wD^Q|w!!%yV-1<41piohZg zP0!2_?tm#ZrG$2J*hxazQbL5r%UC*?vVg{XMv-MS|1)}43%@;!L_%59)3zErs$!ur zksoAX$&;#SN2+3!$s!SnSb9^xqqYp_yI(f%_pAEdOx<}pRZ>uCCnxuXl8dpZlszCX z4;@yI-c)65Ee?z*O4N?>iZNtC^PMzWan3;*X7XF(vbR!K@Y@bW6PCvZg`yReCJN2LYt16Lv&y!~2h8`s|OM zw@R&=jVBx~h*4aT%B}@f_nNx?jxyNh@ydAu2v&ujoeu0zu~?>2t8(y!%|2eIs?pd& z-16qev)qfv-!!up)T*m^VvQ%;DHH(ca%aYsUd3=q0KkV&X>zYi92oMK&tH^YbRgZ} zDn`*ewWf{e-dwh3&kv3poP6oTIrKs~ax{gymO&M>j>~`+yT30p_*gf2;|~`>{?3Ef zjlXR;VD5-EqNunAMJobu*)+A#swfI_kY+9b?oX> zf%BG^ra~Gg09Tia>q}C}ssz-B<&}<99$01{ zP$^>S>4N#~Iqx8$2xfFzqiKV46qStumz#yXD5}un zhlTrbqOht?OAQdQ5CUPzX4e)vyIzfdEOC^UfeZAMad#-7ERr9|g%kO%?Js$8Dmr1J)EZBqC)Q_4+mOk@#j8VqbbmET`16n1dSu;F+;9YUR45 z-0$!r1yY8N;dnE>;L7(?d7Lr(+ItPG{XAFY<7py)dd)RPoqJMk^dL*T--72ZtvvsF zVol2A(;C-IFxT&qg(>P(-lwNs#EDL@{J5Y+fYrg(2h=JK#b6;eIzlnPiLU^t3qW+_ z&nFL$J9AEu-gTkvMoyH-j9Sxr#*Ms$^O?X+*>Y%Y+X+vC47k;F%M?-=bxoe0JEA( zQ>|5p@q`EYA=1i73p>rq-ulPZ#V86ZS0A%*9DPPnvCnl`TUS(jI9sO^ITV5yuB>0O z98^20b$JM<1;ru}tKXF8#h|Q}=U0c_egilwH)h>vI?1?yiLuXpkDunpa+CuHH6XbK$l;!j_$j>awzYmQ4LK`r(I%8tZ@NW+)*5@q9SYLo^OO@W zf3?48Kpwe8gMm<=zeNKbklwpR9#*LJElTi=yAbo;v@PqWVJ7KoHO-fGyT+l*ttO2< zfX$3PN6e@3T-IGdm>)~-=-DR=VNg9H6ggJlI^e3!0OyB4bT#Be=FSLJy4K`f zFDXJT3+^0pcnz5Iqsy?1XKN%Gc>Ix1n<}H0Pf9boJL=5(7=LrbfG{thGvKbSRzPv~ zNZku)mQ9KKp#|h-r}5GcpJVCb(zmw+rxb08lBEyte?6@KQoGXAzxRWlTWcKjjn`*V zu#LvSvG*N$E$w@3YmLndKNlHfQlbYe3*X^D@>;n4-k@OP{Hwg$C`LU_$!WFR%hqLc z!=I4@^X!Jxr}1~_x{W5x=d^+_kGM;3lG8ar&DIN3>?(3Za2+wB>HOMr=W$tu>o$t9 z)#w}(@5&am!-J(!-8Zk1H|K!BVBDh(wiwpZ5z1`S_xR6Y{o8Qr^J$))#`_;)Dzf{E z>{{9X^P!$SZ7z}NSo-Yv%3zgL6@9CiEuQys{O2m;=_|i~()aT}tB~FzD1+;G?V&uK zj5^QGT(&!Z5X8@GE8O*`4{0ZCha>-Ff+YqhdT2uArN+jV5(3i~Pan~92dH-TBdR89 z!j$9Ae`~gv{$5hIuihvf{1d4M{rOz!-hVGjxh}m_^nET(-ij>#EadEfl}j-IdLDXA zMiosT^;Z~4)?(%}>f;1~L_McuCs>az&neqU6DD?fF1w>YFI&1IW!aK@5Fy+g-ndFf zs49_%v&IKXrv3c<|R>$N<}@jd5d?!0=8-xIO3 zho!uclC!7o;;R8s_N|n%SneWUQ=kjF8}ph5BXvv#Qu08$Jt_V;yF2!s;2~|B9p2Dx z7wA&AH?px2qP;qtG+uWI2=*w@!p(2!CG%MFR$dp&Eh)GpN=bstHqj zy{1{N;C1Jn+^4B!Yp1kH-JB-13lSGMzwdMQyJ~*=^R;`)^8}^5g#RxO6NtZekSqPE zv-@{=eO8UFr6fnAKhGDm#xaBcbiRP&r+ob6Kbrb zS~}RK#h-z~sWu5(%E30UlMc3NeGG4c0M1FtaB)zv&KZD{zw zhxkUNl5Dc*T4rg)GH*60m?J)rsQeDVSEE)*JLFm0%^oaDU1p_B4lJ7a$l(ZTC!6-k zMKi`%k|r1q+j@AtS5sj8E^+o>;%l+VlZ9F)RX{I0g1C*X48n}S0$>=D&(b-d7PvBOA2&e*HL zAg7zCBt2W}KYwtf_9ep5`tPs~n9x{HNcjp79Obz3Xc|?Wv*x4$@!W(mfbccJPn+>b zy=WO8v#vtOBm=@3IlR}Y?6CCV`W?KgV0pY$CCJt*e&4B2y?l@^)| zG2|GVlcNqTb2XRi{ibD0ZKY=$))){W=G2Z6U4d{0j|-d1SpSeeuBrhMYfh7OnmETO z#AA5OPUqFxyDQX}4;kac2}d=;E0MD|6fp*$g;xZk)rR7=4{JTGVED++hTIV*Q7b@v zk>(kK^I6NhHU0m&*6?R`UqA5m|G`>A`F?P3t65W#AJ0rIdh7uj4#4R*=dwV2J@9LO zY*kH%_HcAJD~DB4Ke?MAhc(svO!IYBbP;%iiG8(XOJb~Pe0_K^vJfewJ{Fro%7uJI z7kr=3liPI9QnxL6Q(#{B6GY5yBRNi`u4hAEf-%~`09paKae2RvxlzIVxfUxTUX%Tm zyJHty{CySx-3Dh5c^cL027pSSbBHY^`-9bFAb7Gp_qw}nxL;#F_n{z?ZRrdUYK5ia z_@S~iT-B}(W^WeoL6d&Nl4(m-8o<^~$8Qa=I6AF)e5A?p6C)H}Fe3r>)E@}-RC`*+ zNE@x(Q_EMAEbVFx@&S^)Zz!XSmI@nSy7&UYq0V&|qSqac&-hhBz?R^55s<^3kKXY8 zOPBtU9K6LEz!r5G4sQfNwDJ)?>KCB#6SIM4``f;U`NcZPU2>F~fR>KqX?+{xhZ1;R zl)v(Nesp&EA%=?bk;ArR$H+$!mz#YKQHo+bnrNv)AQYq&=0HeI(E64RD1Bt~a+hUh zPkRG3-j0#4<=LC^>yE~2KAYok$ap1=Tu_-TgCN>xm8nUPChY6Zs1(%MRfRSLVaT6V zmPI?(IA(Fsj8zCq=m#?OHRXecdWsXdLC^F@9f-OIOW_?p@t|(*Oc}`ZEnQpNJIkwd zK=zb+cb*T%B8-5X^hR1yV6pV+Ax{f+4`&JsL9f!BDJ}#`nBh!|aPM0L*6eEkv1Yo( z#f!#xO)q_!fG5)5K0>O#G$f8fz3M3Ah_O%_te-vP-4Jse6|`#z#!8E%hm?#Q-|?>U zGGJx%OV6~iHRR;hq@AG<FHYF!)(ewrlyS*J};C{3g znKyQG>=BXSGW$`X0~J3SXQENocImI^L-xo1k8I#zohdp6CxIio5k!LD-O4 z6HVpVtM~;lDRgFS?bw-2aa8Rjo|vJ1q4i{E&}GJxow}Fb;&T*zP7mbpI31`^6jPk! zbl8wH2|2vP_gvMZ)?kkxYz#RolpIZ3dQq#Y7oRFQEX;k#;-MSTbBuj*xy)=Si}p3q zO!f7|4`i{jC*2OaJ>T~PTS*=X*uVzJ;gw>r@2tScg;NoE)KB4N9yGow4m z#e=pt*LYD%bB%-apIUjs%nF->X$gc4wQZsC|5~-XTLAel4d>B7JJ9e7EhYWr??5TI zrDmezzmCv#pdE*z^*j#6uJMDDBA?)x4`zZNuVYGwxsBhn(kxPM_olHkxT4ND9i(g-1KJza0Dzj=j{s=Q`34fWbMDf+PeQ9iK$n}XIWuSoivmYJj`||$u z1^12v{ADqQl->1le?fXjb~_|%Z4~EEr@~NTray%tbxZ}4r?*ARqutD|?_Hx-EyNRE zJ-7N(93%JplVh9zf+vC|rSg(_c>U#=6TYz!H5I8_8;z@DUHs@O54&abxzRQ@6;~n_ zfnnf*NcE?bHt3mkAf4sZDUgiAk$w|M4Z<~XD(R@L8$AryIN`*-XeK(MT+iJYT zyMgjtn={KHv`MCP3Qif_-W1;!&hOkHS`A={=#!JIkA#-H$|cvnT2Joq3x^a&^vCdfK*}G;bF6eEhx+&YhxTYh47 zF94K~{Yd^DXZ(8~NE@OwO(GtQm7{s_`aQT;rXB93ZT_VWJKOb|(Z4E%eya(wDw-}oo?PGOgleSumo!TJ zR^#M3{3-?k+>ff#7ge6KV!p6A)Bex2icH4k;PZz$)FI+@oX!sest~&lfF9SGk=S&5q7l}HalA@NET9q$;K=zitVUb zq3V+360Lc1GbbU)_+CXCbXDU@i~NnN@Jw$iv-rP&WI-_*`NI4?taetfbqO-&H0Q>|6T>;4Cpx!6en diff --git a/test/integration/jsdom/jsdom.test.ts b/test/integration/jsdom/jsdom.test.ts new file mode 100644 index 0000000000..b816e33d73 --- /dev/null +++ b/test/integration/jsdom/jsdom.test.ts @@ -0,0 +1,14 @@ +import { test, expect, describe } from "bun:test"; +import { JSDOM } from "jsdom"; + +describe("jsdom", () => { + for (const runScripts of ["dangerously", "outside-only", undefined]) { + test(`runScripts: ${runScripts}`, () => { + const dom = new JSDOM(`

Hello World!

`, { + url: "https://example.com", + runScripts, + }); + expect(dom.window.document.querySelector("h1").textContent).toBe("Hello World!"); + }); + } +}); diff --git a/test/js/node/test/parallel/test-vm-set-proto-null-on-globalthis.js b/test/js/node/test/parallel/test-vm-set-proto-null-on-globalthis.js new file mode 100644 index 0000000000..869124fa86 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-set-proto-null-on-globalthis.js @@ -0,0 +1,13 @@ +'use strict'; +require('../common'); + +// Setting __proto__ on vm context's globalThis should not cause a crash +// Regression test for https://github.com/nodejs/node/issues/47798 + +const vm = require('vm'); +const context = vm.createContext(); + +const contextGlobalThis = vm.runInContext('this', context); + +// Should not crash. +contextGlobalThis.__proto__ = null; // eslint-disable-line no-proto diff --git a/test/package.json b/test/package.json index 95a6074447..efe5c43799 100644 --- a/test/package.json +++ b/test/package.json @@ -35,6 +35,7 @@ "isbot": "5.1.13", "jest-extended": "4.0.0", "jimp": "1.6.0", + "jsdom": "25.0.1", "jsonwebtoken": "9.0.2", "jws": "4.0.0", "lodash": "4.17.21", From ebc2eb5c5b6eb913c385cecde131d75799ff39c0 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 18 Dec 2024 23:23:42 -0800 Subject: [PATCH 054/125] Support colors array in util.styleText (#15872) --- src/js/node/util.ts | 23 ++++++++++++++++++++++- test/js/node/util/util.test.js | 8 +++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/js/node/util.ts b/src/js/node/util.ts index 3541d1b806..562aad9d15 100644 --- a/src/js/node/util.ts +++ b/src/js/node/util.ts @@ -206,7 +206,28 @@ function styleText(format, text) { e.code = "ERR_INVALID_ARG_TYPE"; throw e; } - const formatCodes = inspect.colors[format]; + + if ($isJSArray(format)) { + let left = ""; + let right = ""; + for (const key of format) { + const formatCodes = inspect.colors[key]; + if (formatCodes == null) { + const e = new Error( + `The value "${typeof key === "symbol" ? key.description : key}" is invalid for argument 'format'. Reason: must be one of: ${Object.keys(inspect.colors).join(", ")}`, + ); + e.code = "ERR_INVALID_ARG_VALUE"; + throw e; + } + left += `\u001b[${formatCodes[0]}m`; + right = `\u001b[${formatCodes[1]}m${right}`; + } + + return `${left}${text}${right}`; + } + + let formatCodes = inspect.colors[format]; + if (formatCodes == null) { const e = new Error( `The value "${typeof format === "symbol" ? format.description : format}" is invalid for argument 'format'. Reason: must be one of: ${Object.keys(inspect.colors).join(", ")}`, diff --git a/test/js/node/util/util.test.js b/test/js/node/util/util.test.js index dd55d12b1a..3f02c2b183 100644 --- a/test/js/node/util/util.test.js +++ b/test/js/node/util/util.test.js @@ -341,7 +341,13 @@ describe("util", () => { }); it("styleText", () => { - [undefined, null, false, 5n, 5, Symbol(), () => {}, {}, []].forEach(invalidOption => { + it("multiplecolors", () => { + expect(util.styleText(["bold", "red"], "test")).toBe("\u001b[1m\u001b[31mtest\u001b[39m\u001b[22m"); + expect(util.styleText("bold"), "test").toBe("\u001b[1mtest\u001b[22m"); + expect(util.styleText("red", "test")).toBe("\u001b[31mtest\u001b[39m"); + }); + + [undefined, null, false, 5n, 5, Symbol(), () => {}, {}].forEach(invalidOption => { assert.throws( () => { util.styleText(invalidOption, "test"); From b539ca32ea90c5af6054778a44262a3ffe6c8172 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 18 Dec 2024 23:23:50 -0800 Subject: [PATCH 055/125] Make `"use strict"` become CommonJS if we don't know whether it's ESM or CJS (#15868) --- src/bun.js/RuntimeTranspilerCache.zig | 3 ++- src/js_parser.zig | 7 ++++--- test/bundler/transpiler/runtime-transpiler.test.ts | 9 +++++++++ test/bundler/transpiler/use-strict-fixture.js | 5 +++++ 4 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 test/bundler/transpiler/use-strict-fixture.js diff --git a/src/bun.js/RuntimeTranspilerCache.zig b/src/bun.js/RuntimeTranspilerCache.zig index 62e8f9a253..ad40bc7399 100644 --- a/src/bun.js/RuntimeTranspilerCache.zig +++ b/src/bun.js/RuntimeTranspilerCache.zig @@ -8,7 +8,8 @@ /// Version 9: String printing changes /// Version 10: Constant folding for ''.charCodeAt(n) /// Version 11: Fix \uFFFF printing regression -const expected_version = 11; +/// Version 12: "use strict"; makes it CommonJS if we otherwise don't know which one to pick. +const expected_version = 12; const bun = @import("root").bun; const std = @import("std"); diff --git a/src/js_parser.zig b/src/js_parser.zig index e0fe7510c6..abe0a5271b 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -3952,9 +3952,10 @@ pub const Parser = struct { if (uses_any_import_statements) { exports_kind = .esm; - - // Otherwise, if they use CommonJS features its CommonJS - } else if (p.symbols.items[p.require_ref.innerIndex()].use_count_estimate > 0 or uses_dirname or uses_filename) { + } + // Otherwise, if they use CommonJS features its CommonJS. + // If you add a 'use strict'; at the top, you probably meant CommonJS because "use strict"; does nothing in ESM. + else if (p.symbols.items[p.require_ref.innerIndex()].use_count_estimate > 0 or uses_dirname or uses_filename or (!p.options.bundle and p.module_scope.strict_mode == .explicit_strict_mode)) { exports_kind = .cjs; } else { // If unknown, we default to ESM diff --git a/test/bundler/transpiler/runtime-transpiler.test.ts b/test/bundler/transpiler/runtime-transpiler.test.ts index 7534e42042..19a234f556 100644 --- a/test/bundler/transpiler/runtime-transpiler.test.ts +++ b/test/bundler/transpiler/runtime-transpiler.test.ts @@ -1,6 +1,15 @@ import { beforeEach, describe, expect, test } from "bun:test"; import { bunEnv, bunExe } from "harness"; +test("use strict causes CommonJS", () => { + const { stdout, exitCode } = Bun.spawnSync({ + cmd: [bunExe(), require.resolve("./use-strict-fixture.js")], + env: bunEnv, + }); + expect(stdout.toString()).toBe("function\n"); + expect(exitCode).toBe(0); +}); + test("non-ascii regexp literals", () => { var str = "🔴11 54 / 10,000"; expect(str.replace(/[🔵🔴,]+/g, "")).toBe("11 54 / 10000"); diff --git a/test/bundler/transpiler/use-strict-fixture.js b/test/bundler/transpiler/use-strict-fixture.js new file mode 100644 index 0000000000..49ee828032 --- /dev/null +++ b/test/bundler/transpiler/use-strict-fixture.js @@ -0,0 +1,5 @@ +"use strict"; + +// Test that 'use strict' makes it CommonJS when we otherwise don't know which one to pick. +// Without that, this direct eval becomes indirect, throwing a ReferenceError. +console.log(eval("typeof module.require")); From 276da2dbf59ac42812609d31920a772d1aa2c96c Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 19 Dec 2024 03:09:10 -0800 Subject: [PATCH 056/125] Create svelte-test.md --- docs/guides/test/svelte-test.md | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 docs/guides/test/svelte-test.md diff --git a/docs/guides/test/svelte-test.md b/docs/guides/test/svelte-test.md new file mode 100644 index 0000000000..b0d775d3fb --- /dev/null +++ b/docs/guides/test/svelte-test.md @@ -0,0 +1,68 @@ +--- +name: "Test Svelte components with bun:test" +description: "import & require .svelte files in your tests in bun's jest-compatible test api, bun:test" +--- + +Bun's [Plugin API](/docs/runtime/plugins.md) lets you add custom loaders to your project and the `test.preload` option in `bunfig.toml` lets you ensure your loaders start before your tests run. + +To support tests that import or require `*.svelte` files + +Save the following plugin in your project: + +```ts#svelte-loader.js +// TODO: make this an npm package instead of a file +import { plugin } from "bun"; +import { compile } from "svelte/compiler"; +import { readFileSync } from "fs"; + +plugin({ + name: "svelte loader", + setup(builder) { + builder.onLoad({ filter: /\.svelte(\?[^.]+)?$/ }, ({ path }) => ({ + contents: compile( + readFileSync(path.substring(0, path.includes("?") ? path.indexOf("?") : path.length), "utf-8"), + { + filename: path, + generate: "server", + dev: false, + }, + ).js.code, + loader: "js", + })); + }, +}); +``` + +--- + +Add it as a `test.preload` in `bunfig.toml`: + +```toml +[test] +preload = ["./svelte-loader.js"] +``` + +--- + +Write a test that imports or requires a `*.svelte` file: + +```ts#hello-svelte.test.ts +import { test, expect } from "bun:test"; +import App from "./my-component.svelte"; + +test("svelte", () => { + expect(App).toBeDefined(); +}); +``` + +--- + +Run your tests: + +```bash +$ bun test +``` + +--- + +You can also try `bun test --preload=./svelte-loader.js` if you don't want to save a bunfig.toml file. From e21050dc6fe165be0e4278045fb7eb4a173acbc2 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 19 Dec 2024 03:09:21 -0800 Subject: [PATCH 057/125] Update svelte-test.md --- docs/guides/test/svelte-test.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/test/svelte-test.md b/docs/guides/test/svelte-test.md index b0d775d3fb..0c21108df6 100644 --- a/docs/guides/test/svelte-test.md +++ b/docs/guides/test/svelte-test.md @@ -3,7 +3,7 @@ name: "Test Svelte components with bun:test" description: "import & require .svelte files in your tests in bun's jest-compatible test api, bun:test" --- -Bun's [Plugin API](/docs/runtime/plugins.md) lets you add custom loaders to your project and the `test.preload` option in `bunfig.toml` lets you ensure your loaders start before your tests run. +Bun's [Plugin API](/docs/runtime/plugins) lets you add custom loaders to your project and the `test.preload` option in `bunfig.toml` lets you ensure your loaders start before your tests run. To support tests that import or require `*.svelte` files From d9b23969482fb55cfea498edaa2d0dde7057b151 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 19 Dec 2024 03:16:06 -0800 Subject: [PATCH 058/125] Update svelte-test.md --- docs/guides/test/svelte-test.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/guides/test/svelte-test.md b/docs/guides/test/svelte-test.md index 0c21108df6..70fcf44d95 100644 --- a/docs/guides/test/svelte-test.md +++ b/docs/guides/test/svelte-test.md @@ -1,13 +1,10 @@ --- -name: "Test Svelte components with bun:test" -description: "import & require .svelte files in your tests in bun's jest-compatible test api, bun:test" +name: "import, require, and test Svelte components with bun:test" --- Bun's [Plugin API](/docs/runtime/plugins) lets you add custom loaders to your project and the `test.preload` option in `bunfig.toml` lets you ensure your loaders start before your tests run. -To support tests that import or require `*.svelte` files - -Save the following plugin in your project: +To get started, save this plugin in your project. ```ts#svelte-loader.js // TODO: make this an npm package instead of a file @@ -35,16 +32,20 @@ plugin({ --- -Add it as a `test.preload` in `bunfig.toml`: +Add this to `bunfig.toml` to tell Bun to preload the plugin, so it loads before your tests run. -```toml +```toml#bunfig.toml [test] +# Tell Bun to load this plugin before your tests run preload = ["./svelte-loader.js"] + +# This also works: +# test.preload = ["./svelte-loader.js"] ``` --- -Write a test that imports or requires a `*.svelte` file: +Now you can `import` or `require` `*.svelte` files in your tests, and it will load the Svelte component as a JavaScript module. ```ts#hello-svelte.test.ts import { test, expect } from "bun:test"; @@ -57,7 +58,7 @@ test("svelte", () => { --- -Run your tests: +To run your tests: ```bash $ bun test From 5dcfc6f10fd26257431cff3efde96c8e129e0278 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 19 Dec 2024 03:17:02 -0800 Subject: [PATCH 059/125] Update svelte-test.md --- docs/guides/test/svelte-test.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/test/svelte-test.md b/docs/guides/test/svelte-test.md index 70fcf44d95..db24cd228e 100644 --- a/docs/guides/test/svelte-test.md +++ b/docs/guides/test/svelte-test.md @@ -1,8 +1,8 @@ --- -name: "import, require, and test Svelte components with bun:test" +name: "import, require, and test Svelte components with bun test" --- -Bun's [Plugin API](/docs/runtime/plugins) lets you add custom loaders to your project and the `test.preload` option in `bunfig.toml` lets you ensure your loaders start before your tests run. +Bun's [Plugin API](/docs/runtime/plugins) lets you add custom loaders to your project. The `test.preload` option in `bunfig.toml` lets you configure your loader to start before your tests run. To get started, save this plugin in your project. From b254e6932279ee6ab7aa924d98d4d1b52a601bfe Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 19 Dec 2024 03:44:46 -0800 Subject: [PATCH 060/125] Fix svelte testing guide --- docs/guides/test/svelte-test.md | 85 ++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 17 deletions(-) diff --git a/docs/guides/test/svelte-test.md b/docs/guides/test/svelte-test.md index db24cd228e..062cd3312d 100644 --- a/docs/guides/test/svelte-test.md +++ b/docs/guides/test/svelte-test.md @@ -4,30 +4,59 @@ name: "import, require, and test Svelte components with bun test" Bun's [Plugin API](/docs/runtime/plugins) lets you add custom loaders to your project. The `test.preload` option in `bunfig.toml` lets you configure your loader to start before your tests run. -To get started, save this plugin in your project. +Firstly, install `@testing-library/svelte`, `svelte`, and `@happy-dom/global-registrator`. + +```bash +$ bun add @testing-library/svelte svelte@4 @happy-dom/global-registrator +``` + +Then, save this plugin in your project. ```ts#svelte-loader.js -// TODO: make this an npm package instead of a file import { plugin } from "bun"; import { compile } from "svelte/compiler"; import { readFileSync } from "fs"; +import { beforeEach, afterEach } from "bun:test"; +import { GlobalRegistrator } from "@happy-dom/global-registrator"; + +beforeEach(async () => { + await GlobalRegistrator.register(); +}); + +afterEach(async () => { + await GlobalRegistrator.unregister(); +}); plugin({ name: "svelte loader", setup(builder) { - builder.onLoad({ filter: /\.svelte(\?[^.]+)?$/ }, ({ path }) => ({ - contents: compile( - readFileSync(path.substring(0, path.includes("?") ? path.indexOf("?") : path.length), "utf-8"), - { + builder.onLoad({ filter: /\.svelte(\?[^.]+)?$/ }, ({ path }) => { + try { + const source = readFileSync( + path.substring( + 0, + path.includes("?") ? path.indexOf("?") : path.length + ), + "utf-8" + ); + + const result = compile(source, { filename: path, - generate: "server", + generate: "client", dev: false, - }, - ).js.code, - loader: "js", - })); + }); + + return { + contents: result.js.code, + loader: "js", + }; + } catch (err) { + throw new Error(`Failed to compile Svelte component: ${err.message}`); + } + }); }, }); + ``` --- @@ -45,25 +74,47 @@ preload = ["./svelte-loader.js"] --- +Add an example `.svelte` file in your project. + +```html#Counter.svelte + + + +``` + +--- + Now you can `import` or `require` `*.svelte` files in your tests, and it will load the Svelte component as a JavaScript module. ```ts#hello-svelte.test.ts import { test, expect } from "bun:test"; -import App from "./my-component.svelte"; +import { render, fireEvent } from "@testing-library/svelte"; +import Counter from "./Counter.svelte"; -test("svelte", () => { - expect(App).toBeDefined(); +test("Counter increments when clicked", async () => { + const { getByText, component } = render(Counter); + const button = getByText("+1"); + + // Initial state + expect(component.$$.ctx[0]).toBe(0); // initialCount is the first prop + + // Click the increment button + await fireEvent.click(button); + + // Check the new state + expect(component.$$.ctx[0]).toBe(1); }); ``` --- -To run your tests: +Use `bun test` to run your tests. ```bash $ bun test ``` --- - -You can also try `bun test --preload=./svelte-loader.js` if you don't want to save a bunfig.toml file. From 3cbcd43f9abdd7c376f582bcbdfebdc0ab800feb Mon Sep 17 00:00:00 2001 From: Ashcon Partovi Date: Thu, 19 Dec 2024 11:18:13 -0800 Subject: [PATCH 061/125] ci: Enable merge queue, disable soft failing tests --- .buildkite/ci.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.buildkite/ci.mjs b/.buildkite/ci.mjs index 9f39a72a3d..3fb1e643f3 100755 --- a/.buildkite/ci.mjs +++ b/.buildkite/ci.mjs @@ -543,9 +543,8 @@ function getTestBunStep(platform, options, testOptions = {}) { label: `${getPlatformLabel(platform)} - test-bun`, depends_on: depends, agents: getTestAgent(platform, options), - cancel_on_build_failing: isMergeQueue(), retry: getRetry(), - soft_fail: isMainBranch() ? true : [{ exit_status: 2 }], + cancel_on_build_failing: isMergeQueue(), parallelism: unifiedTests ? undefined : os === "darwin" ? 2 : 10, command: os === "windows" @@ -590,6 +589,7 @@ function getBuildImageStep(platform, options) { DEBUG: "1", }, retry: getRetry(), + cancel_on_build_failing: isMergeQueue(), command: command.filter(Boolean).join(" "), timeout_in_minutes: 3 * 60, }; From f546a9b605225c6e81bac1bc33ee127525ddfca1 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Thu, 19 Dec 2024 14:32:25 -0800 Subject: [PATCH 062/125] chore: add usage messages to check-node.sh (#15885) Co-authored-by: Don Isaac --- scripts/check-node.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/scripts/check-node.sh b/scripts/check-node.sh index 39624e8278..47c2787186 100755 --- a/scripts/check-node.sh +++ b/scripts/check-node.sh @@ -1,8 +1,28 @@ #!/bin/bash +# How to use this script: +# 1. Pick a module from node's standard library (e.g. 'assert', 'fs') +# 2. Copy over relevant tests from node's parallel test suite into test/js/node/test/parallel +# 3. Run this script, e.g. `./scripts/check-node.sh fs` +# 4. Tests that passed get staged for commit + i=0 j=0 +if [[ -z $1 ]] +then + echo "Usage: $0 " + exit 1 +fi + +case $1 in + -h|--help) + echo "Usage: $0 " + echo "Run all parallel tests for a single module in node's standard library" + exit 0 + ;; +esac + export BUN_DEBUG_QUIET_LOGS=1 export NO_COLOR=1 From 960b2b2c11ed20a21082dfdc56006f5da693f58b Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Thu, 19 Dec 2024 15:42:18 -0800 Subject: [PATCH 063/125] perf(node:util): fast path for `extractedSplitNewLines` (#15838) Co-authored-by: Don Isaac Co-authored-by: DonIsaac --- src/bun.js/node/node_util_binding.zig | 90 +++++++++++++++++++++++++++ src/js/internal/util/inspect.js | 28 ++++++++- test/js/web/fetch/fetch.test.ts | 4 +- 3 files changed, 117 insertions(+), 5 deletions(-) diff --git a/src/bun.js/node/node_util_binding.zig b/src/bun.js/node/node_util_binding.zig index 2f886cb0fa..384a478de2 100644 --- a/src/bun.js/node/node_util_binding.zig +++ b/src/bun.js/node/node_util_binding.zig @@ -1,5 +1,6 @@ const std = @import("std"); const bun = @import("root").bun; +const Allocator = std.mem.Allocator; const Environment = bun.Environment; const JSC = bun.JSC; const string = bun.string; @@ -105,3 +106,92 @@ pub fn internalErrorName(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFr var fmtstring = bun.String.createFormat("Unknown system error {d}", .{err_int}) catch bun.outOfMemory(); return fmtstring.transferToJS(globalThis); } + +/// `extractedSplitNewLines` for ASCII/Latin1 strings. Panics if passed a non-string. +/// Returns `undefined` if param is utf8 or utf16 and not fully ascii. +/// +/// ```js +/// // util.js +/// const extractedNewLineRe = new RegExp("(?<=\\n)"); +/// extractedSplitNewLines = value => RegExpPrototypeSymbolSplit(extractedNewLineRe, value); +/// ``` +pub fn extractedSplitNewLinesFastPathStringsOnly(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { + bun.assert(callframe.argumentsCount() == 1); + const value = callframe.argument(0); + bun.assert(value.isString()); + + const str = try value.toBunString2(globalThis); + defer str.deref(); + + return switch (str.encoding()) { + inline .utf16, .latin1 => |encoding| split(encoding, globalThis, bun.default_allocator, &str), + .utf8 => if (bun.strings.isAllASCII(str.byteSlice())) + return split(.utf8, globalThis, bun.default_allocator, &str) + else + return JSC.JSValue.jsUndefined(), + }; +} + +fn split( + comptime encoding: bun.strings.EncodingNonAscii, + globalThis: *JSC.JSGlobalObject, + allocator: Allocator, + str: *const bun.String, +) bun.JSError!JSC.JSValue { + std.debug.print("{any}\n", .{encoding}); + var fallback = std.heap.stackFallback(1024, allocator); + const alloc = fallback.get(); + const Char = switch (encoding) { + .utf8, .latin1 => u8, + .utf16 => u16, + }; + + var lines: std.ArrayListUnmanaged(bun.String) = .{}; + defer { + for (lines.items) |out| { + out.deref(); + } + lines.deinit(alloc); + } + + const buffer: []const Char = if (encoding == .utf16) + str.utf16() + else + str.byteSlice(); + var it: SplitNewlineIterator(Char) = .{ .buffer = buffer, .index = 0 }; + while (it.next()) |line| { + const encoded_line = switch (encoding) { + inline .utf8 => bun.String.fromUTF8(line), + inline .latin1 => bun.String.createLatin1(line), + inline .utf16 => bun.String.fromUTF16(line), + }; + errdefer encoded_line.deref(); + try lines.append(alloc, encoded_line); + } + + return bun.String.toJSArray(globalThis, lines.items); +} + +pub fn SplitNewlineIterator(comptime T: type) type { + return struct { + buffer: []const T, + index: ?usize, + + const Self = @This(); + + /// Returns a slice of the next field, or null if splitting is complete. + pub fn next(self: *Self) ?[]const T { + const start = self.index orelse return null; + + if (std.mem.indexOfScalarPos(T, self.buffer, start, '\n')) |delim_start| { + const end = delim_start + 1; + const slice = self.buffer[start..end]; + self.index = end; + return slice; + } else { + self.index = null; + return self.buffer[start..]; + } + } + }; +} diff --git a/src/js/internal/util/inspect.js b/src/js/internal/util/inspect.js index 5cdb40af5b..f98354aae0 100644 --- a/src/js/internal/util/inspect.js +++ b/src/js/internal/util/inspect.js @@ -141,6 +141,21 @@ const kRejected = Symbol("kRejected"); // state ID 2 const ALL_PROPERTIES = 0; const ONLY_ENUMERABLE = 2; +/** + * Fast path for {@link extractedSplitNewLines} for ASCII/Latin1 strings. + * @returns `value` split on newlines (newline included at end), or `undefined` + * if non-ascii UTF8/UTF16. + * + * Passing this a non-string will cause a panic. + * + * @type {(value: string) => string[] | undefined} + */ +const extractedSplitNewLinesFastPathStringsOnly = $newZigFunction( + "node_util_binding.zig", + "extractedSplitNewLinesFastPathStringsOnly", + 1, +); + const isAsyncFunction = v => typeof v === "function" && StringPrototypeStartsWith(FunctionPrototypeToString(v), "async"); const isGeneratorFunction = v => @@ -397,7 +412,7 @@ let strEscapeSequencesRegExp, strEscapeSequencesReplacer, strEscapeSequencesRegExpSingle, strEscapeSequencesReplacerSingle, - extractedSplitNewLines; + extractedSplitNewLinesSlow; try { // Change from regex literals to RegExp constructors to avoid unrecoverable // syntax error at load time. @@ -416,7 +431,7 @@ try { "g", ); const extractedNewLineRe = new RegExp("(?<=\\n)"); - extractedSplitNewLines = value => RegExpPrototypeSymbolSplit(extractedNewLineRe, value); + extractedSplitNewLinesSlow = value => RegExpPrototypeSymbolSplit(extractedNewLineRe, value); // CI doesn't run in an elderly runtime } catch { // These are from a previous version of node, @@ -426,7 +441,7 @@ try { strEscapeSequencesReplacer = /[\x00-\x1f\x27\x5c\x7f-\x9f]/g; strEscapeSequencesRegExpSingle = /[\x00-\x1f\x5c\x7f-\x9f]/; strEscapeSequencesReplacerSingle = /[\x00-\x1f\x5c\x7f-\x9f]/g; - extractedSplitNewLines = value => { + extractedSplitNewLinesSlow = value => { const lines = RegExpPrototypeSymbolSplit(/\n/, value); const last = ArrayPrototypePop(lines); const nlLines = ArrayPrototypeMap(lines, line => line + "\n"); @@ -437,6 +452,13 @@ try { }; } +const extractedSplitNewLines = value => { + if (typeof value === "string") { + return extractedSplitNewLinesFastPathStringsOnly(value) || extractedSplitNewLinesSlow(value); + } + return extractedSplitNewLinesSlow(value); +} + const keyStrRegExp = /^[a-zA-Z_][a-zA-Z_0-9]*$/; const numberRegExp = /^(0|[1-9][0-9]*)$/; diff --git a/test/js/web/fetch/fetch.test.ts b/test/js/web/fetch/fetch.test.ts index 2b9f434aa2..02ff359eea 100644 --- a/test/js/web/fetch/fetch.test.ts +++ b/test/js/web/fetch/fetch.test.ts @@ -1,7 +1,7 @@ import { AnyFunction, serve, ServeOptions, Server, sleep, TCPSocketListener } from "bun"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "bun:test"; import { chmodSync, readFileSync, rmSync, writeFileSync } from "fs"; -import { bunEnv, bunExe, gc, isWindows, tls, tmpdirSync, withoutAggressiveGC } from "harness"; +import { bunEnv, bunExe, gc, isBroken, isWindows, tls, tmpdirSync, withoutAggressiveGC } from "harness"; import { mkfifo } from "mkfifo"; import net from "net"; import { join } from "path"; @@ -2010,7 +2010,7 @@ describe("http/1.1 response body length", () => { expect(response.arrayBuffer()).resolves.toHaveLength(0); }); - it("should ignore body on HEAD", async () => { + it.todoIf(isBroken)("should ignore body on HEAD", async () => { const response = await fetch(`http://${getHost()}/text`, { method: "HEAD" }); expect(response.status).toBe(200); expect(response.arrayBuffer()).resolves.toHaveLength(0); From 35679b317873bca3667105c8ba195c208bbd5880 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 19 Dec 2024 17:34:38 -0800 Subject: [PATCH 064/125] Update node_util_binding.zig --- src/bun.js/node/node_util_binding.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bun.js/node/node_util_binding.zig b/src/bun.js/node/node_util_binding.zig index 384a478de2..cbcf25f09b 100644 --- a/src/bun.js/node/node_util_binding.zig +++ b/src/bun.js/node/node_util_binding.zig @@ -138,7 +138,6 @@ fn split( allocator: Allocator, str: *const bun.String, ) bun.JSError!JSC.JSValue { - std.debug.print("{any}\n", .{encoding}); var fallback = std.heap.stackFallback(1024, allocator); const alloc = fallback.get(); const Char = switch (encoding) { From 747828965ed04c43c07ffb3abfe8194daf61fdec Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:14:33 -0800 Subject: [PATCH 065/125] fix(install): sort tree dependencies by behavior and name (#15895) --- src/install/lockfile.zig | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index ae36f49184..d6f7f7e3c9 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -762,10 +762,14 @@ pub const Tree = struct { const deps_buf = sorter.lockfile.buffers.dependencies.items; const string_buf = sorter.lockfile.buffers.string_bytes.items; - const l_dep_name = deps_buf[l].name.slice(string_buf); - const r_dep_name = deps_buf[r].name.slice(string_buf); + const l_dep = deps_buf[l]; + const r_dep = deps_buf[r]; - return strings.order(l_dep_name, r_dep_name) == .lt; + return switch (l_dep.behavior.cmp(r_dep.behavior)) { + .lt => true, + .gt => false, + .eq => strings.order(l_dep.name.slice(string_buf), r_dep.name.slice(string_buf)) == .lt, + }; } }; From 9164760a5a8a76c6d9e0934d6216c2a3f7d1bc97 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:52:50 -0800 Subject: [PATCH 066/125] fix `pnpm.test.ts` (#15897) --- test/js/third_party/pnpm/pnpm.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/js/third_party/pnpm/pnpm.test.ts b/test/js/third_party/pnpm/pnpm.test.ts index 9094de5eaf..c6e8e6ff03 100644 --- a/test/js/third_party/pnpm/pnpm.test.ts +++ b/test/js/third_party/pnpm/pnpm.test.ts @@ -9,7 +9,7 @@ it("successfully traverses pnpm-generated install directory", async () => { // let { exited } = Bun.spawn({ - cmd: [bunExe(), "create", "vite", "my-vite-app", "--template", "solid-ts"], + cmd: [bunExe(), "create", "vite@5", "my-vite-app", "--template", "solid-ts"], cwd: package_dir, stdio: ["ignore", "inherit", "inherit"], env: bunEnv, From e3fed4908296c3afc3e606e629979f3c6bd58052 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 20 Dec 2024 00:23:55 -0800 Subject: [PATCH 067/125] Implement expect().toHaveBeenCalledOnce() (#15871) Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> --- src/bun.js/test/expect.zig | 31 +++++++++++++++++++++++++++++++ src/bun.js/test/jest.classes.ts | 4 ++++ test/js/bun/test/mock-fn.test.js | 3 +++ 3 files changed, 38 insertions(+) diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index d16b4e4be9..a9ef928354 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -4060,6 +4060,37 @@ pub const Expect = struct { return this.throw(globalThis, signature, "\n\n" ++ "Expected number of calls: \\>= 1\n" ++ "Received number of calls: {any}\n", .{calls.getLength(globalThis)}); } + pub fn toHaveBeenCalledOnce(this: *Expect, globalThis: *JSGlobalObject, callframe: *CallFrame) bun.JSError!JSValue { + JSC.markBinding(@src()); + + const thisValue = callframe.this(); + defer this.postMatch(globalThis); + const value: JSValue = try this.getValue(globalThis, thisValue, "toHaveBeenCalledOnce", "expected"); + + incrementExpectCallCounter(); + + const calls = JSMockFunction__getCalls(value); + + if (calls == .zero or !calls.jsType().isArray()) { + return globalThis.throw("Expected value must be a mock function: {}", .{value}); + } + + var pass = @as(i32, @intCast(calls.getLength(globalThis))) == 1; + + const not = this.flags.not; + if (not) pass = !pass; + if (pass) return .undefined; + + // handle failure + if (not) { + const signature = comptime getSignature("toHaveBeenCalledOnce", "expected", true); + return this.throw(globalThis, signature, "\n\n" ++ "Expected number of calls: not 1\n" ++ "Received number of calls: {d}\n", .{calls.getLength(globalThis)}); + } + + const signature = comptime getSignature("toHaveBeenCalledOnce", "expected", false); + return this.throw(globalThis, signature, "\n\n" ++ "Expected number of calls: 1\n" ++ "Received number of calls: {d}\n", .{calls.getLength(globalThis)}); + } + pub fn toHaveBeenCalledTimes(this: *Expect, globalThis: *JSGlobalObject, callframe: *CallFrame) bun.JSError!JSValue { JSC.markBinding(@src()); diff --git a/src/bun.js/test/jest.classes.ts b/src/bun.js/test/jest.classes.ts index 38c0397a03..57b4273aba 100644 --- a/src/bun.js/test/jest.classes.ts +++ b/src/bun.js/test/jest.classes.ts @@ -297,6 +297,10 @@ export default [ fn: "toHaveBeenCalled", length: 0, }, + toHaveBeenCalledOnce: { + fn: "toHaveBeenCalledOnce", + length: 0, + }, toHaveBeenCalledTimes: { fn: "toHaveBeenCalledTimes", length: 1, diff --git a/test/js/bun/test/mock-fn.test.js b/test/js/bun/test/mock-fn.test.js index c9c29fd63d..4f813f7ffa 100644 --- a/test/js/bun/test/mock-fn.test.js +++ b/test/js/bun/test/mock-fn.test.js @@ -100,13 +100,16 @@ describe("mock()", () => { } test("are callable", () => { const fn = jest.fn(() => 42); + expect(fn).not.toHaveBeenCalledOnce(); expect(fn()).toBe(42); + expect(fn).toHaveBeenCalledOnce(); expect(fn).toHaveBeenCalled(); expect(fn).toHaveBeenCalledTimes(1); expect(fn.mock.calls).toHaveLength(1); expect(fn.mock.calls[0]).toBeEmpty(); expect(fn).toHaveBeenLastCalledWith(); expect(fn()).toBe(42); + expect(fn).not.toHaveBeenCalledOnce(); expect(fn).toHaveBeenCalledTimes(2); expect(fn.mock.calls).toHaveLength(2); expect(fn.mock.calls[1]).toBeEmpty(); From 45ca9e08c3e8cc71c788461328c2091b59611883 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Fri, 20 Dec 2024 00:34:21 -0800 Subject: [PATCH 068/125] fix(install): `peer/dev/optional = false` lockfile fix (#15874) Co-authored-by: Jarred Sumner --- docs/cli/bun-install.md | 3 + docs/cli/install.md | 14 + docs/install/index.md | 7 + src/ini.zig | 62 ++++ src/install/bun.lock.zig | 105 +++--- src/install/extract_tarball.zig | 4 +- src/install/install.zig | 309 +++++++++--------- src/install/lockfile.zig | 298 +++++++++++------ src/install/migration.zig | 2 +- src/install/patch_install.zig | 9 +- src/resolver/resolver.zig | 2 +- test/cli/install/bun-install.test.ts | 184 ++++++++--- test/cli/install/bun-run.test.ts | 4 +- .../bun-install-registry.test.ts.snap | 27 ++ .../registry/bun-install-registry.test.ts | 123 +++++++ test/harness.ts | 7 + 16 files changed, 808 insertions(+), 352 deletions(-) diff --git a/docs/cli/bun-install.md b/docs/cli/bun-install.md index f06e1843e5..a2eb2ee196 100644 --- a/docs/cli/bun-install.md +++ b/docs/cli/bun-install.md @@ -57,12 +57,15 @@ frozenLockfile = false dryRun = true # Install optionalDependencies (default: true) +# Setting this to false is equivalent to the `--omit=optional` CLI argument optional = true # Install local devDependencies (default: true) +# Setting this to false is equivalent to the `--omit=dev` CLI argument dev = true # Install peerDependencies (default: true) +# Setting this to false is equivalent to the `--omit=peer` CLI argument peer = true # Max number of concurrent lifecycle scripts (default: (cpu count or GOMAXPROCS) x2) diff --git a/docs/cli/install.md b/docs/cli/install.md index 2fa9db7461..25d46c98a1 100644 --- a/docs/cli/install.md +++ b/docs/cli/install.md @@ -130,6 +130,20 @@ $ bun install --frozen-lockfile For more information on Bun's binary lockfile `bun.lockb`, refer to [Package manager > Lockfile](https://bun.sh/docs/install/lockfile). +## Omitting dependencies + +To omit dev, peer, or optional dependencies use the `--omit` flag. + +```bash +# Exclude "devDependencies" from the installation. This will apply to the +# root package and workspaces if they exist. Transitive dependencies will +# not have "devDependencies". +$ bun install --omit dev + +# Install only dependencies from "dependencies" +$ bun install --omit=dev --omit=peer --omit=optional +``` + ## Dry run To perform a dry run (i.e. don't actually install anything): diff --git a/docs/install/index.md b/docs/install/index.md index 5631b55adb..8f412a05e9 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -55,6 +55,13 @@ To install dependencies without allowing changes to lockfile (useful on CI): $ bun install --frozen-lockfile ``` +To exclude dependency types from installing, use `--omit` with `dev`, `optional`, or `peer`: + +```bash +# Disable devDependencies and optionalDependencies +$ bun install --omit=dev --omit=optional +``` + To perform a dry run (i.e. don't actually install anything): ```bash diff --git a/src/ini.zig b/src/ini.zig index d13c34d696..017670fbd3 100644 --- a/src/ini.zig +++ b/src/ini.zig @@ -971,6 +971,68 @@ pub fn loadNpmrc( } } + if (out.asProperty("omit")) |omit| { + switch (omit.expr.data) { + .e_string => |str| { + if (str.eqlComptime("dev")) { + install.save_dev = false; + } else if (str.eqlComptime("peer")) { + install.save_peer = false; + } else if (str.eqlComptime("optional")) { + install.save_optional = false; + } + }, + .e_array => |arr| { + for (arr.items.slice()) |item| { + switch (item.data) { + .e_string => |str| { + if (str.eqlComptime("dev")) { + install.save_dev = false; + } else if (str.eqlComptime("peer")) { + install.save_peer = false; + } else if (str.eqlComptime("optional")) { + install.save_optional = false; + } + }, + else => {}, + } + } + }, + else => {}, + } + } + + if (out.asProperty("include")) |omit| { + switch (omit.expr.data) { + .e_string => |str| { + if (str.eqlComptime("dev")) { + install.save_dev = true; + } else if (str.eqlComptime("peer")) { + install.save_peer = true; + } else if (str.eqlComptime("optional")) { + install.save_optional = true; + } + }, + .e_array => |arr| { + for (arr.items.slice()) |item| { + switch (item.data) { + .e_string => |str| { + if (str.eqlComptime("dev")) { + install.save_dev = true; + } else if (str.eqlComptime("peer")) { + install.save_peer = true; + } else if (str.eqlComptime("optional")) { + install.save_optional = true; + } + }, + else => {}, + } + } + }, + else => {}, + } + } + var registry_map = install.scoped orelse bun.Schema.Api.NpmRegistryMap{}; // Process scopes diff --git a/src/install/bun.lock.zig b/src/install/bun.lock.zig index 4a18b12e64..fef28d2b91 100644 --- a/src/install/bun.lock.zig +++ b/src/install/bun.lock.zig @@ -246,11 +246,7 @@ pub const Stringifier = struct { // _ = this; // } - pub fn saveFromBinary(allocator: std.mem.Allocator, lockfile: *const BinaryLockfile) OOM!string { - var writer_buf = MutableString.initEmpty(allocator); - var buffered_writer = writer_buf.bufferedWriter(); - var writer = buffered_writer.writer(); - + pub fn saveFromBinary(allocator: std.mem.Allocator, lockfile: *const BinaryLockfile, writer: anytype) @TypeOf(writer).Error!void { const buf = lockfile.buffers.string_bytes.items; const deps_buf = lockfile.buffers.dependencies.items; const resolution_buf = lockfile.buffers.resolutions.items; @@ -594,15 +590,17 @@ pub const Stringifier = struct { TreeDepsSortCtx.isLessThan, ); - // first index is resolution for all dependency types - // npm -> [ "name@version", registry or "" (default), deps..., integrity, ... ] - // symlink -> [ "name@link:path", deps..., ... ] - // folder -> [ "name@path", deps..., ... ] - // workspace -> [ "name@workspace:path", version or "", deps..., ... ] - // tarball -> [ "name@tarball", deps..., ... ] - // root -> [ "name@root:", bins ] - // git -> [ "name@git+repo", deps..., ... ] - // github -> [ "name@github:user/repo", deps..., ... ] + // INFO = { prod/dev/optional/peer dependencies, os, cpu, libc (TODO), bin, binDir } + + // first index is resolution for each type of package + // npm -> [ "name@version", registry (TODO: remove if default), INFO, integrity] + // symlink -> [ "name@link:path", INFO ] + // folder -> [ "name@file:path", INFO ] + // workspace -> [ "name@workspace:path", INFO ] + // tarball -> [ "name@tarball", INFO ] + // root -> [ "name@root:", { bin, binDir } ] + // git -> [ "name@git+repo", INFO, .bun-tag string (TODO: remove this) ] + // github -> [ "name@github:user/repo", INFO, .bun-tag string (TODO: remove this) ] switch (res.tag) { .root => { @@ -716,9 +714,6 @@ pub const Stringifier = struct { } try decIndent(writer, indent); try writer.writeAll("}\n"); - - try buffered_writer.flush(); - return writer_buf.list.items; } /// Writes a single line object. Contains dependencies, os, cpu, libc (soon), and bin @@ -1218,21 +1213,26 @@ pub fn parseIntoBinaryLockfile( var optional_peers_buf: std.AutoHashMapUnmanaged(u64, void) = .{}; defer optional_peers_buf.deinit(allocator); - if (maybe_root_pkg) |root_pkg| { - const maybe_name = if (root_pkg.get("name")) |name| name.asString(allocator) orelse { + const root_pkg_exr = maybe_root_pkg orelse { + try log.addError(source, workspaces.loc, "Expected root package"); + return error.InvalidWorkspaceObject; + }; + + { + const maybe_name = if (root_pkg_exr.get("name")) |name| name.asString(allocator) orelse { try log.addError(source, name.loc, "Expected a string"); return error.InvalidWorkspaceObject; } else null; - const off, var len = try parseAppendDependencies(lockfile, allocator, &root_pkg, &string_buf, log, source, &optional_peers_buf); + const off, var len = try parseAppendDependencies(lockfile, allocator, &root_pkg_exr, &string_buf, log, source, &optional_peers_buf); - var pkg: BinaryLockfile.Package = .{}; - pkg.meta.id = 0; + var root_pkg: BinaryLockfile.Package = .{}; + root_pkg.meta.id = 0; if (maybe_name) |name| { const name_hash = String.Builder.stringHash(name); - pkg.name = try string_buf.appendWithHash(name, name_hash); - pkg.name_hash = name_hash; + root_pkg.name = try string_buf.appendWithHash(name, name_hash); + root_pkg.name_hash = name_hash; } workspaces: for (lockfile.workspace_paths.values()) |workspace_path| { @@ -1262,15 +1262,12 @@ pub fn parseIntoBinaryLockfile( } } - pkg.dependencies = .{ .off = off, .len = len }; - pkg.resolutions = .{ .off = off, .len = len }; + root_pkg.dependencies = .{ .off = off, .len = len }; + root_pkg.resolutions = .{ .off = off, .len = len }; - pkg.meta.id = 0; - try lockfile.packages.append(allocator, pkg); - try lockfile.getOrPutID(0, pkg.name_hash); - } else { - try log.addError(source, workspaces.loc, "Expected root package"); - return error.InvalidWorkspaceObject; + root_pkg.meta.id = 0; + try lockfile.packages.append(allocator, root_pkg); + try lockfile.getOrPutID(0, root_pkg.name_hash); } var pkg_map = bun.StringArrayHashMap(PackageID).init(allocator); @@ -1491,9 +1488,15 @@ pub fn parseIntoBinaryLockfile( const dep_id: DependencyID = @intCast(_dep_id); const dep = lockfile.buffers.dependencies.items[dep_id]; - if (pkg_map.get(dep.name.slice(lockfile.buffers.string_bytes.items))) |res_pkg_id| { - lockfile.buffers.resolutions.items[dep_id] = res_pkg_id; - } + const res_pkg_id = pkg_map.get(dep.name.slice(lockfile.buffers.string_bytes.items)) orelse { + if (dep.behavior.optional) { + continue; + } + try dependencyResolutionFailure(&dep, null, allocator, lockfile.buffers.string_bytes.items, source, log, root_pkg_exr.loc); + return error.InvalidPackageInfo; + }; + + lockfile.buffers.resolutions.items[dep_id] = res_pkg_id; } // TODO(dylan-conway) should we handle workspaces separately here for custom hoisting @@ -1533,10 +1536,10 @@ pub fn parseIntoBinaryLockfile( } if (offset == 0) { - if (dep.behavior.isOptionalPeer()) { + if (dep.behavior.optional) { continue :deps; } - try log.addError(source, key.loc, "Unable to resolve dependencies for package"); + try dependencyResolutionFailure(&dep, pkg_path, allocator, lockfile.buffers.string_bytes.items, source, log, key.loc); return error.InvalidPackageInfo; } @@ -1584,7 +1587,7 @@ pub fn parseIntoBinaryLockfile( } } - lockfile.hoist(log, if (manager) |pm| pm.options.local_package_features.dev_dependencies else true) catch |err| { + lockfile.hoist(log, .resolvable, {}) catch |err| { switch (err) { error.OutOfMemory => |oom| return oom, else => { @@ -1599,6 +1602,32 @@ pub fn parseIntoBinaryLockfile( lockfile.initEmpty(allocator); } +fn dependencyResolutionFailure(dep: *const Dependency, pkg_path: ?string, allocator: std.mem.Allocator, buf: string, source: *const logger.Source, log: *logger.Log, loc: logger.Loc) OOM!void { + const behavior_str = if (dep.behavior.isDev()) + "dev" + else if (dep.behavior.isOptional()) + "optional" + else if (dep.behavior.isPeer()) + "peer" + else if (dep.behavior.isWorkspaceOnly()) + "workspace" + else + "prod"; + + if (pkg_path) |path| { + try log.addErrorFmt(source, loc, allocator, "Failed to resolve {s} dependency '{s}' for package '{s}'", .{ + behavior_str, + dep.name.slice(buf), + path, + }); + } else { + try log.addErrorFmt(source, loc, allocator, "Failed to resolve root {s} dependency '{s}'", .{ + behavior_str, + dep.name.slice(buf), + }); + } +} + fn parseAppendDependencies( lockfile: *BinaryLockfile, allocator: std.mem.Allocator, diff --git a/src/install/extract_tarball.zig b/src/install/extract_tarball.zig index 8959383769..e8b8fb0c48 100644 --- a/src/install/extract_tarball.zig +++ b/src/install/extract_tarball.zig @@ -53,8 +53,8 @@ pub fn buildURL( full_name_: strings.StringOrTinyString, version: Semver.Version, string_buf: []const u8, -) !string { - return try buildURLWithPrinter( +) OOM!string { + return buildURLWithPrinter( registry_, full_name_, version, diff --git a/src/install/install.zig b/src/install/install.zig index efbe502056..521594194f 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -477,13 +477,17 @@ const NetworkTask = struct { this.http.schedule(this.allocator, batch); } + pub const ForTarballError = OOM || error{ + InvalidURL, + }; + pub fn forTarball( this: *NetworkTask, allocator: std.mem.Allocator, tarball_: *const ExtractTarball, scope: *const Npm.Registry.Scope, authorization: NetworkTask.Authorization, - ) !void { + ) ForTarballError!void { this.callback = .{ .extract = tarball_.* }; const tarball = &this.callback.extract; const tarball_url = tarball.url.slice(); @@ -504,11 +508,11 @@ const NetworkTask = struct { .args = .{ bun.fmt.QuotedFormatter{ .text = this.url_buf }, bun.fmt.QuotedFormatter{ .text = tarball.name.slice() } }, }; - this.package_manager.log.addErrorFmt(null, .{}, allocator, msg.fmt, msg.args) catch unreachable; + try this.package_manager.log.addErrorFmt(null, .{}, allocator, msg.fmt, msg.args); return error.InvalidURL; } - this.response_buffer = try MutableString.init(allocator, 0); + this.response_buffer = MutableString.initEmpty(allocator); this.allocator = allocator; var header_builder = HeaderBuilder{}; @@ -1024,10 +1028,6 @@ pub fn NewPackageInstall(comptime kind: PkgInstallKind) type { skipped: u32 = 0, successfully_installed: ?Bitset = null, - /// The lockfile used by `installPackages`. Might be different from the lockfile - /// on disk if `--production` is used and dev dependencies are removed. - lockfile_used_for_install: *Lockfile, - /// Package name hash -> number of scripts skipped. /// Multiple versions of the same package might add to the count, and each version /// might have a different number of scripts @@ -4245,8 +4245,6 @@ pub const PackageManager = struct { }; } else if (behavior.isPeer() and !install_peer) { return null; - } else if (behavior.isOptional() and !this.options.remote_package_features.optional_dependencies) { - return null; } // appendPackage sets the PackageID on the package @@ -4279,24 +4277,26 @@ pub const PackageManager = struct { // We don't need to download the tarball, but we should enqueue dependencies .done => .{ .package = package, .is_first_time = true }, // Do we need to download the tarball? - .extract => .{ - .package = package, - .is_first_time = true, - .task = .{ - .network_task = try this.generateNetworkTaskForTarball( - Task.Id.forNPMPackage( - this.lockfile.str(&name), - package.resolution.value.npm.version, - ), - manifest.str(&find_result.package.tarball_url), - dependency.behavior.isRequired(), - dependency_id, - package, - name_and_version_hash, - // its npm. - .allow_authorization, - ) orelse unreachable, - }, + .extract => extract: { + const task_id = Task.Id.forNPMPackage(this.lockfile.str(&name), package.resolution.value.npm.version); + bun.debugAssert(!this.network_dedupe_map.contains(task_id)); + + break :extract .{ + .package = package, + .is_first_time = true, + .task = .{ + .network_task = try this.generateNetworkTaskForTarball( + task_id, + manifest.str(&find_result.package.tarball_url), + dependency.behavior.isRequired(), + dependency_id, + package, + name_and_version_hash, + // its npm. + .allow_authorization, + ) orelse unreachable, + }, + }; }, .calc_patch_hash => .{ .package = package, @@ -4354,7 +4354,7 @@ pub const PackageManager = struct { package: Lockfile.Package, patch_name_and_version_hash: ?u64, authorization: NetworkTask.Authorization, - ) !?*NetworkTask { + ) NetworkTask.ForTarballError!?*NetworkTask { if (this.hasCreatedNetworkTask(task_id, is_required)) { return null; } @@ -4380,21 +4380,21 @@ pub const PackageManager = struct { this.allocator, &.{ .package_manager = this, - .name = try strings.StringOrTinyString.initAppendIfNeeded( + .name = strings.StringOrTinyString.initAppendIfNeeded( this.lockfile.str(&package.name), *FileSystem.FilenameStore, FileSystem.FilenameStore.instance, - ), + ) catch bun.outOfMemory(), .resolution = package.resolution, .cache_dir = this.getCacheDirectory(), .temp_dir = this.getTemporaryDirectory(), .dependency_id = dependency_id, .integrity = package.meta.integrity, - .url = try strings.StringOrTinyString.initAppendIfNeeded( + .url = strings.StringOrTinyString.initAppendIfNeeded( url, *FileSystem.FilenameStore, FileSystem.FilenameStore.instance, - ), + ) catch bun.outOfMemory(), }, scope, authorization, @@ -5344,15 +5344,13 @@ pub const PackageManager = struct { this.allocator, this.scopeForPackageName(name_str), if (loaded_manifest) |*manifest| manifest else null, - dependency.behavior.isOptional() or !this.options.do.install_peer_dependencies, + dependency.behavior.isOptional(), ); this.enqueueNetworkTask(network_task); } } else { - if (this.options.do.install_peer_dependencies) { - try this.peer_dependencies.writeItem(id); - return; - } + try this.peer_dependencies.writeItem(id); + return; } var manifest_entry_parse = try this.task_queue.getOrPutContext(this.allocator, task_id, .{}); @@ -5424,9 +5422,7 @@ pub const PackageManager = struct { if (dependency.behavior.isPeer()) { if (!install_peer) { - if (this.options.do.install_peer_dependencies) { - try this.peer_dependencies.writeItem(id); - } + try this.peer_dependencies.writeItem(id); return; } } @@ -5449,9 +5445,7 @@ pub const PackageManager = struct { if (dependency.behavior.isPeer()) { if (!install_peer) { - if (this.options.do.install_peer_dependencies) { - try this.peer_dependencies.writeItem(id); - } + try this.peer_dependencies.writeItem(id); return; } } @@ -5501,9 +5495,7 @@ pub const PackageManager = struct { if (dependency.behavior.isPeer()) { if (!install_peer) { - if (this.options.do.install_peer_dependencies) { - try this.peer_dependencies.writeItem(id); - } + try this.peer_dependencies.writeItem(id); return; } } @@ -5690,9 +5682,7 @@ pub const PackageManager = struct { if (dependency.behavior.isPeer()) { if (!install_peer) { - if (this.options.do.install_peer_dependencies) { - try this.peer_dependencies.writeItem(id); - } + try this.peer_dependencies.writeItem(id); return; } } @@ -7039,6 +7029,7 @@ pub const PackageManager = struct { .optional_dependencies = true, }, local_package_features: Features = .{ + .optional_dependencies = true, .dev_dependencies = true, .workspaces = true, }, @@ -7269,11 +7260,18 @@ pub const PackageManager = struct { if (config.save_dev) |save| { this.local_package_features.dev_dependencies = save; + // remote packages should never install dev dependencies + // (TODO: unless git dependency with postinstalls) + } + + if (config.save_optional) |save| { + this.remote_package_features.optional_dependencies = save; + this.local_package_features.optional_dependencies = save; } if (config.save_peer) |save| { - this.do.install_peer_dependencies = save; this.remote_package_features.peer_dependencies = save; + this.local_package_features.peer_dependencies = save; } if (config.exact) |exact| { @@ -7303,11 +7301,6 @@ pub const PackageManager = struct { this.max_concurrent_lifecycle_scripts = jobs; } - if (config.save_optional) |save| { - this.remote_package_features.optional_dependencies = save; - this.local_package_features.optional_dependencies = save; - } - this.explicit_global_directory = config.global_dir orelse this.explicit_global_directory; } @@ -7445,8 +7438,22 @@ pub const PackageManager = struct { this.enable.manifest_cache_control = false; } - if (cli.omit.dev) { - this.local_package_features.dev_dependencies = false; + if (cli.omit) |omit| { + if (omit.dev) { + this.local_package_features.dev_dependencies = false; + // remote packages should never install dev dependencies + // (TODO: unless git dependency with postinstalls) + } + + if (omit.optional) { + this.local_package_features.optional_dependencies = false; + this.remote_package_features.optional_dependencies = false; + } + + if (omit.peer) { + this.local_package_features.peer_dependencies = false; + this.remote_package_features.peer_dependencies = false; + } } if (cli.global or cli.ignore_scripts) { @@ -7461,8 +7468,6 @@ pub const PackageManager = struct { this.save_text_lockfile = save_text_lockfile; } - this.local_package_features.optional_dependencies = !cli.omit.optional; - const disable_progress_bar = default_disable_progress_bar or cli.no_progress; if (cli.verbose) { @@ -7568,7 +7573,6 @@ pub const PackageManager = struct { print_meta_hash_string: bool = false, verify_integrity: bool = true, summary: bool = true, - install_peer_dependencies: bool = true, trust_dependencies_from_args: bool = false, update_to_latest: bool = false, }; @@ -9434,6 +9438,7 @@ pub const PackageManager = struct { clap.parseParam("--concurrent-scripts Maximum number of concurrent jobs for lifecycle scripts (default 5)") catch unreachable, clap.parseParam("--network-concurrency Maximum number of concurrent network requests (default 48)") catch unreachable, clap.parseParam("--save-text-lockfile Save a text-based lockfile") catch unreachable, + clap.parseParam("--omit ... Exclude 'dev', 'optional', or 'peer' dependencies from install") catch unreachable, clap.parseParam("-h, --help Print this help menu") catch unreachable, }; @@ -9546,8 +9551,7 @@ pub const PackageManager = struct { development: bool = false, optional: bool = false, - no_optional: bool = false, - omit: Omit = Omit{}, + omit: ?Omit = null, exact: bool = false, @@ -9574,16 +9578,8 @@ pub const PackageManager = struct { const Omit = struct { dev: bool = false, - optional: bool = true, + optional: bool = false, peer: bool = false, - - pub inline fn toFeatures(this: Omit) Features { - return .{ - .dev_dependencies = this.dev, - .optional_dependencies = this.optional, - .peer_dependencies = this.peer, - }; - } }; pub fn printHelp(subcommand: Subcommand) void { @@ -9920,6 +9916,25 @@ pub const PackageManager = struct { cli.save_text_lockfile = true; } + const omit_values = args.options("--omit"); + + if (omit_values.len > 0) { + var omit: Omit = .{}; + for (omit_values) |omit_value| { + if (strings.eqlComptime(omit_value, "dev")) { + omit.dev = true; + } else if (strings.eqlComptime(omit_value, "optional")) { + omit.optional = true; + } else if (strings.eqlComptime(omit_value, "peer")) { + omit.peer = true; + } else { + Output.errGeneric("invalid `omit` value: '{s}'", .{omit_value}); + Global.crash(); + } + } + cli.omit = omit; + } + // commands that support --filter if (comptime subcommand.supportsWorkspaceFiltering()) { cli.filters = args.options("--filter"); @@ -12271,6 +12286,7 @@ pub const PackageManager = struct { options: *const PackageManager.Options, metas: []const Lockfile.Package.Meta, names: []const String, + pkg_dependencies: []const Lockfile.DependencySlice, pkg_name_hashes: []const PackageNameHash, bins: []const Bin, resolutions: []Resolution, @@ -12649,6 +12665,7 @@ pub const PackageManager = struct { this.pkg_name_hashes = packages.items(.name_hash); this.bins = packages.items(.bin); this.resolutions = packages.items(.resolution); + this.pkg_dependencies = packages.items(.dependencies); // fixes an assertion failure where a transitive dependency is a git dependency newly added to the lockfile after the list of dependencies has been resized // this assertion failure would also only happen after the lockfile has been written to disk and the summary is being printed. @@ -13084,7 +13101,14 @@ pub const PackageManager = struct { url, context, patch_name_and_version_hash, - ); + ) catch |err| switch (err) { + error.OutOfMemory => bun.outOfMemory(), + error.InvalidURL => this.failWithInvalidUrl( + pkg_has_patch, + is_pending_package_install, + log_level, + ), + }; }, .local_tarball => { this.manager.enqueueTarballForReading( @@ -13101,7 +13125,14 @@ pub const PackageManager = struct { resolution.value.remote_tarball.slice(this.lockfile.buffers.string_bytes.items), context, patch_name_and_version_hash, - ); + ) catch |err| switch (err) { + error.OutOfMemory => bun.outOfMemory(), + error.InvalidURL => this.failWithInvalidUrl( + pkg_has_patch, + is_pending_package_install, + log_level, + ), + }; }, .npm => { if (comptime Environment.isDebug) { @@ -13123,7 +13154,14 @@ pub const PackageManager = struct { resolution.value.npm.url.slice(this.lockfile.buffers.string_bytes.items), context, patch_name_and_version_hash, - ); + ) catch |err| switch (err) { + error.OutOfMemory => bun.outOfMemory(), + error.InvalidURL => this.failWithInvalidUrl( + pkg_has_patch, + is_pending_package_install, + log_level, + ), + }; }, else => { if (comptime Environment.allow_assert) { @@ -13414,6 +13452,16 @@ pub const PackageManager = struct { } } + fn failWithInvalidUrl( + this: *PackageInstaller, + pkg_has_patch: bool, + comptime is_pending_package_install: bool, + comptime log_level: Options.LogLevel, + ) void { + this.summary.fail += 1; + if (!pkg_has_patch) this.incrementTreeInstallCount(this.current_tree_id, null, !is_pending_package_install, log_level); + } + // returns true if scripts are enqueued fn enqueueLifecycleScripts( this: *PackageInstaller, @@ -13484,47 +13532,18 @@ pub const PackageManager = struct { pub fn installPackage( this: *PackageInstaller, - dependency_id: DependencyID, + dep_id: DependencyID, comptime log_level: Options.LogLevel, ) void { - this.installPackageImpl(dependency_id, log_level, true); - } - - pub fn installPackageImpl( - this: *PackageInstaller, - dependency_id: DependencyID, - comptime log_level: Options.LogLevel, - comptime increment_tree_count: bool, - ) void { - const package_id = this.lockfile.buffers.resolutions.items[dependency_id]; - const meta = &this.metas[package_id]; - const is_pending_package_install = false; - - if (meta.isDisabled()) { - if (comptime log_level.showProgress()) { - this.node.completeOne(); - } - if (comptime log_level.isVerbose()) { - const name = this.lockfile.str(&this.names[package_id]); - if (!meta.os.isMatch() and !meta.arch.isMatch()) { - Output.prettyErrorln("Skip installing '{s}' cpu & os mismatch", .{name}); - } else if (!meta.os.isMatch()) { - Output.prettyErrorln("Skip installing '{s}' os mismatch", .{name}); - } else if (!meta.arch.isMatch()) { - Output.prettyErrorln("Skip installing '{s}' cpu mismatch", .{name}); - } - } - - if (comptime increment_tree_count) this.incrementTreeInstallCount(this.current_tree_id, null, !is_pending_package_install, log_level); - return; - } + const package_id = this.lockfile.buffers.resolutions.items[dep_id]; const name = this.names[package_id]; const resolution = &this.resolutions[package_id]; const needs_verify = true; + const is_pending_package_install = false; this.installPackageWithNameAndResolution( - dependency_id, + dep_id, package_id, log_level, name, @@ -13587,6 +13606,8 @@ pub const PackageManager = struct { } } + const EnqueuePackageForDownloadError = NetworkTask.ForTarballError; + pub fn enqueuePackageForDownload( this: *PackageManager, name: []const u8, @@ -13596,23 +13617,23 @@ pub const PackageManager = struct { url: []const u8, task_context: TaskCallbackContext, patch_name_and_version_hash: ?u64, - ) void { + ) EnqueuePackageForDownloadError!void { const task_id = Task.Id.forNPMPackage(name, version); - var task_queue = this.task_queue.getOrPut(this.allocator, task_id) catch unreachable; + var task_queue = try this.task_queue.getOrPut(this.allocator, task_id); if (!task_queue.found_existing) { task_queue.value_ptr.* = .{}; } - task_queue.value_ptr.append( + try task_queue.value_ptr.append( this.allocator, task_context, - ) catch unreachable; + ); if (task_queue.found_existing) return; const is_required = this.lockfile.buffers.dependencies.items[dependency_id].behavior.isRequired(); - if (this.generateNetworkTaskForTarball( + if (try this.generateNetworkTaskForTarball( task_id, url, is_required, @@ -13620,7 +13641,7 @@ pub const PackageManager = struct { this.lockfile.packages.get(package_id), patch_name_and_version_hash, .allow_authorization, - ) catch unreachable) |task| { + )) |task| { task.schedule(&this.network_tarball_batch); if (this.network_tarball_batch.len > 0) { _ = this.scheduleTasks(); @@ -13628,6 +13649,8 @@ pub const PackageManager = struct { } } + const EnqueueTarballForDownloadError = NetworkTask.ForTarballError; + pub fn enqueueTarballForDownload( this: *PackageManager, dependency_id: DependencyID, @@ -13635,21 +13658,21 @@ pub const PackageManager = struct { url: string, task_context: TaskCallbackContext, patch_name_and_version_hash: ?u64, - ) void { + ) EnqueueTarballForDownloadError!void { const task_id = Task.Id.forTarball(url); - var task_queue = this.task_queue.getOrPut(this.allocator, task_id) catch unreachable; + var task_queue = try this.task_queue.getOrPut(this.allocator, task_id); if (!task_queue.found_existing) { task_queue.value_ptr.* = .{}; } - task_queue.value_ptr.append( + try task_queue.value_ptr.append( this.allocator, task_context, - ) catch unreachable; + ); if (task_queue.found_existing) return; - if (this.generateNetworkTaskForTarball( + if (try this.generateNetworkTaskForTarball( task_id, url, this.lockfile.buffers.dependencies.items[dependency_id].behavior.isRequired(), @@ -13657,7 +13680,7 @@ pub const PackageManager = struct { this.lockfile.packages.get(package_id), patch_name_and_version_hash, .no_authorization, - ) catch unreachable) |task| { + )) |task| { task.schedule(&this.network_tarball_batch); if (this.network_tarball_batch.len > 0) { _ = this.scheduleTasks(); @@ -13721,15 +13744,14 @@ pub const PackageManager = struct { ctx: Command.Context, comptime log_level: PackageManager.Options.LogLevel, ) !PackageInstall.Summary { - const original_lockfile = this.lockfile; - defer this.lockfile = original_lockfile; - if (!this.options.local_package_features.dev_dependencies) { - this.lockfile = try this.lockfile.maybeCloneFilteringRootPackages( - this, - this.options.local_package_features, - this.options.enable.exact_versions, - log_level, - ); + const original_trees = this.lockfile.buffers.trees; + const original_tree_dep_ids = this.lockfile.buffers.hoisted_dependencies; + + try this.lockfile.hoist(this.log, .filter, this); + + defer { + this.lockfile.buffers.trees = original_trees; + this.lockfile.buffers.hoisted_dependencies = original_tree_dep_ids; } var root_node: *Progress.Node = undefined; @@ -13744,7 +13766,7 @@ pub const PackageManager = struct { root_node = progress.start("", 0); download_node = root_node.start(ProgressStrings.download(), 0); - install_node = root_node.start(ProgressStrings.install(), this.lockfile.packages.len); + install_node = root_node.start(ProgressStrings.install(), this.lockfile.buffers.hoisted_dependencies.items.len); scripts_node = root_node.start(ProgressStrings.script(), 0); this.downloads_node = &download_node; this.scripts_node = &scripts_node; @@ -13795,9 +13817,7 @@ pub const PackageManager = struct { skip_delete = false; } - var summary = PackageInstall.Summary{ - .lockfile_used_for_install = this.lockfile, - }; + var summary = PackageInstall.Summary{}; { var iterator = Lockfile.Tree.Iterator(.node_modules).init(this.lockfile); @@ -13895,6 +13915,7 @@ pub const PackageManager = struct { .names = parts.items(.name), .pkg_name_hashes = parts.items(.name_hash), .resolutions = parts.items(.resolution), + .pkg_dependencies = parts.items(.dependencies), .lockfile = this.lockfile, .node = &install_node, .node_modules = .{ @@ -14671,9 +14692,7 @@ pub const PackageManager = struct { try waitForEverythingExceptPeers(manager); } - if (manager.options.do.install_peer_dependencies) { - try waitForPeers(manager); - } + try waitForPeers(manager); if (comptime log_level.showProgress()) { manager.endProgressBar(); @@ -14802,9 +14821,7 @@ pub const PackageManager = struct { const lockfile_before_install = manager.lockfile; - var install_summary = PackageInstall.Summary{ - .lockfile_used_for_install = manager.lockfile, - }; + var install_summary = PackageInstall.Summary{}; if (manager.options.do.install_packages) { install_summary = try manager.installPackages( ctx, @@ -14968,7 +14985,7 @@ pub const PackageManager = struct { if (comptime log_level != .silent) { if (manager.options.do.summary) { var printer = Lockfile.Printer{ - .lockfile = install_summary.lockfile_used_for_install, + .lockfile = manager.lockfile, .options = manager.options, .updates = manager.update_requests, .successfully_installed = install_summary.successfully_installed, @@ -15088,6 +15105,7 @@ pub const PackageManager = struct { const lockfile = this.lockfile; const resolutions_lists: []const Lockfile.DependencyIDSlice = lockfile.packages.items(.resolutions); const dependency_lists: []const Lockfile.DependencySlice = lockfile.packages.items(.dependencies); + const pkg_resolutions = lockfile.packages.items(.resolution); const dependencies_buffer = lockfile.buffers.dependencies.items; const resolutions_buffer = lockfile.buffers.resolutions.items; const end: PackageID = @truncate(lockfile.packages.len); @@ -15095,7 +15113,6 @@ pub const PackageManager = struct { var any_failed = false; const string_buf = lockfile.buffers.string_bytes.items; - const root_list = resolutions_lists[0]; for (resolutions_lists, dependency_lists, 0..) |resolution_list, dependency_list, parent_id| { for (resolution_list.get(resolutions_buffer), dependency_list.get(dependencies_buffer)) |package_id, failed_dep| { if (package_id < end) continue; @@ -15104,13 +15121,13 @@ pub const PackageManager = struct { // Need to keep this for now because old lockfiles might have a peer dependency without the optional flag set. if (failed_dep.behavior.isPeer()) continue; + const features = switch (pkg_resolutions[parent_id].tag) { + .root, .workspace, .folder => this.options.local_package_features, + else => this.options.remote_package_features, + }; // even if optional dependencies are enabled, it's still allowed to fail - if (failed_dep.behavior.optional or !failed_dep.behavior.isEnabled( - if (root_list.contains(@truncate(parent_id))) - this.options.local_package_features - else - this.options.remote_package_features, - )) continue; + if (failed_dep.behavior.optional or !failed_dep.behavior.isEnabled(features)) continue; + if (log_level != .silent) { if (failed_dep.name.isEmpty() or strings.eqlLong(failed_dep.name.slice(string_buf), failed_dep.version.literal.slice(string_buf), true)) { Output.errGeneric("{} failed to resolve", .{ diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index d6f7f7e3c9..515cc803ad 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -373,15 +373,23 @@ pub fn loadFromDir( switch (result) { .ok => { - if (bun.getenvZ("BUN_DEBUG_TEST_TEXT_LOCKFILE") != null) { + if (bun.getenvZ("BUN_DEBUG_TEST_TEXT_LOCKFILE") != null and manager != null) { // Convert the loaded binary lockfile into a text lockfile in memory, then // parse it back into a binary lockfile. - const text_lockfile_bytes = TextLockfile.Stringifier.saveFromBinary(allocator, result.ok.lockfile) catch |err| { + var writer_buf = MutableString.initEmpty(allocator); + var buffered_writer = writer_buf.bufferedWriter(); + const writer = buffered_writer.writer(); + + TextLockfile.Stringifier.saveFromBinary(allocator, result.ok.lockfile, writer) catch |err| { Output.panic("failed to convert binary lockfile to text lockfile: {s}", .{@errorName(err)}); }; + buffered_writer.flush() catch bun.outOfMemory(); + + const text_lockfile_bytes = writer_buf.list.items; + const source = logger.Source.initPathString("bun.lock", text_lockfile_bytes); initializeStore(); const json = JSON.parsePackageJSONUTF8(&source, log, allocator) catch |err| { @@ -485,7 +493,7 @@ pub const Tree = struct { pub const root_dep_id: DependencyID = invalid_package_id - 1; pub const invalid_id: Id = std.math.maxInt(Id); - pub const HoistResult = union(enum) { + pub const HoistDependencyResult = union(enum) { dependency_loop, hoisted, dest_id: Id, @@ -652,82 +660,96 @@ pub const Tree = struct { return .{ rel, depth }; } - const Builder = struct { - allocator: Allocator, - name_hashes: []const PackageNameHash, - list: bun.MultiArrayList(Entry) = .{}, - resolutions: []const PackageID, - dependencies: []const Dependency, - resolution_lists: []const Lockfile.DependencyIDSlice, - queue: Lockfile.TreeFiller, - log: *logger.Log, - lockfile: *Lockfile, - prefer_dev_dependencies: bool = false, - sort_buf: std.ArrayListUnmanaged(DependencyID) = .{}, + const BuilderMethod = enum { + /// Hoist, but include every dependency so it's resolvable if configuration + /// changes. For saving to disk. + resolvable, - pub fn maybeReportError(this: *Builder, comptime fmt: string, args: anytype) void { - this.log.addErrorFmt(null, logger.Loc.Empty, this.allocator, fmt, args) catch {}; - } - - pub fn buf(this: *const Builder) []const u8 { - return this.lockfile.buffers.string_bytes.items; - } - - pub fn packageName(this: *Builder, id: PackageID) String.Formatter { - return this.lockfile.packages.items(.name)[id].fmt(this.lockfile.buffers.string_bytes.items); - } - - pub fn packageVersion(this: *Builder, id: PackageID) Resolution.Formatter { - return this.lockfile.packages.items(.resolution)[id].fmt(this.lockfile.buffers.string_bytes.items, .auto); - } - - pub const Entry = struct { - tree: Tree, - dependencies: Lockfile.DependencyIDList, - }; - - /// Flatten the multi-dimensional ArrayList of package IDs into a single easily serializable array - pub fn clean(this: *Builder) !DependencyIDList { - const end = @as(Id, @truncate(this.list.len)); - var i: Id = 0; - var total: u32 = 0; - const trees = this.list.items(.tree); - const dependencies = this.list.items(.dependencies); - - while (i < end) : (i += 1) { - total += trees[i].dependencies.len; - } - - var dependency_ids = try DependencyIDList.initCapacity(z_allocator, total); - var next = PackageIDSlice{}; - - for (trees, dependencies) |*tree, *child| { - if (tree.dependencies.len > 0) { - const len = @as(PackageID, @truncate(child.items.len)); - next.off += next.len; - next.len = len; - tree.dependencies = next; - dependency_ids.appendSliceAssumeCapacity(child.items); - child.deinit(this.allocator); - } - } - this.queue.deinit(); - this.sort_buf.deinit(this.allocator); - - return dependency_ids; - } + /// This will filter out disabled dependencies, resulting in more aggresive + /// hoisting compared to `hoist()`. We skip dependencies based on 'os', 'cpu', + /// 'libc' (TODO), and omitted dependency types (`--omit=dev/peer/optional`). + /// Dependencies of a disabled package are not included in the output. + filter, }; + pub fn Builder(comptime method: BuilderMethod) type { + return struct { + allocator: Allocator, + name_hashes: []const PackageNameHash, + list: bun.MultiArrayList(Entry) = .{}, + resolutions: []const PackageID, + dependencies: []const Dependency, + resolution_lists: []const Lockfile.DependencyIDSlice, + queue: Lockfile.TreeFiller, + log: *logger.Log, + lockfile: *const Lockfile, + manager: if (method == .filter) *const PackageManager else void, + sort_buf: std.ArrayListUnmanaged(DependencyID) = .{}, + + pub fn maybeReportError(this: *@This(), comptime fmt: string, args: anytype) void { + this.log.addErrorFmt(null, logger.Loc.Empty, this.allocator, fmt, args) catch {}; + } + + pub fn buf(this: *const @This()) []const u8 { + return this.lockfile.buffers.string_bytes.items; + } + + pub fn packageName(this: *@This(), id: PackageID) String.Formatter { + return this.lockfile.packages.items(.name)[id].fmt(this.lockfile.buffers.string_bytes.items); + } + + pub fn packageVersion(this: *@This(), id: PackageID) Resolution.Formatter { + return this.lockfile.packages.items(.resolution)[id].fmt(this.lockfile.buffers.string_bytes.items, .auto); + } + + pub const Entry = struct { + tree: Tree, + dependencies: Lockfile.DependencyIDList, + }; + + /// Flatten the multi-dimensional ArrayList of package IDs into a single easily serializable array + pub fn clean(this: *@This()) OOM!DependencyIDList { + var total: u32 = 0; + const trees = this.list.items(.tree); + const dependencies = this.list.items(.dependencies); + + for (trees) |*tree| { + total += tree.dependencies.len; + } + + var dependency_ids = try DependencyIDList.initCapacity(z_allocator, total); + var next = PackageIDSlice{}; + + for (trees, dependencies) |*tree, *child| { + if (tree.dependencies.len > 0) { + const len = @as(PackageID, @truncate(child.items.len)); + next.off += next.len; + next.len = len; + tree.dependencies = next; + dependency_ids.appendSliceAssumeCapacity(child.items); + child.deinit(this.allocator); + } + } + this.queue.deinit(); + this.sort_buf.deinit(this.allocator); + + return dependency_ids; + } + }; + } + pub fn processSubtree( this: *const Tree, dependency_id: DependencyID, - builder: *Builder, + comptime method: BuilderMethod, + builder: *Builder(method), + log_level: if (method == .filter) PackageManager.Options.LogLevel else void, ) SubtreeError!void { - const package_id = switch (dependency_id) { + const parent_pkg_id = switch (dependency_id) { root_dep_id => 0, else => |id| builder.resolutions[id], }; - const resolution_list = builder.resolution_lists[package_id]; + const resolution_list = builder.resolution_lists[parent_pkg_id]; if (resolution_list.len == 0) return; @@ -746,7 +768,11 @@ pub const Tree = struct { const next: *Tree = &trees[builder.list.len - 1]; const name_hashes: []const PackageNameHash = builder.name_hashes; const max_package_id = @as(PackageID, @truncate(name_hashes.len)); - const resolutions = builder.lockfile.packages.items(.resolution); + + const pkgs = builder.lockfile.packages.slice(); + const pkg_resolutions = pkgs.items(.resolution); + const pkg_metas = pkgs.items(.meta); + const pkg_names = pkgs.items(.name); builder.sort_buf.clearRetainingCapacity(); try builder.sort_buf.ensureUnusedCapacity(builder.allocator, resolution_list.len); @@ -783,21 +809,48 @@ pub const Tree = struct { ); for (builder.sort_buf.items) |dep_id| { - const pid = builder.resolutions[dep_id]; + const pkg_id = builder.resolutions[dep_id]; // Skip unresolved packages, e.g. "peerDependencies" - if (pid >= max_package_id) continue; + if (pkg_id >= max_package_id) continue; + + // filter out disabled dependencies + if (comptime method == .filter) { + if (builder.lockfile.isPackageDisabled( + dep_id, + switch (pkg_resolutions[parent_pkg_id].tag) { + .root, .workspace, .folder => builder.manager.options.local_package_features, + else => builder.manager.options.remote_package_features, + }, + &pkg_metas[pkg_id], + )) { + if (log_level.isVerbose()) { + const meta = &pkg_metas[pkg_id]; + const name = builder.lockfile.str(&pkg_names[pkg_id]); + if (!meta.os.isMatch() and !meta.arch.isMatch()) { + Output.prettyErrorln("Skip installing '{s}' cpu & os mismatch", .{name}); + } else if (!meta.os.isMatch()) { + Output.prettyErrorln("Skip installing '{s}' os mismatch", .{name}); + } else if (!meta.arch.isMatch()) { + Output.prettyErrorln("Skip installing '{s}' cpu mismatch", .{name}); + } + } + + continue; + } + } const dependency = builder.dependencies[dep_id]; // Do not hoist folder dependencies - const res: HoistResult = if (resolutions[pid].tag == .folder) + const res: HoistDependencyResult = if (pkg_resolutions[pkg_id].tag == .folder) .{ .dest_id = next.id } else try next.hoistDependency( true, - pid, + pkg_id, &dependency, dependency_lists, trees, + method, builder, ); @@ -815,7 +868,7 @@ pub const Tree = struct { .dest_id => |dest_id| { dependency_lists[dest_id].append(builder.allocator, dep_id) catch bun.outOfMemory(); trees[dest_id].dependencies.len += 1; - if (builder.resolution_lists[pid].len > 0) { + if (builder.resolution_lists[pkg_id].len > 0) { try builder.queue.writeItem(.{ .tree_id = dest_id, .dependency_id = dep_id, @@ -843,8 +896,9 @@ pub const Tree = struct { dependency: *const Dependency, dependency_lists: []Lockfile.DependencyIDList, trees: []Tree, - builder: *Builder, - ) !HoistResult { + comptime method: BuilderMethod, + builder: *Builder(method), + ) !HoistDependencyResult { const this_dependencies = this.dependencies.get(dependency_lists[this.id].items); for (0..this_dependencies.len) |i| { const dep_id = this_dependencies[i]; @@ -857,14 +911,11 @@ pub const Tree = struct { } if (comptime as_defined) { - // same dev dependency as another package in the same package.json, but different version. - // choose dev dep over other if enabled if (dep.behavior.isDev() != dependency.behavior.isDev()) { - if (builder.prefer_dev_dependencies and dep.behavior.isDev()) { - return .hoisted; // 1 - } - - return .dependency_loop; // 3 + // will only happen in workspaces and root package because + // dev dependencies won't be included in other types of + // dependencies + return .hoisted; // 1 } } @@ -911,6 +962,7 @@ pub const Tree = struct { dependency, dependency_lists, trees, + method, builder, ) catch unreachable; if (!as_defined or id != .dependency_loop) return id; // 1 or 2 @@ -921,6 +973,19 @@ pub const Tree = struct { } }; +pub fn isPackageDisabled( + lockfile: *const Lockfile, + dep_id: DependencyID, + features: Features, + meta: *const Package.Meta, +) bool { + if (meta.isDisabled()) return true; + + const dep = lockfile.buffers.dependencies.items[dep_id]; + + return !dep.behavior.isEnabled(features); +} + /// This conditionally clones the lockfile with root packages marked as non-resolved /// that do not satisfy `Features`. The package may still end up installed even /// if it was e.g. in "devDependencies" and its a production install. In that case, @@ -1383,7 +1448,7 @@ const Cloner = struct { this.manager.clearCachedItemsDependingOnLockfileBuffer(); if (this.lockfile.packages.len != 0) { - try this.lockfile.hoist(this.log, this.manager.options.local_package_features.dev_dependencies); + try this.lockfile.hoist(this.log, .resolvable, {}); } // capacity is used for calculating byte size @@ -1393,10 +1458,15 @@ const Cloner = struct { } }; -pub fn hoist(lockfile: *Lockfile, log: *logger.Log, prefer_dev_dependencies: bool) Tree.SubtreeError!void { +pub fn hoist( + lockfile: *Lockfile, + log: *logger.Log, + comptime method: Tree.BuilderMethod, + manager: if (method == .filter) *PackageManager else void, +) Tree.SubtreeError!void { const allocator = lockfile.allocator; var slice = lockfile.packages.slice(); - var builder = Tree.Builder{ + var builder = Tree.Builder(method){ .name_hashes = slice.items(.name_hash), .queue = TreeFiller.init(allocator), .resolution_lists = slice.items(.resolutions), @@ -1405,23 +1475,17 @@ pub fn hoist(lockfile: *Lockfile, log: *logger.Log, prefer_dev_dependencies: boo .dependencies = lockfile.buffers.dependencies.items, .log = log, .lockfile = lockfile, - .prefer_dev_dependencies = prefer_dev_dependencies, + .manager = manager, }; - try (Tree{}).processSubtree(Tree.root_dep_id, &builder); + try (Tree{}).processSubtree(Tree.root_dep_id, method, &builder, if (method == .filter) manager.options.log_level else {}); // This goes breadth-first while (builder.queue.readItem()) |item| { - try builder.list.items(.tree)[item.tree_id].processSubtree(item.dependency_id, &builder); + try builder.list.items(.tree)[item.tree_id].processSubtree(item.dependency_id, method, &builder, if (method == .filter) manager.options.log_level else {}); } + lockfile.buffers.trees = std.ArrayListUnmanaged(Tree).fromOwnedSlice(builder.list.items(.tree)); lockfile.buffers.hoisted_dependencies = try builder.clean(); - { - const final = builder.list.items(.tree); - lockfile.buffers.trees = .{ - .items = final, - .capacity = final.len, - }; - } } const PendingResolution = struct { @@ -1581,6 +1645,7 @@ pub const Printer = struct { const dependencies = lockfile.buffers.dependencies.items; const workspace_res = packages_slice.items(.resolution)[workspace_package_id]; const names = packages_slice.items(.name); + const pkg_metas = packages_slice.items(.meta); bun.assert(workspace_res.tag == .workspace or workspace_res.tag == .root); const resolutions_list = packages_slice.items(.resolutions); var printed_section_header = false; @@ -1588,7 +1653,7 @@ pub const Printer = struct { // find the updated packages for (resolutions_list[workspace_package_id].begin()..resolutions_list[workspace_package_id].end()) |dep_id| { - switch (shouldPrintPackageInstall(this, manager, @intCast(dep_id), installed, id_map)) { + switch (shouldPrintPackageInstall(this, manager, @intCast(dep_id), installed, id_map, pkg_metas)) { .yes, .no, .@"return" => {}, .update => |update_info| { printed_new_install.* = true; @@ -1610,7 +1675,7 @@ pub const Printer = struct { } for (resolutions_list[workspace_package_id].begin()..resolutions_list[workspace_package_id].end()) |dep_id| { - switch (shouldPrintPackageInstall(this, manager, @intCast(dep_id), installed, id_map)) { + switch (shouldPrintPackageInstall(this, manager, @intCast(dep_id), installed, id_map, pkg_metas)) { .@"return" => return, .yes => {}, .no, .update => continue, @@ -1659,6 +1724,7 @@ pub const Printer = struct { dep_id: DependencyID, installed: *const Bitset, id_map: ?[]DependencyID, + pkg_metas: []const Package.Meta, ) ShouldPrintPackageInstallResult { const dependencies = this.lockfile.buffers.dependencies.items; const resolutions = this.lockfile.buffers.resolutions.items; @@ -1682,6 +1748,17 @@ pub const Printer = struct { if (!installed.isSet(package_id)) return .no; + // It's possible this package was installed but the dependency is disabled. + // Have "zod@1.0.0" in dependencies and `zod2@npm:zod@1.0.0` in devDependencies + // and install with --omit=dev. + if (this.lockfile.isPackageDisabled( + dep_id, + this.options.local_package_features, + &pkg_metas[package_id], + )) { + return .no; + } + const resolution = this.lockfile.packages.items(.resolution)[package_id]; if (resolution.tag == .npm) { const name = dependency.name.slice(this.lockfile.buffers.string_bytes.items); @@ -1801,6 +1878,7 @@ pub const Printer = struct { if (resolved.len == 0) return; const string_buf = this.lockfile.buffers.string_bytes.items; const resolutions_list = slice.items(.resolutions); + const pkg_metas = slice.items(.meta); const resolutions_buffer: []const PackageID = this.lockfile.buffers.resolutions.items; const dependencies_buffer: []const Dependency = this.lockfile.buffers.dependencies.items; if (dependencies_buffer.len == 0) return; @@ -1827,7 +1905,7 @@ pub const Printer = struct { for (workspaces_to_print.items) |workspace_dep_id| { const workspace_package_id = resolutions_buffer[workspace_dep_id]; for (resolutions_list[workspace_package_id].begin()..resolutions_list[workspace_package_id].end()) |dep_id| { - switch (shouldPrintPackageInstall(this, manager, @intCast(dep_id), installed, id_map)) { + switch (shouldPrintPackageInstall(this, manager, @intCast(dep_id), installed, id_map, pkg_metas)) { .yes => found_workspace_to_print = true, else => {}, } @@ -2242,13 +2320,23 @@ pub fn saveToDisk(this: *Lockfile, save_format: LoadResult.LockfileFormat, verbo assert(FileSystem.instance_loaded); } - const bytes = if (save_format == .text) - TextLockfile.Stringifier.saveFromBinary(bun.default_allocator, this) catch |err| { - switch (err) { + const bytes = bytes: { + if (save_format == .text) { + var writer_buf = MutableString.initEmpty(bun.default_allocator); + var buffered_writer = writer_buf.bufferedWriter(); + const writer = buffered_writer.writer(); + + TextLockfile.Stringifier.saveFromBinary(bun.default_allocator, this, writer) catch |err| switch (err) { error.OutOfMemory => bun.outOfMemory(), - } + }; + + buffered_writer.flush() catch |err| switch (err) { + error.OutOfMemory => bun.outOfMemory(), + }; + + break :bytes writer_buf.list.items; } - else bytes: { + var bytes = std.ArrayList(u8).init(bun.default_allocator); var total_size: usize = 0; diff --git a/src/install/migration.zig b/src/install/migration.zig index 5e3688865c..f57c59fb79 100644 --- a/src/install/migration.zig +++ b/src/install/migration.zig @@ -1019,7 +1019,7 @@ pub fn migrateNPMLockfile( return error.NotAllPackagesGotResolved; } - try this.hoist(log, manager.options.local_package_features.dev_dependencies); + try this.hoist(log, .resolvable, {}); // if (Environment.isDebug) { // const dump_file = try std.fs.cwd().createFileZ("after-clean.json", .{}); diff --git a/src/install/patch_install.zig b/src/install/patch_install.zig index cb8b932aa1..842ca4a01f 100644 --- a/src/install/patch_install.zig +++ b/src/install/patch_install.zig @@ -211,12 +211,13 @@ pub const PatchTask = struct { }, .extract => { debug("pkg: {s} extract", .{pkg.name.slice(manager.lockfile.buffers.string_bytes.items)}); + + const task_id = Task.Id.forNPMPackage(manager.lockfile.str(&pkg.name), pkg.resolution.value.npm.version); + bun.debugAssert(!manager.network_dedupe_map.contains(task_id)); + const network_task = try manager.generateNetworkTaskForTarball( // TODO: not just npm package - Task.Id.forNPMPackage( - manager.lockfile.str(&pkg.name), - pkg.resolution.value.npm.version, - ), + task_id, url, manager.lockfile.buffers.dependencies.items[dep_id].behavior.isRequired(), dep_id, diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index c765c9f79b..bf87b29dad 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -1939,7 +1939,7 @@ pub const Resolver = struct { .root_request_id = 0, }, null, - ); + ) catch |enqueue_download_err| return .{ .failure = enqueue_download_err }; return .{ .pending = .{ diff --git a/test/cli/install/bun-install.test.ts b/test/cli/install/bun-install.test.ts index 9097867d4f..70addfbf37 100644 --- a/test/cli/install/bun-install.test.ts +++ b/test/cli/install/bun-install.test.ts @@ -22,6 +22,7 @@ import { toHaveBins, runBunInstall, isWindows, + textLockfile, } from "harness"; import { join, sep, resolve } from "path"; import { @@ -1122,59 +1123,6 @@ it("should handle inter-dependency between workspaces (optionalDependencies)", a await access(join(package_dir, "bun.lockb")); }); -it("should ignore peerDependencies within workspaces", async () => { - await writeFile( - join(package_dir, "package.json"), - JSON.stringify({ - name: "Foo", - version: "0.0.1", - workspaces: ["packages/baz"], - peerDependencies: { - Bar: ">=0.0.2", - }, - }), - ); - await mkdir(join(package_dir, "packages", "baz"), { recursive: true }); - await writeFile( - join(package_dir, "packages", "baz", "package.json"), - JSON.stringify({ - name: "Baz", - version: "0.0.3", - peerDependencies: { - Moo: ">=0.0.4", - }, - }), - ); - await writeFile( - join(package_dir, "bunfig.toml"), - ` - [install] - peer = false - `, - ); - const { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "install"], - cwd: package_dir, - stdout: "pipe", - stdin: "pipe", - stderr: "pipe", - env, - }); - const err = await new Response(stderr).text(); - expect(err).toContain("Saved lockfile"); - const out = await new Response(stdout).text(); - expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ - expect.stringContaining("bun install v1."), - "", - "1 package installed", - ]); - expect(await exited).toBe(0); - expect(requested).toBe(0); - expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual(["Baz"]); - expect(package_dir).toHaveWorkspaceLink(["Baz", "packages/baz"]); - await access(join(package_dir, "bun.lockb")); -}); - it("should handle installing the same peerDependency with different versions", async () => { const urls: string[] = []; setHandler(dummyRegistry(urls)); @@ -8458,3 +8406,133 @@ saveTextLockfile = true expect(await exists(join(package_dir, "bun.lockb"))).toBeFalse(); expect(await file(join(package_dir, "bun.lock")).text()).toMatchSnapshot(); }); + +test("providing invalid url in lockfile does not crash", async () => { + await Promise.all([ + write( + join(package_dir, "package.json"), + JSON.stringify({ + dependencies: { + "jquery": "3.7.1", + }, + }), + ), + write( + join(package_dir, "bun.lock"), + textLockfile(0, { + "workspaces": { + "": { + "dependencies": { + "jquery": "3.7.1", + }, + }, + }, + "packages": { + "jquery": [ + "jquery@3.7.1", + "invalid-url", + {}, + "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + ], + }, + }), + ), + ]); + + const { stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: package_dir, + stderr: "pipe", + env, + }); + + const err = await Bun.readableStreamToText(stderr); + expect(err).toContain( + 'error: Expected tarball URL to start with https:// or http://, got "invalid-url" while fetching package "jquery"', + ); + expect(await exited).toBe(1); +}); + +test("optional dependencies do not need to be resolvable in text lockfile", async () => { + await Promise.all([ + write( + join(package_dir, "package.json"), + JSON.stringify({ + optionalDependencies: { + jquery: "3.7.1", + }, + }), + ), + write( + join(package_dir, "bun.lock"), + textLockfile(0, { + "workspaces": { + "": { + "optionalDependencies": { + "jquery": "3.7.1", + }, + }, + }, + "packages": {}, + }), + ), + ]); + + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: package_dir, + stdout: "pipe", + stderr: "pipe", + env, + }); + + const err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("Saved lockfile"); + const out = await Bun.readableStreamToText(stdout); + expect(out).not.toContain("1 package installed"); + + expect(await exited).toBe(0); +}); + +test("non-optional dependencies need to be resolvable in text lockfile", async () => { + await Promise.all([ + write( + join(package_dir, "package.json"), + JSON.stringify({ + dependencies: { + jquery: "3.7.1", + }, + }), + ), + write( + join(package_dir, "bun.lock"), + textLockfile(0, { + workspaces: { + "": { + dependencies: { + "jquery": "3.7.1", + }, + }, + }, + packages: {}, + }), + ), + ]); + + const { stdout, stderr, exited } = spawn({ + // --production to fail early + cmd: [bunExe(), "install", "--production"], + cwd: package_dir, + stdout: "pipe", + stderr: "pipe", + env, + }); + + const err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("Saved lockfile"); + expect(err).toContain("error: Failed to resolve root prod dependency 'jquery'"); + const out = await Bun.readableStreamToText(stdout); + expect(out).not.toContain("1 package installed"); + + expect(await exited).toBe(1); +}); diff --git a/test/cli/install/bun-run.test.ts b/test/cli/install/bun-run.test.ts index 52954e16c5..99293d6013 100644 --- a/test/cli/install/bun-run.test.ts +++ b/test/cli/install/bun-run.test.ts @@ -275,7 +275,7 @@ console.log(minify("print(6 * 7)").code); BUN_INSTALL_CACHE_DIR: join(run_dir, ".cache"), }, }); - const err1 = await new Response(stderr1).text(); + const err1 = stderrForInstall(await new Response(stderr1).text()); expect(err1).toBe(""); expect(await readdirSorted(run_dir)).toEqual([".cache", "test.js"]); expect(await readdirSorted(join(run_dir, ".cache"))).toContain("uglify-js"); @@ -339,7 +339,7 @@ for (const entry of await decompress(Buffer.from(buffer))) { BUN_INSTALL_CACHE_DIR: join(run_dir, ".cache"), }, }); - const err1 = await new Response(stderr1).text(); + const err1 = stderrForInstall(await new Response(stderr1).text()); expect(err1).toBe(""); expect(await readdirSorted(run_dir)).toEqual([".cache", "test.js"]); expect(await readdirSorted(join(run_dir, ".cache"))).toContain("decompress"); diff --git a/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap b/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap index a58e5d1e73..9d2bebfe0c 100644 --- a/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap +++ b/test/cli/install/registry/__snapshots__/bun-install-registry.test.ts.snap @@ -311,3 +311,30 @@ exports[`hoisting text lockfile is hoisted 1`] = ` } " `; + +exports[`it should ignore peerDependencies within workspaces 1`] = ` +"{ + "lockfileVersion": 0, + "workspaces": { + "": { + "peerDependencies": { + "no-deps": ">=1.0.0", + }, + }, + "packages/baz": { + "name": "Baz", + "peerDependencies": { + "a-dep": ">=1.0.1", + }, + }, + }, + "packages": { + "Baz": ["Baz@workspace:packages/baz", { "peerDependencies": { "a-dep": ">=1.0.1" } }], + + "a-dep": ["a-dep@1.0.10", "http://localhost:1234/a-dep/-/a-dep-1.0.10.tgz", {}, "sha512-NeQ6Ql9jRW8V+VOiVb+PSQAYOvVoSimW+tXaR0CoJk4kM9RIk/XlAUGCsNtn5XqjlDO4hcH8NcyaL507InevEg=="], + + "no-deps": ["no-deps@2.0.0", "http://localhost:1234/no-deps/-/no-deps-2.0.0.tgz", {}, "sha512-W3duJKZPcMIG5rA1io5cSK/bhW9rWFz+jFxZsKS/3suK4qHDkQNxUTEXee9/hTaAoDCeHWQqogukWYKzfr6X4g=="], + } +} +" +`; diff --git a/test/cli/install/registry/bun-install-registry.test.ts b/test/cli/install/registry/bun-install-registry.test.ts index 18474bcb0c..00248aa9c6 100644 --- a/test/cli/install/registry/bun-install-registry.test.ts +++ b/test/cli/install/registry/bun-install-registry.test.ts @@ -1838,6 +1838,64 @@ describe("text lockfile", () => { expect(await Bun.file(join(packageDir, "bun.lock")).text()).toBe(firstLockfile); }); + + for (const omit of ["dev", "peer", "optional"]) { + test(`resolvable lockfile with ${omit} dependencies disabled`, async () => { + await Promise.all([ + write( + join(packageDir, "package.json"), + JSON.stringify({ + name: "foo", + peerDependencies: { "no-deps": "1.0.0" }, + devDependencies: { "a-dep": "1.0.1" }, + optionalDependencies: { "basic-1": "1.0.0" }, + }), + ), + ]); + + let { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile", `--omit=${omit}`], + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env, + }); + + let err = await Bun.readableStreamToText(stderr); + expect(err).toContain("Saved lockfile"); + expect(err).not.toContain("error:"); + + expect(await exited).toBe(0); + + const depName = omit === "dev" ? "a-dep" : omit === "peer" ? "no-deps" : "basic-1"; + + expect(await exists(join(packageDir, "node_modules", depName))).toBeFalse(); + + const lockfile = (await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + + ({ stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env, + })); + + err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("Saved lockfile"); + expect(err).not.toContain("error:"); + expect(await exited).toBe(0); + + expect(await exists(join(packageDir, "node_modules", depName))).toBeTrue(); + + expect((await Bun.file(join(packageDir, "bun.lock")).text()).replaceAll(/localhost:\d+/g, "localhost:1234")).toBe( + lockfile, + ); + }); + } }); describe("optionalDependencies", () => { @@ -1974,6 +2032,71 @@ describe("optionalDependencies", () => { }); }); +test("it should ignore peerDependencies within workspaces", async () => { + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "foo", + workspaces: ["packages/baz"], + peerDependencies: { + "no-deps": ">=1.0.0", + }, + }), + ), + write( + join(packageDir, "packages", "baz", "package.json"), + JSON.stringify({ + name: "Baz", + peerDependencies: { + "a-dep": ">=1.0.1", + }, + }), + ), + write(join(packageDir, ".npmrc"), `omit=peer`), + ]); + + const { exited } = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile"], + cwd: packageDir, + env, + }); + + expect(await exited).toBe(0); + + expect(await readdirSorted(join(packageDir, "node_modules"))).toEqual(["Baz"]); + expect( + (await file(join(packageDir, "bun.lock")).text()).replaceAll(/localhost:\d+/g, "localhost:1234"), + ).toMatchSnapshot(); + + // installing with them enabled works + await rm(join(packageDir, ".npmrc")); + await runBunInstall(env, packageDir, { savesLockfile: false }); + + expect(await readdirSorted(join(packageDir, "node_modules"))).toEqual(["Baz", "a-dep", "no-deps"]); +}); + +test("disabled dev/peer/optional dependencies are still included in the lockfile", async () => { + await Promise.all([ + write( + packageJson, + JSON.stringify({ + devDependencies: { + "no-deps": "1.0.0", + }, + peerDependencies: { + "a-dep": "1.0.1", + }, + optionalDependencies: { + "basic-1": "1.0.0", + }, + }), + ), + ]); + + await runBunInstall; +}); + test("tarball override does not crash", async () => { await write( packageJson, diff --git a/test/harness.ts b/test/harness.ts index a6e1950025..bbdc48006f 100644 --- a/test/harness.ts +++ b/test/harness.ts @@ -1427,3 +1427,10 @@ export function rmScope(path: string) { }, }; } + +export function textLockfile(version: number, pkgs: any): string { + return JSON.stringify({ + lockfileVersion: version, + ...pkgs, + }); +} From 8a4852b8b04162c0e513e33214e310176f6a4cf6 Mon Sep 17 00:00:00 2001 From: dave caruso Date: Fri, 20 Dec 2024 00:36:59 -0800 Subject: [PATCH 069/125] fix: pass homedir test (#15811) Co-authored-by: paperdave Co-authored-by: Ashcon Partovi Co-authored-by: Dylan Conway --- .../bindings/JSEnvironmentVariableMap.cpp | 24 +++++++++++++ src/bun.js/node/types.zig | 36 +++++++++++++++++++ src/http.zig | 3 +- src/js/builtins/ProcessObjectInternals.ts | 14 ++++++-- .../parallel/test-os-homedir-no-envvar.js | 31 ++++++++++++++++ test/preload.ts | 2 +- 6 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 test/js/node/test/parallel/test-os-homedir-no-envvar.js diff --git a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp index 84e19282dc..daac639878 100644 --- a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp +++ b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp @@ -254,6 +254,27 @@ JSC_DEFINE_CUSTOM_SETTER(jsBunConfigVerboseFetchSetter, (JSGlobalObject * global return true; } +extern "C" void Bun__Process__editWindowsEnvVar(BunString, BunString); + +JSC_DEFINE_HOST_FUNCTION(jsEditWindowsEnvVar, (JSGlobalObject * global, JSC::CallFrame* callFrame)) +{ + auto scope = DECLARE_THROW_SCOPE(global->vm()); + ASSERT(callFrame->argumentCount() == 2); + ASSERT(callFrame->uncheckedArgument(0).isString()); + WTF::String string1 = callFrame->uncheckedArgument(0).toWTFString(global); + RETURN_IF_EXCEPTION(scope, {}); + JSValue arg2 = callFrame->uncheckedArgument(1); + ASSERT(arg2.isNull() || arg2.isString()); + if (arg2.isCell()) { + WTF::String string2 = arg2.toWTFString(global); + RETURN_IF_EXCEPTION(scope, {}); + Bun__Process__editWindowsEnvVar(Bun::toString(string1), Bun::toString(string2)); + } else { + Bun__Process__editWindowsEnvVar(Bun::toString(string1), { .tag = BunStringTag::Dead }); + } + RELEASE_AND_RETURN(scope, JSValue::encode(jsUndefined())); +} + JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject) { VM& vm = globalObject->vm(); @@ -348,11 +369,14 @@ JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject) Identifier::fromString(vm, BUN_CONFIG_VERBOSE_FETCH), JSC::CustomGetterSetter::create(vm, jsBunConfigVerboseFetchGetter, jsBunConfigVerboseFetchSetter), BUN_CONFIG_VERBOSE_FETCH_Attrs); #if OS(WINDOWS) + auto editWindowsEnvVar = JSC::JSFunction::create(vm, globalObject, 0, String("editWindowsEnvVar"_s), jsEditWindowsEnvVar, ImplementationVisibility::Public); + JSC::JSFunction* getSourceEvent = JSC::JSFunction::create(vm, globalObject, processObjectInternalsWindowsEnvCodeGenerator(vm), globalObject); RETURN_IF_EXCEPTION(scope, {}); JSC::MarkedArgumentBuffer args; args.append(object); args.append(keyArray); + args.append(editWindowsEnvVar); auto clientData = WebCore::clientData(vm); JSC::CallData callData = JSC::getCallData(getSourceEvent); NakedPtr returnedException = nullptr; diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index 5a2730770e..4a4b26b274 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -2133,6 +2133,42 @@ pub const Process = struct { vm.globalExit(); } + // TODO: switch this to using *bun.wtf.String when it is added + pub fn Bun__Process__editWindowsEnvVar(k: bun.String, v: bun.String) callconv(.C) void { + if (k.tag == .Empty) return; + const wtf1 = k.value.WTFStringImpl; + var buf1: [32768]u16 = undefined; + var buf2: [32768]u16 = undefined; + const len1: usize = switch (wtf1.is8Bit()) { + true => bun.strings.copyLatin1IntoUTF16([]u16, &buf1, []const u8, wtf1.latin1Slice()).written, + false => b: { + @memcpy(buf1[0..wtf1.length()], wtf1.utf16Slice()); + break :b wtf1.length(); + }, + }; + buf1[len1] = 0; + const str2: ?[*:0]const u16 = if (v.tag != .Dead) str: { + if (v.tag == .Empty) break :str (&[_]u16{0})[0..0 :0]; + const wtf2 = v.value.WTFStringImpl; + const len2: usize = switch (wtf2.is8Bit()) { + true => bun.strings.copyLatin1IntoUTF16([]u16, &buf2, []const u8, wtf2.latin1Slice()).written, + false => b: { + @memcpy(buf2[0..wtf2.length()], wtf2.utf16Slice()); + break :b wtf2.length(); + }, + }; + buf2[len2] = 0; + break :str buf2[0..len2 :0].ptr; + } else null; + _ = bun.windows.SetEnvironmentVariableW(buf1[0..len1 :0].ptr, str2); + } + + comptime { + if (Environment.export_cpp_apis and Environment.isWindows) { + @export(Bun__Process__editWindowsEnvVar, .{ .name = "Bun__Process__editWindowsEnvVar" }); + } + } + pub export const Bun__version: [*:0]const u8 = "v" ++ bun.Global.package_json_version; pub export const Bun__version_with_sha: [*:0]const u8 = "v" ++ bun.Global.package_json_version_with_sha; pub export const Bun__versions_boringssl: [*:0]const u8 = bun.Global.versions.boringssl; diff --git a/src/http.zig b/src/http.zig index 3a6a27138d..19a346691c 100644 --- a/src/http.zig +++ b/src/http.zig @@ -1148,7 +1148,8 @@ pub const HTTPThread = struct { if (Environment.isWindows) { _ = std.process.getenvW(comptime bun.strings.w("SystemRoot")) orelse { - std.debug.panic("The %SystemRoot% environment variable is not set. Bun needs this set in order for network requests to work.", .{}); + bun.Output.errGeneric("The %SystemRoot% environment variable is not set. Bun needs this set in order for network requests to work.", .{}); + Global.crash(); }; } diff --git a/src/js/builtins/ProcessObjectInternals.ts b/src/js/builtins/ProcessObjectInternals.ts index 0cf98e9e37..1c7f2a0670 100644 --- a/src/js/builtins/ProcessObjectInternals.ts +++ b/src/js/builtins/ProcessObjectInternals.ts @@ -341,8 +341,13 @@ export function setMainModule(value) { } type InternalEnvMap = Record; +type EditWindowsEnvVarCb = (key: string, value: null | string) => void; -export function windowsEnv(internalEnv: InternalEnvMap, envMapList: Array) { +export function windowsEnv( + internalEnv: InternalEnvMap, + envMapList: Array, + editWindowsEnvVar: EditWindowsEnvVarCb, +) { // The use of String(key) here is intentional because Node.js as of v21.5.0 will throw // on symbol keys as it seems they assume the user uses string keys: // @@ -371,7 +376,10 @@ export function windowsEnv(internalEnv: InternalEnvMap, envMapList: Array Date: Fri, 20 Dec 2024 03:34:45 -0500 Subject: [PATCH 070/125] Fix macro imports (#15833) --- src/js_parser.zig | 134 ++++++++++----------- test/bundler/transpiler/macro-test.test.ts | 25 ++++ test/bundler/transpiler/macro.ts | 4 + 3 files changed, 95 insertions(+), 68 deletions(-) diff --git a/src/js_parser.zig b/src/js_parser.zig index abe0a5271b..c21d275903 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -187,7 +187,15 @@ const JSXFactoryName = "JSX"; const JSXAutomaticName = "jsx_module"; // kept as a static reference const exports_string_name: string = "exports"; -const MacroRefs = std.AutoArrayHashMap(Ref, u32); + +const MacroRefData = struct { + import_record_id: u32, + // if name is null the macro is imported as a namespace import + // import * as macros from "./macros.js" with {type: "macro"}; + name: ?string = null, +}; + +const MacroRefs = std.AutoArrayHashMap(Ref, MacroRefData); pub const AllocatedNamesPool = ObjectPool( std.ArrayList(string), @@ -8938,20 +8946,33 @@ fn NewParser_( const name = p.loadNameFromRef(name_loc.ref.?); const ref = try p.declareSymbol(.other, name_loc.loc, name); try p.is_import_item.put(p.allocator, ref, {}); - try p.macro.refs.put(ref, id); + try p.macro.refs.put(ref, .{ + .import_record_id = id, + .name = "default", + }); + } + + if (stmt.star_name_loc) |star| { + const name = p.loadNameFromRef(stmt.namespace_ref); + const ref = try p.declareSymbol(.other, star, name); + stmt.namespace_ref = ref; + try p.macro.refs.put(ref, .{ .import_record_id = id }); } for (stmt.items) |item| { const name = p.loadNameFromRef(item.name.ref.?); const ref = try p.declareSymbol(.other, item.name.loc, name); try p.is_import_item.put(p.allocator, ref, {}); - try p.macro.refs.put(ref, id); + try p.macro.refs.put(ref, .{ + .import_record_id = id, + .name = item.alias, + }); } return p.s(S.Empty{}, loc); } - const macro_remap = if ((comptime allow_macros) and !is_macro) + const macro_remap = if (comptime allow_macros) p.options.macro_context.getRemap(path.text) else null; @@ -8970,6 +8991,8 @@ fn NewParser_( .import_record_index = stmt.import_record_index, }) catch unreachable; } + + // TODO: not sure how to handle macro remappings for namespace imports } else { var path_name = fs.PathName.init(path.text); const name = try strings.append(p.allocator, "import_", try path_name.nonUniqueNameString(p.allocator)); @@ -9010,7 +9033,10 @@ fn NewParser_( if (macro_remap) |*remap| { if (remap.get("default")) |remapped_path| { const new_import_id = p.addImportRecord(.stmt, path.loc, remapped_path); - try p.macro.refs.put(ref, new_import_id); + try p.macro.refs.put(ref, .{ + .import_record_id = new_import_id, + .name = "default", + }); p.import_records.items[new_import_id].path.namespace = js_ast.Macro.namespace; p.import_records.items[new_import_id].is_unused = true; @@ -9031,12 +9057,6 @@ fn NewParser_( }) catch unreachable; } - if (is_macro) { - try p.macro.refs.put(ref, stmt.import_record_index); - stmt.default_name = null; - break :outer; - } - if (comptime ParsePassSymbolUsageType != void) { p.parse_pass_symbol_uses.put(name, .{ .ref = ref, @@ -9072,7 +9092,10 @@ fn NewParser_( if (macro_remap) |*remap| { if (remap.get(item.alias)) |remapped_path| { const new_import_id = p.addImportRecord(.stmt, path.loc, remapped_path); - try p.macro.refs.put(ref, new_import_id); + try p.macro.refs.put(ref, .{ + .import_record_id = new_import_id, + .name = item.alias, + }); p.import_records.items[new_import_id].path.namespace = js_ast.Macro.namespace; p.import_records.items[new_import_id].is_unused = true; @@ -14631,48 +14654,6 @@ fn NewParser_( } } - pub const MacroVisitor = struct { - p: *P, - - loc: logger.Loc, - - pub fn visitImport(this: MacroVisitor, import_data: js_ast.Macro.JSNode.ImportData) void { - var p = this.p; - - const record_id = p.addImportRecord(.stmt, this.loc, import_data.path); - var record: *ImportRecord = &p.import_records.items[record_id]; - record.was_injected_by_macro = true; - p.macro.imports.ensureUnusedCapacity(import_data.import.items.len) catch unreachable; - var import = import_data.import; - import.import_record_index = record_id; - - p.is_import_item.ensureUnusedCapacity( - p.allocator, - @as(u32, @intCast(p.is_import_item.count() + import.items.len)), - ) catch unreachable; - - for (import.items) |*clause| { - const import_hash_name = clause.original_name; - - if (strings.eqlComptime(clause.alias, "default")) { - const non_unique_name = record.path.name.nonUniqueNameString(p.allocator) catch unreachable; - clause.original_name = std.fmt.allocPrint(p.allocator, "{s}_default", .{non_unique_name}) catch unreachable; - record.contains_default_alias = true; - } - const name_ref = p.declareSymbol(.import, this.loc, clause.original_name) catch unreachable; - clause.name = LocRef{ .loc = this.loc, .ref = name_ref }; - - p.is_import_item.putAssumeCapacity(name_ref, {}); - - p.macro.imports.putAssumeCapacity(js_ast.Macro.JSNode.SymbolMap.generateImportHash(import_hash_name, import_data.path), name_ref); - - // Ensure we don't accidentally think this is an export from - } - - p.macro.prepend_stmts.append(p.s(import, this.loc)) catch unreachable; - } - }; - pub fn panic(p: *P, comptime fmt: string, args: anytype) noreturn { p.panicLoc(fmt, args, null); @setCold(true); @@ -16500,12 +16481,15 @@ fn NewParser_( e_.tag = p.visitExpr(tag); if (comptime allow_macros) { - if (e_.tag.?.data == .e_import_identifier and !p.options.features.is_macro_runtime) { - const ref = e_.tag.?.data.e_import_identifier.ref; + const ref = switch (e_.tag.?.data) { + .e_import_identifier => |ident| ident.ref, + .e_dot => |dot| if (dot.target.data == .e_identifier) dot.target.data.e_identifier.ref else null, + else => null, + }; - if (p.macro.refs.get(ref)) |import_record_id| { - const name = p.symbols.items[ref.innerIndex()].original_name; - p.ignoreUsage(ref); + if (ref != null and !p.options.features.is_macro_runtime) { + if (p.macro.refs.get(ref.?)) |macro_ref_data| { + p.ignoreUsage(ref.?); if (p.is_control_flow_dead) { return p.newExpr(E.Undefined{}, e_.tag.?.loc); } @@ -16522,7 +16506,8 @@ fn NewParser_( } p.macro_call_count += 1; - const record = &p.import_records.items[import_record_id]; + const name = macro_ref_data.name orelse e_.tag.?.data.e_dot.name; + const record = &p.import_records.items[macro_ref_data.import_record_id]; // We must visit it to convert inline_identifiers and record usage const macro_result = (p.options.macro_context.call( record.path.text, @@ -17297,10 +17282,18 @@ fn NewParser_( else => {}, } - const is_macro_ref: bool = if (comptime FeatureFlags.is_macro_enabled) - e_.target.data == .e_import_identifier and p.macro.refs.contains(e_.target.data.e_import_identifier.ref) - else - false; + const is_macro_ref: bool = if (comptime allow_macros) brk: { + const possible_macro_ref = switch (e_.target.data) { + .e_import_identifier => |ident| ident.ref, + .e_dot => |dot| if (dot.target.data == .e_identifier) + dot.target.data.e_identifier.ref + else + null, + else => null, + }; + + break :brk possible_macro_ref != null and p.macro.refs.contains(possible_macro_ref.?); + } else false; { const old_ce = p.options.ignore_dce_annotations; @@ -17426,8 +17419,13 @@ fn NewParser_( if (comptime allow_macros) { if (is_macro_ref and !p.options.features.is_macro_runtime) { - const ref = e_.target.data.e_import_identifier.ref; - const import_record_id = p.macro.refs.get(ref).?; + const ref = switch (e_.target.data) { + .e_import_identifier => |ident| ident.ref, + .e_dot => |dot| dot.target.data.e_identifier.ref, + else => unreachable, + }; + + const macro_ref_data = p.macro.refs.get(ref).?; p.ignoreUsage(ref); if (p.is_control_flow_dead) { return p.newExpr(E.Undefined{}, e_.target.loc); @@ -17443,8 +17441,8 @@ fn NewParser_( return p.newExpr(E.Undefined{}, expr.loc); } - const name = p.symbols.items[ref.innerIndex()].original_name; - const record = &p.import_records.items[import_record_id]; + const name = macro_ref_data.name orelse e_.target.data.e_dot.name; + const record = &p.import_records.items[macro_ref_data.import_record_id]; const copied = Expr{ .loc = expr.loc, .data = .{ .e_call = e_ } }; const start_error_count = p.log.msgs.items.len; p.macro_call_count += 1; diff --git a/test/bundler/transpiler/macro-test.test.ts b/test/bundler/transpiler/macro-test.test.ts index 5c95553400..be7aed0ac5 100644 --- a/test/bundler/transpiler/macro-test.test.ts +++ b/test/bundler/transpiler/macro-test.test.ts @@ -1,6 +1,13 @@ import { escapeHTML } from "bun" assert { type: "macro" }; import { expect, test } from "bun:test"; import { addStrings, addStringsUTF16, escape, identity } from "./macro.ts" assert { type: "macro" }; +import defaultMacro, { + default as defaultMacroAlias, + identity as identity1, + identity as identity2, +} from "./macro.ts" assert { type: "macro" }; + +import * as macros from "./macro.ts" assert { type: "macro" }; test("bun builtins can be used in macros", async () => { expect(escapeHTML("abc!")).toBe("abc!"); @@ -89,6 +96,24 @@ test("utf16 string", () => { expect(identity("😊 Smiling Face with Smiling Eyes Emoji")).toBe("😊 Smiling Face with Smiling Eyes Emoji"); }); +test("import aliases", () => { + expect(identity1({ a: 1 })).toEqual({ a: 1 }); + expect(identity1([1, 2, 3])).toEqual([1, 2, 3]); + expect(identity2({ a: 1 })).toEqual({ a: 1 }); + expect(identity2([1, 2, 3])).toEqual([1, 2, 3]); +}); + +test("default import", () => { + expect(defaultMacro()).toBe("defaultdefaultdefault"); + expect(defaultMacroAlias()).toBe("defaultdefaultdefault"); +}); + +test("namespace import", () => { + expect(macros.identity({ a: 1 })).toEqual({ a: 1 }); + expect(macros.identity([1, 2, 3])).toEqual([1, 2, 3]); + expect(macros.escape()).toBe("\\\f\n\r\t\v\0'\"`$\x00\x0B\x0C"); +}); + // test("template string ascii", () => { // expect(identity(`A${""}`)).toBe("A"); // }); diff --git a/test/bundler/transpiler/macro.ts b/test/bundler/transpiler/macro.ts index fc747333cb..430fab84ee 100644 --- a/test/bundler/transpiler/macro.ts +++ b/test/bundler/transpiler/macro.ts @@ -13,3 +13,7 @@ export function addStrings(arg: string) { export function addStringsUTF16(arg: string) { return arg + "\\\f\n\r\t\v\0'\"`$\x00\x0B\x0C" + "😊"; } + +export default function() { + return "defaultdefaultdefault"; +} From 1d9fbe7d6726a42dfde1c699b2a6155e37333d1c Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Fri, 20 Dec 2024 01:26:30 -0800 Subject: [PATCH 071/125] fix(lexer): do not treat '#bun' in a url as a pragma (#15888) Co-authored-by: Don Isaac Co-authored-by: DonIsaac --- src/js_lexer.zig | 23 +------- src/js_parser.zig | 57 +++++++++++++++---- test/bundler/transpiler/bun-pragma.test.ts | 15 +++++ .../bundler/transpiler/fixtures/bun-in-url.ts | 5 ++ 4 files changed, 68 insertions(+), 32 deletions(-) create mode 100644 test/bundler/transpiler/bun-pragma.test.ts create mode 100644 test/bundler/transpiler/fixtures/bun-in-url.ts diff --git a/src/js_lexer.zig b/src/js_lexer.zig index ca946482f3..de7cfc2283 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -153,13 +153,6 @@ fn NewLexer_( code_point: CodePoint = -1, identifier: []const u8 = "", jsx_pragma: JSXPragma = .{}, - bun_pragma: enum { - none, - bun, - bun_cjs, - bytecode, - bytecode_cjs, - } = .none, source_mapping_url: ?js_ast.Span = null, number: f64 = 0.0, rescan_close_brace_as_template_token: bool = false, @@ -1957,9 +1950,7 @@ fn NewLexer_( // } } - if (lexer.bun_pragma == .none and strings.hasPrefixWithWordBoundary(chunk, "bun")) { - lexer.bun_pragma = .bun; - } else if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { + if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { if (PragmaArg.scan(.skip_space_first, lexer.start + i + 1, "jsx", chunk)) |span| { lexer.jsx_pragma._jsx = span; } @@ -1979,10 +1970,6 @@ fn NewLexer_( if (PragmaArg.scan(.no_space_first, lexer.start + i + 1, " sourceMappingURL=", chunk)) |span| { lexer.source_mapping_url = span; } - } else if ((lexer.bun_pragma == .bun or lexer.bun_pragma == .bun_cjs) and strings.hasPrefixWithWordBoundary(chunk, "bytecode")) { - lexer.bun_pragma = if (lexer.bun_pragma == .bun) .bytecode else .bytecode_cjs; - } else if ((lexer.bun_pragma == .bytecode or lexer.bun_pragma == .bun) and strings.hasPrefixWithWordBoundary(chunk, "bun-cjs")) { - lexer.bun_pragma = if (lexer.bun_pragma == .bytecode) .bytecode_cjs else .bun_cjs; } }, else => {}, @@ -2012,9 +1999,7 @@ fn NewLexer_( } } - if (lexer.bun_pragma == .none and strings.hasPrefixWithWordBoundary(chunk, "bun")) { - lexer.bun_pragma = .bun; - } else if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { + if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { if (PragmaArg.scan(.skip_space_first, lexer.start + i + 1, "jsx", chunk)) |span| { lexer.jsx_pragma._jsx = span; } @@ -2034,10 +2019,6 @@ fn NewLexer_( if (PragmaArg.scan(.no_space_first, lexer.start + i + 1, " sourceMappingURL=", chunk)) |span| { lexer.source_mapping_url = span; } - } else if ((lexer.bun_pragma == .bun or lexer.bun_pragma == .bun_cjs) and strings.hasPrefixWithWordBoundary(chunk, "bytecode")) { - lexer.bun_pragma = if (lexer.bun_pragma == .bun) .bytecode else .bytecode_cjs; - } else if ((lexer.bun_pragma == .bytecode or lexer.bun_pragma == .bun) and strings.hasPrefixWithWordBoundary(chunk, "bun-cjs")) { - lexer.bun_pragma = if (lexer.bun_pragma == .bytecode) .bytecode_cjs else .bun_cjs; } }, else => {}, diff --git a/src/js_parser.zig b/src/js_parser.zig index c21d275903..231a1cf9e6 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -3,6 +3,7 @@ /// ** you must also increment the `expected_version` in RuntimeTranspilerCache.zig ** /// ** IMPORTANT ** pub const std = @import("std"); +const bun = @import("root").bun; pub const logger = bun.logger; pub const js_lexer = bun.js_lexer; pub const importRecord = @import("./import_record.zig"); @@ -15,7 +16,6 @@ pub const RuntimeImports = _runtime.Runtime.Imports; pub const RuntimeFeatures = _runtime.Runtime.Features; pub const RuntimeNames = _runtime.Runtime.Names; pub const fs = @import("./fs.zig"); -const bun = @import("root").bun; const string = bun.string; const Output = bun.Output; const Global = bun.Global; @@ -3226,16 +3226,12 @@ pub const Parser = struct { } // Detect a leading "// @bun" pragma - if (p.lexer.bun_pragma != .none and p.options.features.dont_bundle_twice) { - return js_ast.Result{ - .already_bundled = switch (p.lexer.bun_pragma) { - .bun => .bun, - .bytecode => .bytecode, - .bytecode_cjs => .bytecode_cjs, - .bun_cjs => .bun_cjs, - else => unreachable, - }, - }; + if (self.options.features.dont_bundle_twice) { + if (self.hasBunPragma()) |pragma| { + return js_ast.Result{ + .already_bundled = pragma, + }; + } } // We must check the cache only after we've consumed the hashbang and leading // @bun pragma @@ -4282,6 +4278,45 @@ pub const Parser = struct { .log = log, }; } + + const PragmaState = packed struct { seen_cjs: bool = false, seen_bytecode: bool = false }; + + fn hasBunPragma(self: *const Parser) ?js_ast.Result.AlreadyBundled { + const BUN_PRAGMA = "// @bun"; + var cursor: usize = 0; + + const contents = self.lexer.source.contents; + if (!bun.strings.startsWith(contents[cursor..], BUN_PRAGMA)) return null; + cursor += BUN_PRAGMA.len; + + var state: PragmaState = .{}; + + while (cursor < self.lexer.end) : (cursor += 1) { + switch (contents[cursor]) { + '\n' => break, + '@' => { + cursor += 1; + if (cursor >= contents.len) break; + if (contents[cursor] != 'b') continue; + const slice = contents[cursor..]; + if (bun.strings.startsWith(slice, "bun-cjs")) { + state.seen_cjs = true; + cursor += "bun-cjs".len; + } else if (bun.strings.startsWith(slice, "bytecode")) { + state.seen_bytecode = true; + cursor += "bytecode".len; + } + }, + else => {}, + } + } + + if (state.seen_cjs) { + return if (state.seen_bytecode) .bytecode_cjs else .bun_cjs; + } else { + return if (state.seen_bytecode) .bytecode else .bun; + } + } }; const FindLabelSymbolResult = struct { ref: Ref, is_loop: bool, found: bool = false }; diff --git a/test/bundler/transpiler/bun-pragma.test.ts b/test/bundler/transpiler/bun-pragma.test.ts new file mode 100644 index 0000000000..d9c9243d8b --- /dev/null +++ b/test/bundler/transpiler/bun-pragma.test.ts @@ -0,0 +1,15 @@ +import path from "path"; +import { bunExe, bunEnv } from "harness"; + +const fixturePath = (name: string): string => path.join(import.meta.dirname, "fixtures", name); + +describe("@bun pragma", () => { + it("is not detected when embedded in a URL", async () => { + const res = Bun.spawn({ + cmd: [bunExe(), "run", fixturePath("bun-in-url.ts")], + stdio: ["ignore", "ignore", "ignore"], + }); + await res.exited; + expect(res.exitCode).toBe(0); + }); +}); diff --git a/test/bundler/transpiler/fixtures/bun-in-url.ts b/test/bundler/transpiler/fixtures/bun-in-url.ts new file mode 100644 index 0000000000..64af8d8e3b --- /dev/null +++ b/test/bundler/transpiler/fixtures/bun-in-url.ts @@ -0,0 +1,5 @@ +// https://bun.sh/docs/api/http#bun-serve +const a: string = "hello"; +console.log(a); + +// '#bun' spotted in first comment but it's not a valid bun pragma From bf9c6fdc00057da26d3ef1b2b2326d6948ff6720 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 20 Dec 2024 01:31:48 -0800 Subject: [PATCH 072/125] Revert "fix(lexer): do not treat '#bun' in a url as a pragma" (#15899) --- src/js_lexer.zig | 23 +++++++- src/js_parser.zig | 57 ++++--------------- test/bundler/transpiler/bun-pragma.test.ts | 15 ----- .../bundler/transpiler/fixtures/bun-in-url.ts | 5 -- 4 files changed, 32 insertions(+), 68 deletions(-) delete mode 100644 test/bundler/transpiler/bun-pragma.test.ts delete mode 100644 test/bundler/transpiler/fixtures/bun-in-url.ts diff --git a/src/js_lexer.zig b/src/js_lexer.zig index de7cfc2283..ca946482f3 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -153,6 +153,13 @@ fn NewLexer_( code_point: CodePoint = -1, identifier: []const u8 = "", jsx_pragma: JSXPragma = .{}, + bun_pragma: enum { + none, + bun, + bun_cjs, + bytecode, + bytecode_cjs, + } = .none, source_mapping_url: ?js_ast.Span = null, number: f64 = 0.0, rescan_close_brace_as_template_token: bool = false, @@ -1950,7 +1957,9 @@ fn NewLexer_( // } } - if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { + if (lexer.bun_pragma == .none and strings.hasPrefixWithWordBoundary(chunk, "bun")) { + lexer.bun_pragma = .bun; + } else if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { if (PragmaArg.scan(.skip_space_first, lexer.start + i + 1, "jsx", chunk)) |span| { lexer.jsx_pragma._jsx = span; } @@ -1970,6 +1979,10 @@ fn NewLexer_( if (PragmaArg.scan(.no_space_first, lexer.start + i + 1, " sourceMappingURL=", chunk)) |span| { lexer.source_mapping_url = span; } + } else if ((lexer.bun_pragma == .bun or lexer.bun_pragma == .bun_cjs) and strings.hasPrefixWithWordBoundary(chunk, "bytecode")) { + lexer.bun_pragma = if (lexer.bun_pragma == .bun) .bytecode else .bytecode_cjs; + } else if ((lexer.bun_pragma == .bytecode or lexer.bun_pragma == .bun) and strings.hasPrefixWithWordBoundary(chunk, "bun-cjs")) { + lexer.bun_pragma = if (lexer.bun_pragma == .bytecode) .bytecode_cjs else .bun_cjs; } }, else => {}, @@ -1999,7 +2012,9 @@ fn NewLexer_( } } - if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { + if (lexer.bun_pragma == .none and strings.hasPrefixWithWordBoundary(chunk, "bun")) { + lexer.bun_pragma = .bun; + } else if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { if (PragmaArg.scan(.skip_space_first, lexer.start + i + 1, "jsx", chunk)) |span| { lexer.jsx_pragma._jsx = span; } @@ -2019,6 +2034,10 @@ fn NewLexer_( if (PragmaArg.scan(.no_space_first, lexer.start + i + 1, " sourceMappingURL=", chunk)) |span| { lexer.source_mapping_url = span; } + } else if ((lexer.bun_pragma == .bun or lexer.bun_pragma == .bun_cjs) and strings.hasPrefixWithWordBoundary(chunk, "bytecode")) { + lexer.bun_pragma = if (lexer.bun_pragma == .bun) .bytecode else .bytecode_cjs; + } else if ((lexer.bun_pragma == .bytecode or lexer.bun_pragma == .bun) and strings.hasPrefixWithWordBoundary(chunk, "bun-cjs")) { + lexer.bun_pragma = if (lexer.bun_pragma == .bytecode) .bytecode_cjs else .bun_cjs; } }, else => {}, diff --git a/src/js_parser.zig b/src/js_parser.zig index 231a1cf9e6..c21d275903 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -3,7 +3,6 @@ /// ** you must also increment the `expected_version` in RuntimeTranspilerCache.zig ** /// ** IMPORTANT ** pub const std = @import("std"); -const bun = @import("root").bun; pub const logger = bun.logger; pub const js_lexer = bun.js_lexer; pub const importRecord = @import("./import_record.zig"); @@ -16,6 +15,7 @@ pub const RuntimeImports = _runtime.Runtime.Imports; pub const RuntimeFeatures = _runtime.Runtime.Features; pub const RuntimeNames = _runtime.Runtime.Names; pub const fs = @import("./fs.zig"); +const bun = @import("root").bun; const string = bun.string; const Output = bun.Output; const Global = bun.Global; @@ -3226,12 +3226,16 @@ pub const Parser = struct { } // Detect a leading "// @bun" pragma - if (self.options.features.dont_bundle_twice) { - if (self.hasBunPragma()) |pragma| { - return js_ast.Result{ - .already_bundled = pragma, - }; - } + if (p.lexer.bun_pragma != .none and p.options.features.dont_bundle_twice) { + return js_ast.Result{ + .already_bundled = switch (p.lexer.bun_pragma) { + .bun => .bun, + .bytecode => .bytecode, + .bytecode_cjs => .bytecode_cjs, + .bun_cjs => .bun_cjs, + else => unreachable, + }, + }; } // We must check the cache only after we've consumed the hashbang and leading // @bun pragma @@ -4278,45 +4282,6 @@ pub const Parser = struct { .log = log, }; } - - const PragmaState = packed struct { seen_cjs: bool = false, seen_bytecode: bool = false }; - - fn hasBunPragma(self: *const Parser) ?js_ast.Result.AlreadyBundled { - const BUN_PRAGMA = "// @bun"; - var cursor: usize = 0; - - const contents = self.lexer.source.contents; - if (!bun.strings.startsWith(contents[cursor..], BUN_PRAGMA)) return null; - cursor += BUN_PRAGMA.len; - - var state: PragmaState = .{}; - - while (cursor < self.lexer.end) : (cursor += 1) { - switch (contents[cursor]) { - '\n' => break, - '@' => { - cursor += 1; - if (cursor >= contents.len) break; - if (contents[cursor] != 'b') continue; - const slice = contents[cursor..]; - if (bun.strings.startsWith(slice, "bun-cjs")) { - state.seen_cjs = true; - cursor += "bun-cjs".len; - } else if (bun.strings.startsWith(slice, "bytecode")) { - state.seen_bytecode = true; - cursor += "bytecode".len; - } - }, - else => {}, - } - } - - if (state.seen_cjs) { - return if (state.seen_bytecode) .bytecode_cjs else .bun_cjs; - } else { - return if (state.seen_bytecode) .bytecode else .bun; - } - } }; const FindLabelSymbolResult = struct { ref: Ref, is_loop: bool, found: bool = false }; diff --git a/test/bundler/transpiler/bun-pragma.test.ts b/test/bundler/transpiler/bun-pragma.test.ts deleted file mode 100644 index d9c9243d8b..0000000000 --- a/test/bundler/transpiler/bun-pragma.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import path from "path"; -import { bunExe, bunEnv } from "harness"; - -const fixturePath = (name: string): string => path.join(import.meta.dirname, "fixtures", name); - -describe("@bun pragma", () => { - it("is not detected when embedded in a URL", async () => { - const res = Bun.spawn({ - cmd: [bunExe(), "run", fixturePath("bun-in-url.ts")], - stdio: ["ignore", "ignore", "ignore"], - }); - await res.exited; - expect(res.exitCode).toBe(0); - }); -}); diff --git a/test/bundler/transpiler/fixtures/bun-in-url.ts b/test/bundler/transpiler/fixtures/bun-in-url.ts deleted file mode 100644 index 64af8d8e3b..0000000000 --- a/test/bundler/transpiler/fixtures/bun-in-url.ts +++ /dev/null @@ -1,5 +0,0 @@ -// https://bun.sh/docs/api/http#bun-serve -const a: string = "hello"; -console.log(a); - -// '#bun' spotted in first comment but it's not a valid bun pragma From 0c50b0fcec7102647f61c7b22dc80f1d8b257ddd Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 20 Dec 2024 02:12:08 -0800 Subject: [PATCH 073/125] Fix potential runtime crash if transpiler generates invalid commonjs (#15898) --- src/bun.js/bindings/CommonJSModuleRecord.cpp | 57 +++++++++++++------- test/cli/run/cjs-fixture-bad.cjs | 7 +++ test/cli/run/commonjs-invalid.test.ts | 16 ++++++ 3 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 test/cli/run/cjs-fixture-bad.cjs create mode 100644 test/cli/run/commonjs-invalid.test.ts diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index e1d7e0573b..6ab63c26cb 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -115,22 +115,26 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj return false; } - JSFunction* resolveFunction = JSC::JSBoundFunction::create(vm, - globalObject, - globalObject->requireResolveFunctionUnbound(), - moduleObject->id(), - ArgList(), 1, globalObject->commonStrings().resolveString(globalObject)); - JSFunction* requireFunction = JSC::JSBoundFunction::create(vm, - globalObject, - globalObject->requireFunctionUnbound(), - moduleObject, - ArgList(), 1, globalObject->commonStrings().requireString(globalObject)); - requireFunction->putDirect(vm, vm.propertyNames->resolve, resolveFunction, 0); - moduleObject->putDirect(vm, WebCore::clientData(vm)->builtinNames().requirePublicName(), requireFunction, 0); + JSFunction* resolveFunction = nullptr; + JSFunction* requireFunction = nullptr; + const auto initializeModuleObject = [&]() { + resolveFunction = JSC::JSBoundFunction::create(vm, + globalObject, + globalObject->requireResolveFunctionUnbound(), + moduleObject->id(), + ArgList(), 1, globalObject->commonStrings().resolveString(globalObject)); + requireFunction = JSC::JSBoundFunction::create(vm, + globalObject, + globalObject->requireFunctionUnbound(), + moduleObject, + ArgList(), 1, globalObject->commonStrings().requireString(globalObject)); + requireFunction->putDirect(vm, vm.propertyNames->resolve, resolveFunction, 0); + moduleObject->putDirect(vm, WebCore::clientData(vm)->builtinNames().requirePublicName(), requireFunction, 0); + moduleObject->hasEvaluated = true; + }; - moduleObject->hasEvaluated = true; - - if (Bun__VM__specifierIsEvalEntryPoint(globalObject->bunVM(), JSValue::encode(filename))) { + if (UNLIKELY(Bun__VM__specifierIsEvalEntryPoint(globalObject->bunVM(), JSValue::encode(filename)))) { + initializeModuleObject(); // Using same approach as node, `arguments` in the entry point isn't defined // https://github.com/nodejs/node/blob/592c6907bfe1922f36240e9df076be1864c3d1bd/lib/internal/process/execution.js#L92 @@ -158,9 +162,22 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj return false; } - JSFunction* fn = jsCast(fnValue); + JSObject* fn = fnValue.getObject(); + + if (UNLIKELY(!fn)) { + exception = Exception::create(vm, createTypeError(globalObject, "Expected CommonJS module to have a function wrapper. If you weren't messing around with Bun's internals, this is a bug in Bun"_s)); + return false; + } JSC::CallData callData = JSC::getCallData(fn); + + if (UNLIKELY(callData.type == CallData::Type::None)) { + exception = Exception::create(vm, createTypeError(globalObject, "Expected CommonJS module to have a function wrapper. If you weren't messing around with Bun's internals, this is a bug in Bun"_s)); + return false; + } + + initializeModuleObject(); + MarkedArgumentBuffer args; args.append(moduleObject->exportsObject()); // exports args.append(requireFunction); // require @@ -168,9 +185,11 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj args.append(filename); // filename args.append(dirname); // dirname - if (fn->jsExecutable()->parameterCount() > 5) { - // it expects ImportMetaObject - args.append(Zig::ImportMetaObject::create(globalObject, filename)); + if (auto* jsFunction = jsDynamicCast(fn)) { + if (jsFunction->jsExecutable()->parameterCount() > 5) { + // it expects ImportMetaObject + args.append(Zig::ImportMetaObject::create(globalObject, filename)); + } } // Clear the source code as early as possible. diff --git a/test/cli/run/cjs-fixture-bad.cjs b/test/cli/run/cjs-fixture-bad.cjs new file mode 100644 index 0000000000..a502af2f4b --- /dev/null +++ b/test/cli/run/cjs-fixture-bad.cjs @@ -0,0 +1,7 @@ +// @bun @bun-cjs + +function f() { + console.log("This module has been evaluated!"); +} + +f(); diff --git a/test/cli/run/commonjs-invalid.test.ts b/test/cli/run/commonjs-invalid.test.ts new file mode 100644 index 0000000000..b0461dcd62 --- /dev/null +++ b/test/cli/run/commonjs-invalid.test.ts @@ -0,0 +1,16 @@ +import { expect, test } from "bun:test"; +import { bunEnv, bunExe } from "harness"; +import { join } from "path"; + +test("Loading an invalid commonjs module", () => { + const { stderr, exitCode } = Bun.spawnSync({ + cmd: [bunExe(), "run", join(import.meta.dir, "cjs-fixture-bad.cjs")], + env: bunEnv, + stdout: "inherit", + stderr: "pipe", + stdin: "inherit", + }); + + expect(stderr.toString().trim()).toContain("Expected CommonJS module to have a function wrapper"); + expect(exitCode).toBe(1); +}); From 7b3554f90c84256a9e7bfd06c3f726d1786cd51f Mon Sep 17 00:00:00 2001 From: dave caruso Date: Fri, 20 Dec 2024 03:22:16 -0800 Subject: [PATCH 074/125] feat(bundler): add --windows-icon, --windows-no-console, fix bun.exe's main icon (#15894) Co-authored-by: Dylan Conway Co-authored-by: Jarred Sumner Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> --- cmake/targets/BuildBun.cmake | 16 +- docs/bundler/executables.md | 13 + src/StandaloneModuleGraph.zig | 29 +- .../bindings/windows/rescle-binding.cpp | 14 + src/bun.js/bindings/windows/rescle.cpp | 1090 +++++++++++++++++ src/bun.js/bindings/windows/rescle.h | 211 ++++ src/cli.zig | 38 +- src/cli/build_command.zig | 2 + src/windows-app-info.rc | 2 +- src/windows.zig | 30 + 10 files changed, 1435 insertions(+), 10 deletions(-) create mode 100644 src/bun.js/bindings/windows/rescle-binding.cpp create mode 100644 src/bun.js/bindings/windows/rescle.cpp create mode 100644 src/bun.js/bindings/windows/rescle.h diff --git a/cmake/targets/BuildBun.cmake b/cmake/targets/BuildBun.cmake index 84a99eaa58..11759e2f7a 100644 --- a/cmake/targets/BuildBun.cmake +++ b/cmake/targets/BuildBun.cmake @@ -601,6 +601,8 @@ file(GLOB BUN_C_SOURCES ${CONFIGURE_DEPENDS} if(WIN32) list(APPEND BUN_C_SOURCES ${CWD}/src/bun.js/bindings/windows/musl-memmem.c) + list(APPEND BUN_CXX_SOURCES ${CWD}/src/bun.js/bindings/windows/rescle.cpp) + list(APPEND BUN_CXX_SOURCES ${CWD}/src/bun.js/bindings/windows/rescle-binding.cpp) endif() register_repository( @@ -650,11 +652,19 @@ if(WIN32) set(Bun_VERSION_WITH_TAG ${VERSION}) endif() set(BUN_ICO_PATH ${CWD}/src/bun.ico) + configure_file(${CWD}/src/bun.ico ${CODEGEN_PATH}/bun.ico COPYONLY) configure_file( ${CWD}/src/windows-app-info.rc ${CODEGEN_PATH}/windows-app-info.rc + @ONLY ) - list(APPEND BUN_CPP_SOURCES ${CODEGEN_PATH}/windows-app-info.rc) + add_custom_command( + OUTPUT ${CODEGEN_PATH}/windows-app-info.res + COMMAND rc.exe /fo ${CODEGEN_PATH}/windows-app-info.res ${CODEGEN_PATH}/windows-app-info.rc + DEPENDS ${CODEGEN_PATH}/windows-app-info.rc ${CODEGEN_PATH}/bun.ico + COMMENT "Adding Windows resource file ${CODEGEN_PATH}/windows-app-info.res with ico in ${CODEGEN_PATH}/bun.ico" + ) + set(WINDOWS_RESOURCES ${CODEGEN_PATH}/windows-app-info.res) endif() # --- Executable --- @@ -662,7 +672,7 @@ endif() set(BUN_CPP_OUTPUT ${BUILD_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}${bun}${CMAKE_STATIC_LIBRARY_SUFFIX}) if(BUN_LINK_ONLY) - add_executable(${bun} ${BUN_CPP_OUTPUT} ${BUN_ZIG_OUTPUT}) + add_executable(${bun} ${BUN_CPP_OUTPUT} ${BUN_ZIG_OUTPUT} ${WINDOWS_RESOURCES}) set_target_properties(${bun} PROPERTIES LINKER_LANGUAGE CXX) target_link_libraries(${bun} PRIVATE ${BUN_CPP_OUTPUT}) elseif(BUN_CPP_ONLY) @@ -680,7 +690,7 @@ elseif(BUN_CPP_ONLY) ${BUN_CPP_OUTPUT} ) else() - add_executable(${bun} ${BUN_CPP_SOURCES}) + add_executable(${bun} ${BUN_CPP_SOURCES} ${WINDOWS_RESOURCES}) target_link_libraries(${bun} PRIVATE ${BUN_ZIG_OUTPUT}) endif() diff --git a/docs/bundler/executables.md b/docs/bundler/executables.md index 6ae39a574c..c477e6a82c 100644 --- a/docs/bundler/executables.md +++ b/docs/bundler/executables.md @@ -279,6 +279,19 @@ $ bun build --compile --asset-naming="[name].[ext]" ./index.ts To trim down the size of the executable a little, pass `--minify` to `bun build --compile`. This uses Bun's minifier to reduce the code size. Overall though, Bun's binary is still way too big and we need to make it smaller. +## Windows-specific flags + +When compiling a standalone executable on Windows, there are two platform-specific options that can be used to customize metadata on the generated `.exe` file: + +- `--windows-icon=path/to/icon.ico` to customize the executable file icon. +- `--windows-hide-console` to disable the background terminal, which can be used for applications that do not need a TTY. + +{% callout %} + +These flags currently cannot be used when cross-compiling because they depend on Windows APIs. + +{% /callout %} + ## Unsupported CLI arguments Currently, the `--compile` flag can only accept a single entrypoint at a time and does not support the following flags: diff --git a/src/StandaloneModuleGraph.zig b/src/StandaloneModuleGraph.zig index 6e05878e0e..f067674855 100644 --- a/src/StandaloneModuleGraph.zig +++ b/src/StandaloneModuleGraph.zig @@ -430,7 +430,11 @@ pub const StandaloneModuleGraph = struct { else std.mem.page_size; - pub fn inject(bytes: []const u8, self_exe: [:0]const u8) bun.FileDescriptor { + pub const InjectOptions = struct { + windows_hide_console: bool = false, + }; + + pub fn inject(bytes: []const u8, self_exe: [:0]const u8, inject_options: InjectOptions) bun.FileDescriptor { var buf: bun.PathBuffer = undefined; var zname: [:0]const u8 = bun.span(bun.fs.FileSystem.instance.tmpname("bun-build", &buf, @as(u64, @bitCast(std.time.milliTimestamp()))) catch |err| { Output.prettyErrorln("error: failed to get temporary file name: {s}", .{@errorName(err)}); @@ -470,7 +474,7 @@ pub const StandaloneModuleGraph = struct { bun.invalid_fd, out, // access_mask - w.SYNCHRONIZE | w.GENERIC_WRITE | w.DELETE, + w.SYNCHRONIZE | w.GENERIC_WRITE | w.GENERIC_READ | w.DELETE, // create disposition w.FILE_OPEN, // create options @@ -637,6 +641,15 @@ pub const StandaloneModuleGraph = struct { _ = bun.C.fchmod(cloned_executable_fd.int(), 0o777); } + if (Environment.isWindows and inject_options.windows_hide_console) { + bun.windows.editWin32BinarySubsystem(.{ .handle = cloned_executable_fd }, .windows_gui) catch |err| { + Output.err(err, "failed to disable console on executable", .{}); + cleanup(zname, cloned_executable_fd); + + Global.exit(1); + }; + } + return cloned_executable_fd; } @@ -664,6 +677,8 @@ pub const StandaloneModuleGraph = struct { outfile: []const u8, env: *bun.DotEnv.Loader, output_format: bun.options.Format, + windows_hide_console: bool, + windows_icon: ?[]const u8, ) !void { const bytes = try toBytes(allocator, module_prefix, output_files, output_format); if (bytes.len == 0) return; @@ -680,6 +695,7 @@ pub const StandaloneModuleGraph = struct { Output.err(err, "failed to download cross-compiled bun executable", .{}); Global.exit(1); }, + .{ .windows_hide_console = windows_hide_console }, ); fd.assertKind(.system); @@ -704,6 +720,15 @@ pub const StandaloneModuleGraph = struct { Global.exit(1); }; + _ = bun.sys.close(fd); + + if (windows_icon) |icon_utf8| { + var icon_buf: bun.OSPathBuffer = undefined; + const icon = bun.strings.toWPathNormalized(&icon_buf, icon_utf8); + bun.windows.rescle.setIcon(outfile_slice, icon) catch { + Output.warn("Failed to set executable icon", .{}); + }; + } return; } diff --git a/src/bun.js/bindings/windows/rescle-binding.cpp b/src/bun.js/bindings/windows/rescle-binding.cpp new file mode 100644 index 0000000000..31514168e2 --- /dev/null +++ b/src/bun.js/bindings/windows/rescle-binding.cpp @@ -0,0 +1,14 @@ +#include "root.h" +#include "rescle.h" + +extern "C" int rescle__setIcon(const WCHAR* exeFilename, const WCHAR* iconFilename) +{ + rescle::ResourceUpdater updater; + if (!updater.Load(exeFilename)) + return -1; + if (!updater.SetIcon(iconFilename)) + return -2; + if (!updater.Commit()) + return -3; + return 0; +} diff --git a/src/bun.js/bindings/windows/rescle.cpp b/src/bun.js/bindings/windows/rescle.cpp new file mode 100644 index 0000000000..a3171b4eaa --- /dev/null +++ b/src/bun.js/bindings/windows/rescle.cpp @@ -0,0 +1,1090 @@ +// This file is from Electron's fork of rescle +// https://github.com/electron/rcedit/blob/e36b688b42df0e236922019ce14e0ea165dc176d/src/rescle.cc +// 'bun build --compile' uses this on Windows to allow +// patching the icon of the generated executable. +// +// Copyright (c) 2013 GitHub Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Copyright (c) 2013 GitHub, Inc. All rights reserved. +// Use of this source code is governed by MIT license that can be found in the +// LICENSE file. +// +// This file is modified from Rescle written by yoshio.okumura@gmail.com: +// http://code.google.com/p/rescle/ +#include "rescle.h" + +#include +#include +#include // wstringstream +#include // setw, setfill +#include +#include +#include + +namespace rescle { + +namespace { + +#pragma pack(push, 2) +typedef struct _GRPICONENTRY { + BYTE width; + BYTE height; + BYTE colourCount; + BYTE reserved; + BYTE planes; + BYTE bitCount; + WORD bytesInRes; + WORD bytesInRes2; + WORD reserved2; + WORD id; +} GRPICONENTRY; +#pragma pack(pop) + +#pragma pack(push, 2) +typedef struct _GRPICONHEADER { + WORD reserved; + WORD type; + WORD count; + GRPICONENTRY entries[1]; +} GRPICONHEADER; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct _VS_VERSION_HEADER { + WORD wLength; + WORD wValueLength; + WORD wType; +} VS_VERSION_HEADER; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct _VS_VERSION_STRING { + VS_VERSION_HEADER Header; + WCHAR szKey[1]; +} VS_VERSION_STRING; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct _VS_VERSION_ROOT_INFO { + WCHAR szKey[16]; + WORD Padding1[1]; + VS_FIXEDFILEINFO Info; +} VS_VERSION_ROOT_INFO; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct _VS_VERSION_ROOT { + VS_VERSION_HEADER Header; + VS_VERSION_ROOT_INFO Info; +} VS_VERSION_ROOT; +#pragma pack(pop) + +// The default en-us LANGID. +LANGID kLangEnUs = 1033; +LANGID kCodePageEnUs = 1200; +UINT kDefaultIconBundle = 0; + +template +inline T round(T value, int modula = 4) +{ + return value + ((value % modula > 0) ? (modula - value % modula) : 0); +} + +std::wstring ReadFileToString(const wchar_t* filename) +{ + std::wifstream wif(filename); + wif.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8)); + std::wstringstream wss; + wss << wif.rdbuf(); + return wss.str(); +} + +class ScopedFile { +public: + ScopedFile(const WCHAR* path) + : file_(CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) + { + } + ~ScopedFile() { CloseHandle(file_); } + + operator HANDLE() { return file_; } + +private: + HANDLE file_; +}; + +struct VersionStampValue { + WORD valueLength = 0; // stringfileinfo, stringtable: 0; string: Value size in WORD; var: Value size in bytes + WORD type = 0; // 0: binary data; 1: text data + std::wstring key; // stringtable: 8-digit hex stored as UTF-16 (hiword: hi6: sublang, lo10: majorlang; loword: code page); must include zero words to align next member on 32-bit boundary + std::vector value; // string: zero-terminated string; var: array of language & code page ID pairs + std::vector children; + + size_t GetLength() const; + std::vector Serialize() const; +}; + +} // namespace + +VersionInfo::VersionInfo() +{ + FillDefaultData(); +} + +VersionInfo::VersionInfo(HMODULE hModule, WORD languageId) +{ + HRSRC hRsrc = FindResourceExW(hModule, RT_VERSION, MAKEINTRESOURCEW(1), languageId); + + if (hRsrc == NULL) { + throw std::system_error(GetLastError(), std::system_category()); + } + + HGLOBAL hGlobal = LoadResource(hModule, hRsrc); + if (hGlobal == NULL) { + throw std::system_error(GetLastError(), std::system_category()); + } + + void* p = LockResource(hGlobal); + if (p == NULL) { + throw std::system_error(GetLastError(), std::system_category()); + } + + DWORD size = SizeofResource(hModule, hRsrc); + if (size == 0) { + throw std::system_error(GetLastError(), std::system_category()); + } + + DeserializeVersionInfo(static_cast(p), size); + FillDefaultData(); +} + +bool VersionInfo::HasFixedFileInfo() const +{ + return fixedFileInfo_.dwSignature == 0xFEEF04BD; +} + +VS_FIXEDFILEINFO& VersionInfo::GetFixedFileInfo() +{ + return fixedFileInfo_; +} + +const VS_FIXEDFILEINFO& VersionInfo::GetFixedFileInfo() const +{ + return fixedFileInfo_; +} + +void VersionInfo::SetFixedFileInfo(const VS_FIXEDFILEINFO& value) +{ + fixedFileInfo_ = value; +} + +std::vector VersionInfo::Serialize() const +{ + VersionStampValue versionInfo; + versionInfo.key = L"VS_VERSION_INFO"; + versionInfo.type = 0; + + if (HasFixedFileInfo()) { + auto size = sizeof(VS_FIXEDFILEINFO); + versionInfo.valueLength = size; + + auto& dst = versionInfo.value; + dst.resize(size); + + memcpy(&dst[0], &GetFixedFileInfo(), size); + } + + { + VersionStampValue stringFileInfo; + stringFileInfo.key = L"StringFileInfo"; + stringFileInfo.type = 1; + stringFileInfo.valueLength = 0; + + for (const auto& iTable : stringTables) { + VersionStampValue stringTableRaw; + stringTableRaw.type = 1; + stringTableRaw.valueLength = 0; + + { + auto& translate = iTable.encoding; + std::wstringstream ss; + ss << std::hex << std::setw(8) << std::setfill(L'0') << (translate.wLanguage << 16 | translate.wCodePage); + stringTableRaw.key = ss.str(); + } + + for (const auto& iString : iTable.strings) { + const auto& stringValue = iString.second; + auto strLenNullTerminated = stringValue.length() + 1; + + VersionStampValue stringRaw; + stringRaw.type = 1; + stringRaw.key = iString.first; + stringRaw.valueLength = strLenNullTerminated; + + auto size = strLenNullTerminated * sizeof(WCHAR); + auto& dst = stringRaw.value; + dst.resize(size); + + auto src = stringValue.c_str(); + + memcpy(&dst[0], src, size); + + stringTableRaw.children.push_back(std::move(stringRaw)); + } + + stringFileInfo.children.push_back(std::move(stringTableRaw)); + } + + versionInfo.children.push_back(std::move(stringFileInfo)); + } + + { + VersionStampValue varFileInfo; + varFileInfo.key = L"VarFileInfo"; + varFileInfo.type = 1; + varFileInfo.valueLength = 0; + + { + VersionStampValue varRaw; + varRaw.key = L"Translation"; + varRaw.type = 0; + + { + auto newValueSize = sizeof(DWORD); + auto& dst = varRaw.value; + dst.resize(supportedTranslations.size() * newValueSize); + + for (auto iVar = 0; iVar < supportedTranslations.size(); ++iVar) { + auto& translate = supportedTranslations[iVar]; + auto var = DWORD(translate.wCodePage) << 16 | translate.wLanguage; + memcpy(&dst[iVar * newValueSize], &var, newValueSize); + } + + varRaw.valueLength = varRaw.value.size(); + } + + varFileInfo.children.push_back(std::move(varRaw)); + } + + versionInfo.children.push_back(std::move(varFileInfo)); + } + + return std::move(versionInfo.Serialize()); +} + +void VersionInfo::FillDefaultData() +{ + if (stringTables.empty()) { + Translate enUsTranslate = { kLangEnUs, kCodePageEnUs }; + stringTables.push_back({ enUsTranslate }); + supportedTranslations.push_back(enUsTranslate); + } + if (!HasFixedFileInfo()) { + fixedFileInfo_ = { 0 }; + fixedFileInfo_.dwSignature = 0xFEEF04BD; + fixedFileInfo_.dwFileType = VFT_APP; + } +} + +void VersionInfo::DeserializeVersionInfo(const BYTE* pData, size_t size) +{ + auto pVersionInfo = reinterpret_cast(pData); + WORD fixedFileInfoSize = pVersionInfo->Header.wValueLength; + + if (fixedFileInfoSize > 0) + SetFixedFileInfo(pVersionInfo->Info.Info); + + const BYTE* fixedFileInfoEndOffset = reinterpret_cast(&pVersionInfo->Info.szKey) + (wcslen(pVersionInfo->Info.szKey) + 1) * sizeof(WCHAR) + fixedFileInfoSize; + const BYTE* pVersionInfoChildren = reinterpret_cast(round(reinterpret_cast(fixedFileInfoEndOffset))); + size_t versionInfoChildrenOffset = pVersionInfoChildren - pData; + size_t versionInfoChildrenSize = pVersionInfo->Header.wLength - versionInfoChildrenOffset; + + const auto childrenEndOffset = pVersionInfoChildren + versionInfoChildrenSize; + const auto resourceEndOffset = pData + size; + for (auto p = pVersionInfoChildren; p < childrenEndOffset && p < resourceEndOffset;) { + auto pKey = reinterpret_cast(p)->szKey; + auto versionInfoChildData = GetChildrenData(p); + if (wcscmp(pKey, L"StringFileInfo") == 0) { + DeserializeVersionStringFileInfo(versionInfoChildData.first, versionInfoChildData.second, stringTables); + } else if (wcscmp(pKey, L"VarFileInfo") == 0) { + DeserializeVarFileInfo(versionInfoChildData.first, supportedTranslations); + } + + p += round(reinterpret_cast(p)->Header.wLength); + } +} + +VersionStringTable VersionInfo::DeserializeVersionStringTable(const BYTE* tableData) +{ + auto strings = GetChildrenData(tableData); + auto stringTable = reinterpret_cast(tableData); + auto end_ptr = const_cast(stringTable->szKey + (8 * sizeof(WCHAR))); + auto langIdCodePagePair = static_cast(wcstol(stringTable->szKey, &end_ptr, 16)); + + VersionStringTable tableEntry; + + // unicode string of 8 hex digits + tableEntry.encoding.wLanguage = langIdCodePagePair >> 16; + tableEntry.encoding.wCodePage = langIdCodePagePair; + + for (auto posStrings = 0U; posStrings < strings.second;) { + const auto stringEntry = reinterpret_cast(strings.first + posStrings); + const auto stringData = GetChildrenData(strings.first + posStrings); + tableEntry.strings.push_back(std::pair(stringEntry->szKey, std::wstring(reinterpret_cast(stringData.first), stringEntry->Header.wValueLength))); + + posStrings += round(stringEntry->Header.wLength); + } + + return tableEntry; +} + +void VersionInfo::DeserializeVersionStringFileInfo(const BYTE* offset, size_t length, std::vector& stringTables) +{ + for (auto posStringTables = 0U; posStringTables < length;) { + auto stringTableEntry = DeserializeVersionStringTable(offset + posStringTables); + stringTables.push_back(stringTableEntry); + posStringTables += round(reinterpret_cast(offset + posStringTables)->Header.wLength); + } +} + +void VersionInfo::DeserializeVarFileInfo(const unsigned char* offset, std::vector& translations) +{ + const auto translatePairs = GetChildrenData(offset); + + const auto top = reinterpret_cast(translatePairs.first); + for (auto pTranslatePair = top; pTranslatePair < top + translatePairs.second; pTranslatePair += sizeof(DWORD)) { + auto codePageLangIdPair = *pTranslatePair; + Translate translate; + translate.wLanguage = codePageLangIdPair; + translate.wCodePage = codePageLangIdPair >> 16; + translations.push_back(translate); + } +} + +OffsetLengthPair VersionInfo::GetChildrenData(const BYTE* entryData) +{ + auto entry = reinterpret_cast(entryData); + auto headerOffset = entryData; + auto headerSize = sizeof(VS_VERSION_HEADER); + auto keySize = (wcslen(entry->szKey) + 1) * sizeof(WCHAR); + auto childrenOffset = round(headerSize + keySize); + + auto pChildren = headerOffset + childrenOffset; + auto childrenSize = entry->Header.wLength - childrenOffset; + return OffsetLengthPair(pChildren, childrenSize); +} + +size_t VersionStampValue::GetLength() const +{ + size_t bytes = sizeof(VS_VERSION_HEADER); + bytes += static_cast(key.length() + 1) * sizeof(WCHAR); + if (!value.empty()) + bytes = round(bytes) + value.size(); + for (const auto& child : children) + bytes = round(bytes) + static_cast(child.GetLength()); + return bytes; +} + +std::vector VersionStampValue::Serialize() const +{ + std::vector data = std::vector(GetLength()); + + size_t offset = 0; + + VS_VERSION_HEADER header = { static_cast(data.size()), valueLength, type }; + memcpy(&data[offset], &header, sizeof(header)); + offset += sizeof(header); + + auto keySize = static_cast(key.length() + 1) * sizeof(WCHAR); + memcpy(&data[offset], key.c_str(), keySize); + offset += keySize; + + if (!value.empty()) { + offset = round(offset); + memcpy(&data[offset], &value[0], value.size()); + offset += value.size(); + } + + for (const auto& child : children) { + offset = round(offset); + size_t childLength = child.GetLength(); + std::vector src = child.Serialize(); + memcpy(&data[offset], &src[0], childLength); + offset += childLength; + } + + return std::move(data); +} + +ResourceUpdater::ResourceUpdater() + : module_(NULL) +{ +} + +ResourceUpdater::~ResourceUpdater() +{ + if (module_ != NULL) { + FreeLibrary(module_); + module_ = NULL; + } +} + +bool ResourceUpdater::Load(const WCHAR* filename) +{ + wchar_t abspath[MAX_PATH] = { 0 }; + if (_wfullpath(abspath, filename, MAX_PATH)) + module_ = LoadLibraryExW(abspath, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); + else + module_ = LoadLibraryExW(filename, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); + + if (module_ == NULL) { + return false; + } + + this->filename_ = filename; + + EnumResourceNamesW(module_, RT_STRING, OnEnumResourceName, reinterpret_cast(this)); + EnumResourceNamesW(module_, RT_VERSION, OnEnumResourceName, reinterpret_cast(this)); + EnumResourceNamesW(module_, RT_GROUP_ICON, OnEnumResourceName, reinterpret_cast(this)); + EnumResourceNamesW(module_, RT_ICON, OnEnumResourceName, reinterpret_cast(this)); + EnumResourceNamesW(module_, RT_MANIFEST, OnEnumResourceManifest, reinterpret_cast(this)); + EnumResourceNamesW(module_, RT_RCDATA, OnEnumResourceName, reinterpret_cast(this)); + + return true; +} + +bool ResourceUpdater::SetExecutionLevel(const WCHAR* value) +{ + executionLevel_ = value; + return true; +} + +bool ResourceUpdater::IsExecutionLevelSet() +{ + return !executionLevel_.empty(); +} + +bool ResourceUpdater::SetApplicationManifest(const WCHAR* value) +{ + applicationManifestPath_ = value; + return true; +} + +bool ResourceUpdater::IsApplicationManifestSet() +{ + return !applicationManifestPath_.empty(); +} + +bool ResourceUpdater::SetVersionString(WORD languageId, const WCHAR* name, const WCHAR* value) +{ + std::wstring nameStr(name); + std::wstring valueStr(value); + + auto& stringTables = versionStampMap_[languageId].stringTables; + for (auto j = stringTables.begin(); j != stringTables.end(); ++j) { + auto& stringPairs = j->strings; + for (auto k = stringPairs.begin(); k != stringPairs.end(); ++k) { + if (k->first == nameStr) { + k->second = valueStr; + return true; + } + } + + // Not found, append one for all tables. + stringPairs.push_back(VersionString(nameStr, valueStr)); + } + + return true; +} + +bool ResourceUpdater::SetVersionString(const WCHAR* name, const WCHAR* value) +{ + LANGID langId = versionStampMap_.empty() ? kLangEnUs + : versionStampMap_.begin()->first; + return SetVersionString(langId, name, value); +} + +const WCHAR* ResourceUpdater::GetVersionString(WORD languageId, const WCHAR* name) +{ + std::wstring nameStr(name); + + const auto& stringTables = versionStampMap_[languageId].stringTables; + for (const auto& j : stringTables) { + const auto& stringPairs = j.strings; + for (const auto& k : stringPairs) { + if (k.first == nameStr) { + return k.second.c_str(); + } + } + } + + return NULL; +} + +const WCHAR* ResourceUpdater::GetVersionString(const WCHAR* name) +{ + if (versionStampMap_.empty()) { + return NULL; + } else { + return GetVersionString(versionStampMap_.begin()->first, name); + } +} + +bool ResourceUpdater::SetProductVersion(WORD languageId, UINT id, unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4) +{ + VersionInfo& versionInfo = versionStampMap_[languageId]; + if (!versionInfo.HasFixedFileInfo()) { + return false; + } + + VS_FIXEDFILEINFO& root = versionInfo.GetFixedFileInfo(); + + root.dwProductVersionMS = v1 << 16 | v2; + root.dwProductVersionLS = v3 << 16 | v4; + + return true; +} + +bool ResourceUpdater::SetProductVersion(unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4) +{ + LANGID langId = versionStampMap_.empty() ? kLangEnUs + : versionStampMap_.begin()->first; + return SetProductVersion(langId, 1, v1, v2, v3, v4); +} + +bool ResourceUpdater::SetFileVersion(WORD languageId, UINT id, unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4) +{ + VersionInfo& versionInfo = versionStampMap_[languageId]; + if (!versionInfo.HasFixedFileInfo()) { + return false; + } + + VS_FIXEDFILEINFO& root = versionInfo.GetFixedFileInfo(); + + root.dwFileVersionMS = v1 << 16 | v2; + root.dwFileVersionLS = v3 << 16 | v4; + return true; +} + +bool ResourceUpdater::SetFileVersion(unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4) +{ + LANGID langId = versionStampMap_.empty() ? kLangEnUs + : versionStampMap_.begin()->first; + return SetFileVersion(langId, 1, v1, v2, v3, v4); +} + +bool ResourceUpdater::ChangeString(WORD languageId, UINT id, const WCHAR* value) +{ + StringTable& table = stringTableMap_[languageId]; + + UINT blockId = id / 16; + if (table.find(blockId) == table.end()) { + // Fill the table until we reach the block. + for (size_t i = table.size(); i <= blockId; ++i) { + table[i] = std::vector(16); + } + } + + assert(table[blockId].size() == 16); + UINT blockIndex = id % 16; + table[blockId][blockIndex] = value; + + return true; +} + +bool ResourceUpdater::ChangeString(UINT id, const WCHAR* value) +{ + LANGID langId = stringTableMap_.empty() ? kLangEnUs + : stringTableMap_.begin()->first; + return ChangeString(langId, id, value); +} + +bool ResourceUpdater::ChangeRcData(UINT id, const WCHAR* pathToResource) +{ + auto rcDataLngPairIt = std::find_if(rcDataLngMap_.begin(), rcDataLngMap_.end(), [=](const auto& rcDataLngPair) { + return rcDataLngPair.second.find(id) != rcDataLngPair.second.end(); + }); + + if (rcDataLngPairIt == rcDataLngMap_.end()) { + fprintf(stderr, "Cannot find RCDATA with id '%u'\n", id); + return false; + } + + wchar_t abspath[MAX_PATH] = { 0 }; + const auto filePath = _wfullpath(abspath, pathToResource, MAX_PATH) ? abspath : pathToResource; + ScopedFile newRcDataFile(filePath); + if (newRcDataFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Cannot open new data file '%ws'\n", filePath); + return false; + } + + const auto dwFileSize = GetFileSize(newRcDataFile, NULL); + if (dwFileSize == INVALID_FILE_SIZE) { + fprintf(stderr, "Cannot get file size for '%ws'\n", filePath); + return false; + } + + auto& rcData = rcDataLngPairIt->second[id]; + rcData.clear(); + rcData.resize(dwFileSize); + + DWORD dwBytesRead { 0 }; + if (!ReadFile(newRcDataFile, rcData.data(), dwFileSize, &dwBytesRead, NULL)) { + fprintf(stderr, "Cannot read file '%ws'\n", filePath); + return false; + } + + return true; +} + +const WCHAR* ResourceUpdater::GetString(WORD languageId, UINT id) +{ + StringTable& table = stringTableMap_[languageId]; + + UINT blockId = id / 16; + if (table.find(blockId) == table.end()) { + // Fill the table until we reach the block. + for (size_t i = table.size(); i <= blockId; ++i) { + table[i] = std::vector(16); + } + } + + assert(table[blockId].size() == 16); + UINT blockIndex = id % 16; + + return table[blockId][blockIndex].c_str(); +} + +const WCHAR* ResourceUpdater::GetString(UINT id) +{ + LANGID langId = stringTableMap_.empty() ? kLangEnUs + : stringTableMap_.begin()->first; + return GetString(langId, id); +} + +bool ResourceUpdater::SetIcon(const WCHAR* path, const LANGID& langId, + UINT iconBundle) +{ + std::unique_ptr& pIcon = iconBundleMap_[langId].iconBundles[iconBundle]; + if (!pIcon) + pIcon = std::make_unique(); + + auto& icon = *pIcon; + DWORD bytes; + + ScopedFile file(path); + if (file == INVALID_HANDLE_VALUE) { + fwprintf(stderr, L"Cannot open icon file '%ls'\n", path); + return false; + } + + IconsValue::ICONHEADER& header = icon.header; + if (!ReadFile(file, &header, 3 * sizeof(WORD), &bytes, NULL)) { + fwprintf(stderr, L"Cannot read icon header for '%ls'\n", path); + return false; + } + + if (header.reserved != 0 || header.type != 1) { + fwprintf(stderr, L"Reserved header is not 0 or image type is not icon for '%ls'\n", path); + return false; + } + + header.entries.resize(header.count); + if (!ReadFile(file, header.entries.data(), header.count * sizeof(IconsValue::ICONENTRY), &bytes, NULL)) { + fwprintf(stderr, L"Cannot read icon metadata for '%ls'\n", path); + return false; + } + + icon.images.resize(header.count); + for (size_t i = 0; i < header.count; ++i) { + icon.images[i].resize(header.entries[i].bytesInRes); + SetFilePointer(file, header.entries[i].imageOffset, NULL, FILE_BEGIN); + if (!ReadFile(file, icon.images[i].data(), icon.images[i].size(), &bytes, NULL)) { + fwprintf(stderr, L"Cannot read icon data for '%ls'\n", path); + return false; + } + } + + icon.grpHeader.resize(3 * sizeof(WORD) + header.count * sizeof(GRPICONENTRY)); + GRPICONHEADER* pGrpHeader = reinterpret_cast(icon.grpHeader.data()); + pGrpHeader->reserved = 0; + pGrpHeader->type = 1; + pGrpHeader->count = header.count; + for (size_t i = 0; i < header.count; ++i) { + GRPICONENTRY* entry = pGrpHeader->entries + i; + entry->bitCount = 0; + entry->bytesInRes = header.entries[i].bitCount; + entry->bytesInRes2 = header.entries[i].bytesInRes; + entry->colourCount = header.entries[i].colorCount; + entry->height = header.entries[i].height; + entry->id = i + 1; + entry->planes = header.entries[i].planes; + entry->reserved = header.entries[i].reserved; + entry->width = header.entries[i].width; + entry->reserved2 = 0; + } + + return true; +} + +bool ResourceUpdater::SetIcon(const WCHAR* path, const LANGID& langId) +{ + if (iconBundleMap_[langId].iconBundles.empty()) { + return SetIcon(path, langId, kDefaultIconBundle); + } + UINT iconBundle = iconBundleMap_[langId].iconBundles.begin()->first; + return SetIcon(path, langId, iconBundle); +} + +bool ResourceUpdater::SetIcon(const WCHAR* path) +{ + LANGID langId = iconBundleMap_.empty() ? kLangEnUs + : iconBundleMap_.begin()->first; + return SetIcon(path, langId); +} + +bool ResourceUpdater::Commit() +{ + if (module_ == NULL) { + return false; + } + FreeLibrary(module_); + module_ = NULL; + + ScopedResourceUpdater ru(filename_.c_str(), false); + if (ru.Get() == NULL) { + return false; + } + + // update version info. + for (const auto& i : versionStampMap_) { + LANGID langId = i.first; + std::vector out = i.second.Serialize(); + + if (!UpdateResourceW(ru.Get(), RT_VERSION, MAKEINTRESOURCEW(1), langId, + &out[0], static_cast(out.size()))) { + return false; + } + } + + // update the execution level + if (applicationManifestPath_.empty() && !executionLevel_.empty()) { + // string replace with requested executionLevel + std::wstring::size_type pos = 0u; + while ((pos = manifestString_.find(originalExecutionLevel_, pos)) != std::string::npos) { + manifestString_.replace(pos, originalExecutionLevel_.length(), executionLevel_); + pos += executionLevel_.length(); + } + + // clean old padding and add new padding, ensuring that the size is a multiple of 4 + std::wstring::size_type padPos = manifestString_.find(L""); + // trim anything after the , 11 being the length of (ie, remove old padding) + std::wstring trimmedStr = manifestString_.substr(0, padPos + 11); + std::wstring padding = L"\n"; + + int offset = (trimmedStr.length() + padding.length()) % 4; + // multiple X by the number in offset + pos = 0u; + for (int posCount = 0; posCount < offset; posCount = posCount + 1) { + if ((pos = padding.find(L"X", pos)) != std::string::npos) { + padding.replace(pos, 1, L"XX"); + pos += executionLevel_.length(); + } + } + + // convert the wchar back into char, so that it encodes correctly for Windows to read the XML. + std::wstring stringSectionW = trimmedStr + padding; + std::wstring_convert, wchar_t> converter; + std::string stringSection = converter.to_bytes(stringSectionW); + + if (!UpdateResourceW(ru.Get(), RT_MANIFEST, MAKEINTRESOURCEW(1), + kLangEnUs, // this is hardcoded at 1033, ie, en-us, as that is what RT_MANIFEST default uses + &stringSection.at(0), sizeof(char) * stringSection.size())) { + return false; + } + } + + // load file contents and replace the manifest + if (!applicationManifestPath_.empty()) { + std::wstring fileContents = ReadFileToString(applicationManifestPath_.c_str()); + + // clean old padding and add new padding, ensuring that the size is a multiple of 4 + std::wstring::size_type padPos = fileContents.find(L""); + // trim anything after the , 11 being the length of (ie, remove old padding) + std::wstring trimmedStr = fileContents.substr(0, padPos + 11); + std::wstring padding = L"\n"; + + int offset = (trimmedStr.length() + padding.length()) % 4; + // multiple X by the number in offset + std::wstring::size_type pos = 0u; + for (int posCount = 0; posCount < offset; posCount = posCount + 1) { + if ((pos = padding.find(L"X", pos)) != std::string::npos) { + padding.replace(pos, 1, L"XX"); + pos += executionLevel_.length(); + } + } + + // convert the wchar back into char, so that it encodes correctly for Windows to read the XML. + std::wstring stringSectionW = fileContents + padding; + std::wstring_convert, wchar_t> converter; + std::string stringSection = converter.to_bytes(stringSectionW); + + if (!UpdateResourceW(ru.Get(), RT_MANIFEST, MAKEINTRESOURCEW(1), + kLangEnUs, // this is hardcoded at 1033, ie, en-us, as that is what RT_MANIFEST default uses + &stringSection.at(0), sizeof(char) * stringSection.size())) { + return false; + } + } + + // update string table. + for (const auto& i : stringTableMap_) { + for (const auto& j : i.second) { + std::vector stringTableBuffer; + if (!SerializeStringTable(j.second, j.first, &stringTableBuffer)) { + return false; + } + + if (!UpdateResourceW(ru.Get(), RT_STRING, MAKEINTRESOURCEW(j.first + 1), i.first, + &stringTableBuffer[0], static_cast(stringTableBuffer.size()))) { + return false; + } + } + } + + for (const auto& rcDataLangPair : rcDataLngMap_) { + for (const auto& rcDataMap : rcDataLangPair.second) { + if (!UpdateResourceW(ru.Get(), RT_RCDATA, reinterpret_cast(rcDataMap.first), + rcDataLangPair.first, (LPVOID)rcDataMap.second.data(), rcDataMap.second.size())) { + return false; + } + } + } + + for (const auto& iLangIconInfoPair : iconBundleMap_) { + auto langId = iLangIconInfoPair.first; + auto maxIconId = iLangIconInfoPair.second.maxIconId; + for (const auto& iNameBundlePair : iLangIconInfoPair.second.iconBundles) { + UINT bundleId = iNameBundlePair.first; + const std::unique_ptr& pIcon = iNameBundlePair.second; + if (!pIcon) + continue; + + auto& icon = *pIcon; + // update icon. + if (icon.grpHeader.size() > 0) { + if (!UpdateResourceW(ru.Get(), RT_GROUP_ICON, MAKEINTRESOURCEW(bundleId), + langId, icon.grpHeader.data(), icon.grpHeader.size())) { + return false; + } + + for (size_t i = 0; i < icon.header.count; ++i) { + if (!UpdateResourceW(ru.Get(), RT_ICON, MAKEINTRESOURCEW(i + 1), + langId, icon.images[i].data(), icon.images[i].size())) { + + return false; + } + } + + for (size_t i = icon.header.count; i < maxIconId; ++i) { + if (!UpdateResourceW(ru.Get(), RT_ICON, MAKEINTRESOURCEW(i + 1), + langId, nullptr, 0)) { + return false; + } + } + } + } + } + + return ru.Commit(); +} + +bool ResourceUpdater::SerializeStringTable(const StringValues& values, UINT blockId, std::vector* out) +{ + // calc total size. + // string table is pascal string list. + size_t size = 0; + for (size_t i = 0; i < 16; i++) { + size += sizeof(WORD); + size += values[i].length() * sizeof(WCHAR); + } + + out->resize(size); + + // write. + char* pDst = &(*out)[0]; + for (size_t i = 0; i < 16; i++) { + WORD length = static_cast(values[i].length()); + memcpy(pDst, &length, sizeof(length)); + pDst += sizeof(WORD); + + if (length > 0) { + WORD bytes = length * sizeof(WCHAR); + memcpy(pDst, values[i].c_str(), bytes); + pDst += bytes; + } + } + + return true; +} + +// static +BOOL CALLBACK ResourceUpdater::OnEnumResourceLanguage(HANDLE hModule, LPCWSTR lpszType, LPCWSTR lpszName, WORD wIDLanguage, LONG_PTR lParam) +{ + ResourceUpdater* instance = reinterpret_cast(lParam); + if (IS_INTRESOURCE(lpszName) && IS_INTRESOURCE(lpszType)) { + // case reinterpret_cast(RT_VERSION): { + switch (reinterpret_cast(lpszType)) { + case 16: { + try { + instance->versionStampMap_[wIDLanguage] = VersionInfo(instance->module_, wIDLanguage); + } catch (const std::system_error& e) { + return false; + } + break; + } + case 6: { + // case reinterpret_cast(RT_STRING): { + UINT id = reinterpret_cast(lpszName) - 1; + auto& vector = instance->stringTableMap_[wIDLanguage][id]; + for (size_t k = 0; k < 16; k++) { + CStringW buf; + + buf.LoadStringW(instance->module_, id * 16 + k, wIDLanguage); + vector.push_back(buf.GetBuffer()); + } + break; + } + // case reinterpret_cast(RT_ICON): { + case 3: { + UINT iconId = reinterpret_cast(lpszName); + UINT maxIconId = instance->iconBundleMap_[wIDLanguage].maxIconId; + if (iconId > maxIconId) + maxIconId = iconId; + break; + } + // case reinterpret_cast(RT_GROUP_ICON): { + case 14: { + UINT iconId = reinterpret_cast(lpszName); + instance->iconBundleMap_[wIDLanguage].iconBundles[iconId] = nullptr; + break; + } + // case reinterpret_cast(RT_RCDATA): { + case 10: { + const auto moduleHandle = HMODULE(hModule); + HRSRC hResInfo = FindResource(moduleHandle, lpszName, lpszType); + DWORD cbResource = SizeofResource(moduleHandle, hResInfo); + HGLOBAL hResData = LoadResource(moduleHandle, hResInfo); + + const auto* pResource = (const BYTE*)LockResource(hResData); + const auto resId = reinterpret_cast(lpszName); + instance->rcDataLngMap_[wIDLanguage][resId] = std::vector(pResource, pResource + cbResource); + + UnlockResource(hResData); + FreeResource(hResData); + } + default: + break; + } + } + return TRUE; +} + +// static +BOOL CALLBACK ResourceUpdater::OnEnumResourceName(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) +{ + EnumResourceLanguagesW(hModule, lpszType, lpszName, (ENUMRESLANGPROCW)OnEnumResourceLanguage, lParam); + return TRUE; +} + +// static +// courtesy of http://stackoverflow.com/questions/420852/reading-an-applications-manifest-file +BOOL CALLBACK ResourceUpdater::OnEnumResourceManifest(HMODULE hModule, LPCTSTR lpType, LPWSTR lpName, LONG_PTR lParam) +{ + ResourceUpdater* instance = reinterpret_cast(lParam); + HRSRC hResInfo = FindResource(hModule, lpName, lpType); + DWORD cbResource = SizeofResource(hModule, hResInfo); + + HGLOBAL hResData = LoadResource(hModule, hResInfo); + const BYTE* pResource = (const BYTE*)LockResource(hResData); + + // FIXME(zcbenz): Do a real UTF string convertion. + int len = strlen(reinterpret_cast(pResource)); + std::wstring manifestStringLocal(pResource, pResource + len); + + // FIXME(zcbenz): Strip the BOM instead of doing string search. + size_t start = manifestStringLocal.find(L" 0) { + manifestStringLocal = manifestStringLocal.substr(start); + } + + // Support alternative formatting, such as using " vs ' and level="..." on another line + size_t found = manifestStringLocal.find(L"requestedExecutionLevel"); + size_t level = manifestStringLocal.find(L"level=\"", found); + size_t end = manifestStringLocal.find(L"\"", level + 7); + if (level < 0) { + level = manifestStringLocal.find(L"level=\'", found); + end = manifestStringLocal.find(L"\'", level + 7); + } + + instance->originalExecutionLevel_ = manifestStringLocal.substr(level + 7, end - level - 7); + + // also store original manifestString + instance->manifestString_ = manifestStringLocal; + + UnlockResource(hResData); + FreeResource(hResData); + + return TRUE; // Keep going +} + +ScopedResourceUpdater::ScopedResourceUpdater(const WCHAR* filename, bool deleteOld) + : handle_(BeginUpdateResourceW(filename, deleteOld)) +{ +} + +ScopedResourceUpdater::~ScopedResourceUpdater() +{ + if (!commited_) { + EndUpdate(false); + } +} + +HANDLE ScopedResourceUpdater::Get() const +{ + return handle_; +} + +bool ScopedResourceUpdater::Commit() +{ + commited_ = true; + return EndUpdate(true); +} + +bool ScopedResourceUpdater::EndUpdate(bool doesCommit) +{ + BOOL fDiscard = doesCommit ? FALSE : TRUE; + BOOL bResult = EndUpdateResourceW(handle_, fDiscard); + DWORD e = GetLastError(); + return bResult ? true : false; +} + +} // namespace rescle diff --git a/src/bun.js/bindings/windows/rescle.h b/src/bun.js/bindings/windows/rescle.h new file mode 100644 index 0000000000..417de1dc0d --- /dev/null +++ b/src/bun.js/bindings/windows/rescle.h @@ -0,0 +1,211 @@ +// This file is from Electron's fork of rescle +// https://github.com/electron/rcedit/blob/e36b688b42df0e236922019ce14e0ea165dc176d/src/rescle.h +// 'bun build --compile' uses this on Windows to allow +// patching the icon of the generated executable. +// +// Copyright (c) 2013 GitHub Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Copyright (c) 2013 GitHub, Inc. All rights reserved. +// Use of this source code is governed by MIT license that can be found in the +// LICENSE file. +// +// This file is modified from Rescle written by yoshio.okumura@gmail.com: +// http://code.google.com/p/rescle/ + +#ifndef VERSION_INFO_UPDATER +#define VERSION_INFO_UPDATER + +#ifndef _UNICODE +#define _UNICODE +#endif + +#ifndef UNICODE +#define UNICODE +#endif + +#include +#include +#include + +#include +#include // unique_ptr + +#define RU_VS_COMMENTS L"Comments" +#define RU_VS_COMPANY_NAME L"CompanyName" +#define RU_VS_FILE_DESCRIPTION L"FileDescription" +#define RU_VS_FILE_VERSION L"FileVersion" +#define RU_VS_INTERNAL_NAME L"InternalName" +#define RU_VS_LEGAL_COPYRIGHT L"LegalCopyright" +#define RU_VS_LEGAL_TRADEMARKS L"LegalTrademarks" +#define RU_VS_ORIGINAL_FILENAME L"OriginalFilename" +#define RU_VS_PRIVATE_BUILD L"PrivateBuild" +#define RU_VS_PRODUCT_NAME L"ProductName" +#define RU_VS_PRODUCT_VERSION L"ProductVersion" +#define RU_VS_SPECIAL_BUILD L"SpecialBuild" + +namespace rescle { + +struct IconsValue { + typedef struct _ICONENTRY { + BYTE width; + BYTE height; + BYTE colorCount; + BYTE reserved; + WORD planes; + WORD bitCount; + DWORD bytesInRes; + DWORD imageOffset; + } ICONENTRY; + + typedef struct _ICONHEADER { + WORD reserved; + WORD type; + WORD count; + std::vector entries; + } ICONHEADER; + + ICONHEADER header; + std::vector> images; + std::vector grpHeader; +}; + +struct Translate { + LANGID wLanguage; + WORD wCodePage; +}; + +typedef std::pair VersionString; +typedef std::pair OffsetLengthPair; + +struct VersionStringTable { + Translate encoding; + std::vector strings; +}; + +class VersionInfo { +public: + VersionInfo(); + VersionInfo(HMODULE hModule, WORD languageId); + + std::vector Serialize() const; + + bool HasFixedFileInfo() const; + VS_FIXEDFILEINFO& GetFixedFileInfo(); + const VS_FIXEDFILEINFO& GetFixedFileInfo() const; + void SetFixedFileInfo(const VS_FIXEDFILEINFO& value); + + std::vector stringTables; + std::vector supportedTranslations; + +private: + VS_FIXEDFILEINFO fixedFileInfo_; + + void FillDefaultData(); + void DeserializeVersionInfo(const BYTE* pData, size_t size); + + VersionStringTable DeserializeVersionStringTable(const BYTE* tableData); + void DeserializeVersionStringFileInfo(const BYTE* offset, size_t length, std::vector& stringTables); + void DeserializeVarFileInfo(const unsigned char* offset, std::vector& translations); + OffsetLengthPair GetChildrenData(const BYTE* entryData); +}; + +class ResourceUpdater { +public: + typedef std::vector StringValues; + typedef std::map StringTable; + typedef std::map StringTableMap; + typedef std::map VersionStampMap; + typedef std::map> IconTable; + typedef std::vector RcDataValue; + typedef std::map RcDataMap; + typedef std::map RcDataLangMap; + + struct IconResInfo { + UINT maxIconId = 0; + IconTable iconBundles; + }; + + typedef std::map IconTableMap; + + ResourceUpdater(); + ~ResourceUpdater(); + + bool Load(const WCHAR* filename); + bool SetVersionString(WORD languageId, const WCHAR* name, const WCHAR* value); + bool SetVersionString(const WCHAR* name, const WCHAR* value); + const WCHAR* GetVersionString(WORD languageId, const WCHAR* name); + const WCHAR* GetVersionString(const WCHAR* name); + bool SetProductVersion(WORD languageId, UINT id, unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4); + bool SetProductVersion(unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4); + bool SetFileVersion(WORD languageId, UINT id, unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4); + bool SetFileVersion(unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4); + bool ChangeString(WORD languageId, UINT id, const WCHAR* value); + bool ChangeString(UINT id, const WCHAR* value); + bool ChangeRcData(UINT id, const WCHAR* pathToResource); + const WCHAR* GetString(WORD languageId, UINT id); + const WCHAR* GetString(UINT id); + bool SetIcon(const WCHAR* path, const LANGID& langId, UINT iconBundle); + bool SetIcon(const WCHAR* path, const LANGID& langId); + bool SetIcon(const WCHAR* path); + bool SetExecutionLevel(const WCHAR* value); + bool IsExecutionLevelSet(); + bool SetApplicationManifest(const WCHAR* value); + bool IsApplicationManifestSet(); + bool Commit(); + +private: + bool SerializeStringTable(const StringValues& values, UINT blockId, std::vector* out); + + static BOOL CALLBACK OnEnumResourceName(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam); + static BOOL CALLBACK OnEnumResourceManifest(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam); + static BOOL CALLBACK OnEnumResourceLanguage(HANDLE hModule, LPCWSTR lpszType, LPCWSTR lpszName, WORD wIDLanguage, LONG_PTR lParam); + + HMODULE module_; + std::wstring filename_; + std::wstring executionLevel_; + std::wstring originalExecutionLevel_; + std::wstring applicationManifestPath_; + std::wstring manifestString_; + VersionStampMap versionStampMap_; + StringTableMap stringTableMap_; + IconTableMap iconBundleMap_; + RcDataLangMap rcDataLngMap_; +}; + +class ScopedResourceUpdater { +public: + ScopedResourceUpdater(const WCHAR* filename, bool deleteOld); + ~ScopedResourceUpdater(); + + HANDLE Get() const; + bool Commit(); + +private: + bool EndUpdate(bool doesCommit); + + HANDLE handle_; + bool commited_ = false; +}; + +} // namespace rescle + +#endif // VERSION_INFO_UPDATER diff --git a/src/cli.zig b/src/cli.zig index 49a9124216..9c11e4d2e9 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -290,7 +290,9 @@ pub const Arguments = struct { clap.parseParam("--conditions ... Pass custom conditions to resolve") catch unreachable, clap.parseParam("--app (EXPERIMENTAL) Build a web app for production using Bun Bake.") catch unreachable, clap.parseParam("--server-components (EXPERIMENTAL) Enable server components") catch unreachable, - clap.parseParam("--env Inline environment variables into the bundle as process.env.${name}. Defaults to 'inline'. To inline environment variables matching a prefix, use my prefix like 'FOO_PUBLIC_*'. To disable, use 'disable'. In Bun v1.2+, the default is 'disable'.") catch unreachable, + clap.parseParam("--env Inline environment variables into the bundle as process.env.${name}. Defaults to 'inline'. To inline environment variables matching a prefix, use my prefix like 'FOO_PUBLIC_*'. To disable, use 'disable'. In Bun v1.2+, the default is 'disable'.") catch unreachable, + clap.parseParam("--windows-hide-console When using --compile targeting Windows, prevent a Command prompt from opening alongside the executable") catch unreachable, + clap.parseParam("--windows-icon When using --compile targeting Windows, assign an executable icon") catch unreachable, } ++ if (FeatureFlags.bake_debugging_features) [_]ParamType{ clap.parseParam("--debug-dump-server-files When --app is set, dump all server files to disk even when building statically") catch unreachable, clap.parseParam("--debug-no-minify When --app is set, do not minify anything") catch unreachable, @@ -928,6 +930,31 @@ pub const Arguments = struct { ctx.bundler_options.inline_entrypoint_import_meta_main = true; } + if (args.flag("--windows-hide-console")) { + // --windows-hide-console technically doesnt depend on WinAPI, but since since --windows-icon + // does, all of these customization options have been gated to windows-only + if (!Environment.isWindows) { + Output.errGeneric("Using --windows-hide-console is only available when compiling on Windows", .{}); + Global.crash(); + } + if (!ctx.bundler_options.compile) { + Output.errGeneric("--windows-hide-console requires --compile", .{}); + Global.crash(); + } + ctx.bundler_options.windows_hide_console = true; + } + if (args.option("--windows-icon")) |path| { + if (!Environment.isWindows) { + Output.errGeneric("Using --windows-icon is only available when compiling on Windows", .{}); + Global.crash(); + } + if (!ctx.bundler_options.compile) { + Output.errGeneric("--windows-icon requires --compile", .{}); + Global.crash(); + } + ctx.bundler_options.windows_icon = path; + } + if (args.option("--outdir")) |outdir| { if (outdir.len > 0) { ctx.bundler_options.outdir = outdir; @@ -1456,9 +1483,6 @@ pub const Command = struct { has_loaded_global_config: bool = false, pub const BundlerOptions = struct { - compile: bool = false, - compile_target: Cli.CompileTarget = .{}, - outdir: []const u8 = "", outfile: []const u8 = "", root_dir: []const u8 = "", @@ -1489,6 +1513,12 @@ pub const Command = struct { env_behavior: Api.DotEnvBehavior = .disable, env_prefix: []const u8 = "", + + // Compile options + compile: bool = false, + compile_target: Cli.CompileTarget = .{}, + windows_hide_console: bool = false, + windows_icon: ?[]const u8 = null, }; pub fn create(allocator: std.mem.Allocator, log: *logger.Log, comptime command: Command.Tag) anyerror!Context { diff --git a/src/cli/build_command.zig b/src/cli/build_command.zig index f9600fd335..e5588e9373 100644 --- a/src/cli/build_command.zig +++ b/src/cli/build_command.zig @@ -418,6 +418,8 @@ pub const BuildCommand = struct { outfile, this_bundler.env, this_bundler.options.output_format, + ctx.bundler_options.windows_hide_console, + ctx.bundler_options.windows_icon, ); const compiled_elapsed = @divTrunc(@as(i64, @truncate(std.time.nanoTimestamp() - bundled_end)), @as(i64, std.time.ns_per_ms)); const compiled_elapsed_digit_count: isize = switch (compiled_elapsed) { diff --git a/src/windows-app-info.rc b/src/windows-app-info.rc index 2822798ed0..361145deb4 100644 --- a/src/windows-app-info.rc +++ b/src/windows-app-info.rc @@ -1,6 +1,6 @@ #include "windows.h" -IDI_MYICON ICON "@BUN_ICO_PATH@" +IDI_MYICON ICON "bun.ico" VS_VERSION_INFO VERSIONINFO FILEVERSION @Bun_VERSION_MAJOR@,@Bun_VERSION_MINOR@,@Bun_VERSION_PATCH@,0 diff --git a/src/windows.zig b/src/windows.zig index 2f479c14db..b7d7d6860c 100644 --- a/src/windows.zig +++ b/src/windows.zig @@ -3627,3 +3627,33 @@ pub const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000; pub const JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x400; pub const JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x800; pub const JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000; + +const pe_header_offset_location = 0x3C; +const subsystem_offset = 0x5C; + +pub const Subsystem = enum(u16) { + windows_gui = 2, +}; + +pub fn editWin32BinarySubsystem(fd: bun.sys.File, subsystem: Subsystem) !void { + comptime bun.assert(bun.Environment.isWindows); + if (bun.windows.SetFilePointerEx(fd.handle.cast(), pe_header_offset_location, null, std.os.windows.FILE_BEGIN) == 0) + return error.Win32Error; + const offset = try fd.reader().readInt(u32, .little); + if (bun.windows.SetFilePointerEx(fd.handle.cast(), offset + subsystem_offset, null, std.os.windows.FILE_BEGIN) == 0) + return error.Win32Error; + try fd.writer().writeInt(u16, @intFromEnum(subsystem), .little); +} + +pub const rescle = struct { + extern fn rescle__setIcon([*:0]const u16, [*:0]const u16) c_int; + + pub fn setIcon(exe_path: [*:0]const u16, icon: [*:0]const u16) !void { + comptime bun.assert(bun.Environment.isWindows); + const status = rescle__setIcon(exe_path, icon); + return switch (status) { + 0 => {}, + else => error.IconEditError, + }; + } +}; From b8f28ed8afd1c2b60568b2b0158d39a674178027 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 20 Dec 2024 03:44:55 -0800 Subject: [PATCH 075/125] Bump --- LATEST | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LATEST b/LATEST index f2f5ed4e0b..5e94d235d6 100644 --- a/LATEST +++ b/LATEST @@ -1 +1 @@ -1.1.39 \ No newline at end of file +1.1.40 \ No newline at end of file diff --git a/package.json b/package.json index 79db159c7d..60e7f761c3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "bun", - "version": "1.1.40", + "version": "1.1.41", "workspaces": [ "./packages/bun-types" ], From 6e222c85235f541d8c9c24177e1ace96c46b7a1e Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:03:37 -0800 Subject: [PATCH 076/125] fix #15902 (#15911) --- src/bundler/bundle_v2.zig | 3 +- src/js_parser.zig | 94 +++++++++++++++------------------------ 2 files changed, 38 insertions(+), 59 deletions(-) diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index 260b82c242..0bc292fad1 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -15558,7 +15558,8 @@ pub const AstBuilder = struct { _ = try js_parser.ImportScanner.scan(AstBuilder, p, p.stmts.items, false, true, &hmr_transform_ctx); - const new_parts = try hmr_transform_ctx.finalize(p, parts.slice()); + try hmr_transform_ctx.finalize(p, parts.slice()); + const new_parts = parts.slice(); // preserve original capacity parts.len = @intCast(new_parts.len); bun.assert(new_parts.ptr == parts.ptr); diff --git a/src/js_parser.zig b/src/js_parser.zig index c21d275903..43c7e3f33c 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -3070,8 +3070,8 @@ pub const Parser = struct { .symbol_uses = p.symbol_uses, }; p.symbol_uses = .{}; - var parts = try p.allocator.alloc(js_ast.Part, 2); - parts[0..2].* = .{ ns_export_part, part }; + var parts = try ListManaged(js_ast.Part).initCapacity(p.allocator, 2); + parts.appendSliceAssumeCapacity(&.{ ns_export_part, part }); const exports_kind: js_ast.ExportsKind = brk: { if (expr.data == .e_undefined) { @@ -3080,7 +3080,7 @@ pub const Parser = struct { } break :brk .none; }; - return .{ .ast = try p.toAST(parts, exports_kind, .none, "") }; + return .{ .ast = try p.toAST(&parts, exports_kind, .none, "") }; } pub fn parse(self: *Parser) !js_ast.Result { @@ -4216,41 +4216,21 @@ pub const Parser = struct { ); } - var parts_slice: []js_ast.Part = &([_]js_ast.Part{}); - if (before.items.len > 0 or after.items.len > 0) { - const before_len = before.items.len; - const after_len = after.items.len; + try parts.ensureUnusedCapacity(before.items.len + after.items.len); const parts_len = parts.items.len; + parts.items.len += before.items.len + after.items.len; - const _parts = try p.allocator.alloc( - js_ast.Part, - before_len + - after_len + - parts_len, - ); - - var remaining_parts = _parts; - if (before_len > 0) { - const parts_to_copy = before.items; - bun.copy(js_ast.Part, remaining_parts, parts_to_copy); - remaining_parts = remaining_parts[parts_to_copy.len..]; + if (before.items.len > 0) { + if (parts_len > 0) { + // first copy parts to the middle if before exists + bun.copy(js_ast.Part, parts.items[before.items.len..][0..parts_len], parts.items[0..parts_len]); + } + bun.copy(js_ast.Part, parts.items[0..before.items.len], before.items); } - - if (parts_len > 0) { - const parts_to_copy = parts.items; - bun.copy(js_ast.Part, remaining_parts, parts_to_copy); - remaining_parts = remaining_parts[parts_to_copy.len..]; + if (after.items.len > 0) { + bun.copy(js_ast.Part, parts.items[parts_len + before.items.len ..][0..after.items.len], after.items); } - - if (after_len > 0) { - const parts_to_copy = after.items; - bun.copy(js_ast.Part, remaining_parts, parts_to_copy); - } - - parts_slice = _parts; - } else { - parts_slice = parts.items; } // Pop the module scope to apply the "ContainsDirectEval" rules @@ -4269,7 +4249,7 @@ pub const Parser = struct { } } - return js_ast.Result{ .ast = try p.toAST(parts_slice, exports_kind, wrap_mode, hashbang) }; + return js_ast.Result{ .ast = try p.toAST(&parts, exports_kind, wrap_mode, hashbang) }; } pub fn init(_options: Options, log: *logger.Log, source: *const logger.Source, define: *Define, allocator: Allocator) !Parser { @@ -23282,13 +23262,12 @@ fn NewParser_( pub fn toAST( p: *P, - input_parts: []js_ast.Part, + parts: *ListManaged(js_ast.Part), exports_kind: js_ast.ExportsKind, wrap_mode: WrapMode, hashbang: []const u8, ) !js_ast.Ast { const allocator = p.allocator; - var parts = input_parts; // if (p.options.tree_shaking and p.options.features.trim_unused_imports) { // p.treeShake(&parts, false); @@ -23306,20 +23285,20 @@ fn NewParser_( bun.assert(!p.options.tree_shaking); bun.assert(p.options.features.hot_module_reloading); - var hmr_transform_ctx = ConvertESMExportsForHmr{ .last_part = &parts[parts.len - 1] }; + var hmr_transform_ctx = ConvertESMExportsForHmr{ .last_part = &parts.items[parts.items.len - 1] }; try hmr_transform_ctx.stmts.ensureTotalCapacity(p.allocator, prealloc_count: { // get a estimate on how many statements there are going to be var count: usize = 0; - for (parts) |part| count += part.stmts.len; + for (parts.items) |part| count += part.stmts.len; break :prealloc_count count + 2; }); - for (parts) |part| { + for (parts.items) |part| { // Bake does not care about 'import =', as it handles it on it's own _ = try ImportScanner.scan(P, p, part.stmts, wrap_mode != .none, true, &hmr_transform_ctx); } - parts = try hmr_transform_ctx.finalize(p, parts); + try hmr_transform_ctx.finalize(p, parts.items); } else { // Handle import paths after the whole file has been visited because we need // symbol usage counts to be able to remove unused type-only imports in @@ -23331,7 +23310,7 @@ fn NewParser_( const begin = parts_end; // Potentially remove some statements, then filter out parts to remove any // with no statements - for (parts[begin..]) |part_| { + for (parts.items[begin..]) |part_| { var part = part_; p.import_records_for_current_part.clearRetainingCapacity(); p.declared_symbols.clearRetainingCapacity(); @@ -23362,7 +23341,7 @@ fn NewParser_( part.import_record_indices.append(p.allocator, p.import_records_for_current_part.items) catch unreachable; } - parts[parts_end] = part; + parts.items[parts_end] = part; parts_end += 1; } } @@ -23375,11 +23354,11 @@ fn NewParser_( } // leave the first part in there for namespace export when bundling - parts = parts[0..parts_end]; + parts.items.len = parts_end; // Do a second pass for exported items now that imported items are filled out. // This isn't done for HMR because it already deletes all `.s_export_clause`s - for (parts) |part| { + for (parts.items) |part| { for (part.stmts) |stmt| { switch (stmt.data) { .s_export_clause => |clause| { @@ -23417,14 +23396,14 @@ fn NewParser_( } var total_stmts_count: usize = 0; - for (parts) |part| { + for (parts.items) |part| { total_stmts_count += part.stmts.len; } const preserve_strict_mode = p.module_scope.strict_mode == .explicit_strict_mode and - !(parts.len > 0 and - parts[0].stmts.len > 0 and - parts[0].stmts[0].data == .s_directive); + !(parts.items.len > 0 and + parts.items[0].stmts.len > 0 and + parts.items[0].stmts[0].data == .s_directive); total_stmts_count += @as(usize, @intCast(@intFromBool(preserve_strict_mode))); @@ -23441,7 +23420,7 @@ fn NewParser_( remaining_stmts = remaining_stmts[1..]; } - for (parts) |part| { + for (parts.items) |part| { for (part.stmts, remaining_stmts[0..part.stmts.len]) |src, *dest| { dest.* = src; } @@ -23463,14 +23442,16 @@ fn NewParser_( ); var top_level_stmts = p.allocator.alloc(Stmt, 1) catch bun.outOfMemory(); - parts[0].stmts = top_level_stmts; top_level_stmts[0] = p.s( S.SExpr{ .value = wrapper, }, logger.Loc.Empty, ); - parts.len = 1; + + try parts.ensureUnusedCapacity(1); + parts.items.len = 1; + parts.items[0].stmts = top_level_stmts; } var top_level_symbols_to_parts = js_ast.Ast.TopLevelSymbolToParts{}; @@ -23503,7 +23484,7 @@ fn NewParser_( }; // Each part tracks the other parts it depends on within this file - for (parts, 0..) |*part, part_index| { + for (parts.items, 0..) |*part, part_index| { const decls = &part.declared_symbols; const ctx = Ctx{ .allocator = p.allocator, @@ -23529,7 +23510,7 @@ fn NewParser_( } const wrapper_ref: Ref = brk: { - if (p.options.bundle and p.needsWrapperRef(parts)) { + if (p.options.bundle and p.needsWrapperRef(parts.items)) { break :brk p.newSymbol( .other, std.fmt.allocPrint( @@ -23543,8 +23524,7 @@ fn NewParser_( break :brk Ref.None; }; - var parts_list = bun.BabyList(js_ast.Part).init(parts); - parts_list.cap = @intCast(input_parts.len); + const parts_list = bun.BabyList(js_ast.Part).fromList(parts); return .{ .runtime_imports = p.runtime_imports, @@ -24105,7 +24085,7 @@ pub const ConvertESMExportsForHmr = struct { } } - pub fn finalize(ctx: *ConvertESMExportsForHmr, p: anytype, all_parts: []js_ast.Part) ![]js_ast.Part { + pub fn finalize(ctx: *ConvertESMExportsForHmr, p: anytype, all_parts: []js_ast.Part) !void { if (ctx.export_props.items.len > 0) { try ctx.stmts.append(p.allocator, Stmt.alloc(S.SExpr, .{ .value = Expr.assign( @@ -24152,8 +24132,6 @@ pub const ConvertESMExportsForHmr = struct { ctx.last_part.stmts = ctx.stmts.items; ctx.last_part.tag = .none; - - return all_parts; } }; From ac3cd09a42082bdb959962db498f0cfdc1b245af Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 20 Dec 2024 17:54:39 -0800 Subject: [PATCH 077/125] Bump --- LATEST | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LATEST b/LATEST index 5e94d235d6..2c6bb72b8c 100644 --- a/LATEST +++ b/LATEST @@ -1 +1 @@ -1.1.40 \ No newline at end of file +1.1.41 \ No newline at end of file diff --git a/package.json b/package.json index 60e7f761c3..56ad737a1d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "bun", - "version": "1.1.41", + "version": "1.1.42", "workspaces": [ "./packages/bun-types" ], From 50eec0025b482ad7b340c82f64749903b2fad4b8 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 20 Dec 2024 19:28:13 -0800 Subject: [PATCH 078/125] Add regression test for #15902 --- test/cli/run/syntax.test.ts | 340 ++++++++++++++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 test/cli/run/syntax.test.ts diff --git a/test/cli/run/syntax.test.ts b/test/cli/run/syntax.test.ts new file mode 100644 index 0000000000..8da864184f --- /dev/null +++ b/test/cli/run/syntax.test.ts @@ -0,0 +1,340 @@ +import { describe, expect, test } from "bun:test"; +import { bunEnv, bunExe, tempDirWithFiles } from "harness"; +import { join } from "path"; + +const exitCode0 = [ + " ", + "\n", + "\t", + "\r\n", + " ", + "\n\n\n", + "export default '\\u{000C}'", + "export default '\\u{200B}'", + "export default '\\u{200C}'", + "export default '\\u{200D}'", + "export default '\\u{FEFF}'", + '"use strict";', + '"use strict";\n', + "'use strict';", + '"use strict";\n\n', + '"use asm";', + '"use asm";\n', + "'use strict'; 'use asm';", + '"use strict"; "use strict";', + "// empty comment", + "/* empty block comment */", + "/** JSDoc comment */", + "//\n//\n//", + "/* \n Multi\n line\n comment\n */", + "-->", + "// TODO: ", + "/** @type {number} */", + "const a = 123;", + "let a;", + "var a = undefined;", + "const a = null;", + "const [a] = [];", + "const {a} = {};", + "const [...a] = [];", + "const {...a} = {};", + "let [a = 1] = [];", + "let {a: b = 1} = {};", + "``", + "`template`", + "`template${123}`", + "`${null}`", + "`${'`'}`", + "`\n`", + "`\n`", + "({});", + "({ a: 1 });", + "({ ['computed']: 1 });", + "({ get x() { return 1; } });", + "({ __proto__: null });", + "({ get [1+2](){}, set [1+2](x){} });", + "({ a: 1, ...{b: 2} });", + "[];", + "[,];", + "[,,];", + "[1,];", + "[,...[1]];", + "[,,...[1]];", + "[[[[[]]]]]", + "[...[...[...[]]]]", + "[1,,2,,3];", + "Array(1_000_000).fill(1);", + "()=>{};", + "async()=>{};", + "(function(){}).bind(null);", + "()=>()=>()=>1;", + "function f(a=1,{b}={},...c){};", + "async function* f(){await 1; yield 2;};", + "(async()=>await 1)();", + "class A{}", + "class A extends null{}", + "class A{#private=1}", + "class A{static{}}", + "class A{get #a(){} set #a(x){}}", + "class A{*#gen(){yield this.#p}#p=1}", + "class A extends class B{}{};", + "export {};", + "export default 1;", + "export default function(){};", + "import.meta.url;", + "const pi = Math.PI;", + "const hello = 'world';", + "const star = '⭐';", + "'\\u0000\\uFFFF';", + "'\\x00\\xFF';", + "const \\u{61} = 1;", + "'\\0';", + "'\\v\\f\\b';", + "'\\\r\n';", + "/./;", + "/[]/;", + "/[^]/;", + "/\\u{0}/u;", + "/[\\u0000-\\u{10FFFF}]/u;", + "/./gimsuyd;", + "/\\p{Script=Latin}/u;", + "/(?<=a)b/;", + "/(?/;", + "1n;", + "0n;", + "9007199254740991n;", + "0b1n;", + "0o7n;", + "0xFn;", + "1_2_3n;", + "BigInt(1);", + "-0n;", + "~0n;", + "0b1_0_1;", + "0o7_7_7;", + "0xF_F_F;", + "1_2_3_4;", + "try{}catch{}", + "try{}catch(e){}", + "try{}catch{}finally{}", + "try{}finally{}", + "try{throw 1}catch(e){}", + "try{throw new Error}catch{}", + "try{throw{}}catch({message}){}", + "try{throw null}catch(e){}", + "try{throw undefined}catch(e){}", + "try{throw function(){}}catch(e){}", + "function*g(){yield;}", + "function*g(){yield*g();}", + "async function*g(){yield;}", + "async function*g(){await 1;}", + "(async function*(){for await(x of y){}});", + "function*g(){try{yield}finally{}}", + "[...new Set];", + "for(x of[]){}", + "for await(x of[]){}", + "async function f(){for await(x of y){}}", + "void 0;", + "new (class{})();", + "(class extends null{});", + "(class{[Symbol.hasInstance](){}});", + "function*g(){yield yield yield;}", + "1..toString();", + "`${`${`${1}`}`}`", + "String.raw`\n`", + "String.raw`\\n`", + "`${`${function*(){yield 1}}`}`", + "`${class{}}${()=>{}}${/./}`", + "`${`${async()=>await 1}`}`", + "`${`${class{static{``}}}`}`", + "await import('bun');", + "await import('bun:ffi');", + "await import(import.meta.path);", + "/(?:)/", + "/\\b\\B\\d\\D\\w\\W\\s\\S/", + "/\\cA\\cZ\\ca\\cz/", + "/\\p{General_Category=Letter}/u", + "/\\p{Script_Extensions=Latin}/u", + "/(?<=(?=a)b)c/", + "/(?\\k/", + "/\\u{10FFFF}\\u{0000}/u", + "/[\\p{ASCII}--\\p{Decimal_Number}]/v", + "const [{a: [b = 1] = []} = [{a: [2]}]] = [];", + "let {a: {b: {c = 1} = {}} = {}} = {};", + "const [a, , ...{0: b, length}] = [];", + "const {[class{}.prop]: x} = {};", + "const {[()=>{}]: x} = {};", + "let {[/./]: x} = {};", + "const {[class extends null{}]: x} = {};", + "const {[function*(){}]: x} = {};", + "function f([a] = [1], {b} = {b: 2}, ...c){}", + "(function({[key]: value} = {}){})", + "(({[this?.prop]: x} = {})=>{})", + "function f(a = () => b, b = 1){}", + "(a = class{}, b = new a)=>{}", + "function f(a = new.target){}", + "for await(const x of async function*(){yield 1}()){}", + "for(const x of function*(){yield 1}()){}", + "for(const {[key]: x} of []){}", + "for(let [{a = 1} = {}] of []){}", + "do{continue}while(false);", + "label:do{break label}while(false);", + "outer:for(;;)inner:break outer;", + "block:{break block;}", + "while(false)with(null);", + "switch(0){case 1:default:case 2:}", + "try{throw async()=>{}}catch(e){await e}", + "try{throw class{}}catch(e){new e}", + "try{throw{[Symbol.iterator]:()=>{}}}catch(e){}", + "try{throw Object.create(null)}catch(e){}", + "try{throw new Proxy({},{})}catch(e){}", + "try{throw new WeakMap}catch(e){}", + "try{throw new Int32Array}catch(e){}", + "try{throw new SharedArrayBuffer(0)}catch(e){}", + "try{throw new WebAssembly.Module(new Uint8Array)}catch(e){}", + "void void void 0;", + "typeof typeof typeof 0;", + "delete (delete (delete 0));", + "await (await (await 1));", + "--{a:1}.a;", + "(class{}).prototype.constructor;", + "(()=>{}).prototype?.call;", + "(async()=>{}).prototype?.call;", + "(function*(){}).prototype.next;", + "(async function*(){}).prototype.next;", + "this?.prop?.[key]?.();", + "0b0_1_0_1;", + "0B0_1_0_1;", + "0o0_1_2_3;", + "0O0_1_2_3;", + "0x0_1_2_3;", + "0X0_1_2_3;", + "1_2_3.4_5_6;", + "1_2_3e1_2_3;", + "1_2_3E1_2_3;", + ".0_1_2_3;", + "0b1_0_1n;", + "0B1_0_1n;", + "0o1_2_3n;", + "0O1_2_3n;", + "0x1_2_3n;", + "0X1_2_3n;", + "1_2_3_4_5n;", + "BigInt(0b101);", + "BigInt(0o777);", + "BigInt(0xff);", + "for(const [,,...a] of [[]]){}", + "for(let {a: [b]} of []){}", + "for await(const [a = await 1] of []){}", + "for(const {[await 1]: x} of []){}", + "for(var {[class{}]: x} of []){}", + "for(let {[/./]: x} of []){}", + "for(const {[`${a}`]: x} of []){}", + "for await(const x of async function*(){yield*[1,2,3]}()){}", + "new class extends (await Promise.resolve(class{})){}", + "function*g(){yield yield*function*(){yield yield yield;}();}", + "async function*f(){yield await Promise.all([1,2,3])}", + "async function*f(){yield*[await 1,await 2]}", + "(async function(){await (async()=>1)()})();", + "async function*f(){for await(const x of async function*(){yield 1}())yield x}", + "async function f(){return await new Promise(r=>r(1))}", + "async function*f(){try{yield await 1}finally{await 2}}", + "(async()=>{for await(const x of[])for await(const y of[]){}})();", + "async function*f(){yield await(yield await(yield await 1))}", + "async function*f(){yield*async function*(){yield await 1}()}", + "export default await(async()=>1)();", + "function*g(){yield*{[Symbol.iterator]:function*(){yield 1}}}", + "function*g(){yield*{async*[Symbol.asyncIterator](){yield 1}}}", + "function*g(){yield*function*(){yield function*(){yield 1}}()}", + "function*g(){yield*{get[Symbol.iterator](){return function*(){yield 1}}}}", + "function*g(){yield*(class{static*[Symbol.iterator](){yield 1}});}", + "function*g(){yield*class{static*[Symbol.iterator](){yield 1}}}", + "function*g(){yield*{*[Symbol.iterator](){yield class{}}}}", + "function*g(){yield*{*[Symbol.iterator](){yield function(){}}}}", + "function*g(){yield*{*[Symbol.iterator](){yield async()=>{}}}}", + "function*g(){yield*{*[Symbol.iterator](){yield function*(){}}}}", + "({[function*(){yield 1}]:1});", + "({[async function*(){yield 1}]:1});", + "({[(()=>class{})()]:1});", + "({[new class{valueOf(){return 1}}]:2});", + "({[new class{[Symbol.toPrimitive](){return 1}}]:2});", + "({[new class{toString(){return '1'}}]:2});", + "({[new class{get [Symbol.toPrimitive](){return()=>1}}]:2});", + "({[new class{static{this.prototype.valueOf=()=>1}}]:2});", + "label:while(1)try{continue label}finally{break label}", + "new Proxy(class{},{construct(){return{}}});", + "new Proxy(function(){},{apply(){return{}}});", + "new Proxy({},{get(){return new Proxy({},{})}})", + "new Proxy([],{get(){return new Proxy({},{})}});", + "new Proxy(function(){},{construct(){return new Proxy({},{})}})", + "new Proxy(class{},{construct(){return new Proxy({},{})}})", + "new Proxy({},{get(){return function(){return new Proxy({},{})}}})", + "new Proxy(function(){},{apply(){return new Proxy(class{},{})}})", + "new Proxy(class{},{construct(){return new Proxy(function(){},{})}})", + "Reflect.get(new Proxy({},{}),'')", + "Reflect.set(new Proxy({},{}),'')", + "Reflect.has(new Proxy({},{}),'')", + "Reflect.deleteProperty(new Proxy({},{}),'')", + "Reflect.getOwnPropertyDescriptor(new Proxy({},{}),'')", + "Reflect.getPrototypeOf(new Proxy({},{}))", + "Reflect.setPrototypeOf(new Proxy({},{}),{})", + "Reflect.isExtensible(new Proxy({},{}))", + "Reflect.preventExtensions(new Proxy({},{}))", + "Promise.all([Promise.race([]),Promise.allSettled([])])", + "Promise.race([Promise.all([]),Promise.any([])])", + "Promise.allSettled([Promise.race([]),Promise.all([])])", + "Promise.any([Promise.allSettled([]),Promise.race([])])", + "Promise.resolve(Promise.reject().catch(()=>Promise.all([])))", + "new Function(`return function*(){${`yield${`yield${`yield`}`}`}}`)();", + "new Function(`return async()=>${`await${`await${`1`}`}`}`)();", + "new Function(`return class{${`*[Symbol.iterator](){${`yield 1`}}`}}`)();", + "new Function(`return class{${`async*[Symbol.asyncIterator](){${`yield 1`}}`}}`)();", + "new Function(`return class{${`get #a(){${`return 1`}}`}}`)();", + "new Function(`return class{${`set #a(v){${`this.#b=v`}}#b`}}`)();", + "new Function(`return class{${`#a;${`#b;${`#c`}`}`}}`)();", + "for await(let {...x} of async function*(){yield*[]}()){}", + "for await(const x of (async function*(){yield await 1})()){}", + "function f(){let a=b,b=1}", + "(function(){const[a=b,b=1]=[]})", + "(()=>{let{a=b,b=1}={}})", +]; + +describe("exit code 0", () => { + const fixturePath = tempDirWithFiles("fixture", { + [`package.json`]: `{ + "name": "test", + + }`, + "fixture.js": "export default 1", + }); + + for (let i = 0; i < exitCode0.length; i++) { + const source = exitCode0[i]; + + test(`file #${i}: ${JSON.stringify(source)}`, async () => { + await Bun.write(join(fixturePath, "fixture.js"), source); + await using proc = Bun.spawn([bunExe(), "./fixture.js"], { + stdout: "inherit", + env: bunEnv, + cwd: fixturePath, + stderr: "inherit", + stdin: "inherit", + }); + const exitCode = await proc.exited; + expect(exitCode).toBe(0); + }); + + test(`eval #${i}: ${JSON.stringify(source)}`, async () => { + await using proc = Bun.spawn([bunExe(), "--eval", source], { + stdout: "inherit", + env: bunEnv, + stderr: "inherit", + stdin: "inherit", + }); + const exitCode = await proc.exited; + expect(exitCode).toBe(0); + }); + } +}); From acb9fdfcf5edcc03f9ba80d670b98b364e24d610 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Fri, 20 Dec 2024 20:59:07 -0800 Subject: [PATCH 079/125] refactor: organize native glob code (#15914) Co-authored-by: DonIsaac --- src/bun.js/api/glob.zig | 5 +- src/cli/filter_arg.zig | 6 +- src/cli/outdated_command.zig | 6 +- src/cli/pack_command.zig | 8 +- src/glob.zig | 2204 +----------------------- src/glob/GlobWalker.zig | 2191 +++++++++++++++++++++++ src/{glob_ascii.zig => glob/ascii.zig} | 33 + src/install/lockfile.zig | 5 +- src/shell/interpreter.zig | 2 +- 9 files changed, 2245 insertions(+), 2215 deletions(-) create mode 100644 src/glob/GlobWalker.zig rename src/{glob_ascii.zig => glob/ascii.zig} (93%) diff --git a/src/bun.js/api/glob.zig b/src/bun.js/api/glob.zig index 85051929db..edf341ec6a 100644 --- a/src/bun.js/api/glob.zig +++ b/src/bun.js/api/glob.zig @@ -1,6 +1,5 @@ const Glob = @This(); const globImpl = @import("../../glob.zig"); -const globImplAscii = @import("../../glob_ascii.zig"); const GlobWalker = globImpl.BunGlobWalker; const PathLike = @import("../node/types.zig").PathLike; const ArgumentsSlice = @import("../node/types.zig").ArgumentsSlice; @@ -407,7 +406,7 @@ pub fn match(this: *Glob, globalThis: *JSGlobalObject, callframe: *JSC.CallFrame var str = str_arg.toSlice(globalThis, arena.allocator()); defer str.deinit(); - if (this.is_ascii and isAllAscii(str.slice())) return JSC.JSValue.jsBoolean(globImplAscii.match(this.pattern, str.slice())); + if (this.is_ascii and isAllAscii(str.slice())) return JSC.JSValue.jsBoolean(globImpl.Ascii.match(this.pattern, str.slice())); const codepoints = codepoints: { if (this.pattern_codepoints) |cp| break :codepoints cp.items[0..]; @@ -422,7 +421,7 @@ pub fn match(this: *Glob, globalThis: *JSGlobalObject, callframe: *JSC.CallFrame break :codepoints codepoints.items[0..codepoints.items.len]; }; - return if (globImpl.matchImpl(codepoints, str.slice()).matches()) .true else .false; + return if (globImpl.walk.matchImpl(codepoints, str.slice()).matches()) .true else .false; } pub fn convertUtf8(codepoints: *std.ArrayList(u32), pattern: []const u8) !void { diff --git a/src/cli/filter_arg.zig b/src/cli/filter_arg.zig index 99031058d5..2bf9df67a9 100644 --- a/src/cli/filter_arg.zig +++ b/src/cli/filter_arg.zig @@ -34,7 +34,7 @@ fn globIgnoreFn(val: []const u8) bool { return false; } -const GlobWalker = Glob.GlobWalker_(globIgnoreFn, Glob.DirEntryAccessor, false); +const GlobWalker = Glob.GlobWalker(globIgnoreFn, Glob.walk.DirEntryAccessor, false); pub fn getCandidatePackagePatterns(allocator: std.mem.Allocator, log: *bun.logger.Log, out_patterns: *std.ArrayList([]u8), workdir_: []const u8, root_buf: *bun.PathBuffer) ![]const u8 { bun.JSAst.Expr.Data.Store.create(); @@ -187,7 +187,7 @@ pub const FilterSet = struct { pub fn matchesPath(self: *const FilterSet, path: []const u8) bool { for (self.filters) |filter| { - if (Glob.matchImpl(filter.codepoints, path).matches()) { + if (Glob.walk.matchImpl(filter.codepoints, path).matches()) { return true; } } @@ -200,7 +200,7 @@ pub const FilterSet = struct { .name => name, .path => path, }; - if (Glob.matchImpl(filter.codepoints, target).matches()) { + if (Glob.walk.matchImpl(filter.codepoints, target).matches()) { return true; } } diff --git a/src/cli/outdated_command.zig b/src/cli/outdated_command.zig index f24d333182..447f309bea 100644 --- a/src/cli/outdated_command.zig +++ b/src/cli/outdated_command.zig @@ -212,14 +212,14 @@ pub const OutdatedCommand = struct { const abs_res_path = path.joinAbsString(FileSystem.instance.top_level_dir, &[_]string{res_path}, .posix); - if (!glob.matchImpl(pattern, strings.withoutTrailingSlash(abs_res_path)).matches()) { + if (!glob.walk.matchImpl(pattern, strings.withoutTrailingSlash(abs_res_path)).matches()) { break :matched false; } }, .name => |pattern| { const name = pkg_names[workspace_pkg_id].slice(string_buf); - if (!glob.matchImpl(pattern, name).matches()) { + if (!glob.walk.matchImpl(pattern, name).matches()) { break :matched false; } }, @@ -331,7 +331,7 @@ pub const OutdatedCommand = struct { .path => unreachable, .name => |name_pattern| { if (name_pattern.len == 0) continue; - if (!glob.matchImpl(name_pattern, dep.name.slice(string_buf)).matches()) { + if (!glob.walk.matchImpl(name_pattern, dep.name.slice(string_buf)).matches()) { break :match false; } }, diff --git a/src/cli/pack_command.zig b/src/cli/pack_command.zig index 195a9c3edf..1aae3deb27 100644 --- a/src/cli/pack_command.zig +++ b/src/cli/pack_command.zig @@ -335,7 +335,7 @@ pub const PackCommand = struct { // normally the behavior of `index.js` and `**/index.js` are the same, // but includes require `**/` const match_path = if (include.@"leading **/") entry_name else entry_subpath; - switch (glob.matchImpl(include.glob, match_path)) { + switch (glob.walk.matchImpl(include.glob, match_path)) { .match => included = true, .negate_no_match => included = false, @@ -976,7 +976,7 @@ pub const PackCommand = struct { // check default ignores that only apply to the root project directory for (root_default_ignore_patterns) |pattern| { - switch (glob.matchImpl(pattern, entry_name)) { + switch (glob.walk.matchImpl(pattern, entry_name)) { .match => { // cannot be reversed return .{ @@ -1003,7 +1003,7 @@ pub const PackCommand = struct { for (default_ignore_patterns) |pattern_info| { const pattern, const can_override = pattern_info; - switch (glob.matchImpl(pattern, entry_name)) { + switch (glob.walk.matchImpl(pattern, entry_name)) { .match => { if (can_override) { ignored = true; @@ -1045,7 +1045,7 @@ pub const PackCommand = struct { if (pattern.dirs_only and entry.kind != .directory) continue; const match_path = if (pattern.rel_path) rel else entry_name; - switch (glob.matchImpl(pattern.glob, match_path)) { + switch (glob.walk.matchImpl(pattern.glob, match_path)) { .match => { ignored = true; ignore_pattern = pattern.glob; diff --git a/src/glob.zig b/src/glob.zig index 3b97954620..09248b37ae 100644 --- a/src/glob.zig +++ b/src/glob.zig @@ -1,2200 +1,6 @@ -// Portions of this file are derived from works under the MIT License: -// -// Copyright (c) 2023 Devon Govett -// Copyright (c) 2023 Stephen Gregoratto -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -const std = @import("std"); -const bun = @import("root").bun; +pub const walk = @import("./glob/GlobWalker.zig"); +pub const Ascii = @import("./glob/ascii.zig"); -const eqlComptime = @import("./string_immutable.zig").eqlComptime; -const expect = std.testing.expect; -const isAllAscii = @import("./string_immutable.zig").isAllASCII; -const math = std.math; -const mem = std.mem; -const isWindows = @import("builtin").os.tag == .windows; - -const Allocator = std.mem.Allocator; -const Arena = std.heap.ArenaAllocator; -const ArrayList = std.ArrayListUnmanaged; -const ArrayListManaged = std.ArrayList; -const BunString = bun.String; -const C = @import("./c.zig"); -const CodepointIterator = @import("./string_immutable.zig").PackedCodepointIterator; -const Codepoint = CodepointIterator.Cursor.CodePointType; -const Dirent = @import("./bun.js/node/types.zig").Dirent; -const DirIterator = @import("./bun.js/node/dir_iterator.zig"); -const EntryKind = @import("./bun.js/node/types.zig").Dirent.Kind; -const GlobAscii = @import("./glob_ascii.zig"); -const JSC = bun.JSC; -const Maybe = JSC.Maybe; -const PathLike = @import("./bun.js/node/types.zig").PathLike; -const PathString = @import("./string_types.zig").PathString; -const ResolvePath = @import("./resolver/resolve_path.zig"); -const Syscall = bun.sys; -const ZigString = @import("./bun.js/bindings/bindings.zig").ZigString; - -// const Codepoint = u32; -const Cursor = CodepointIterator.Cursor; - -const log = bun.Output.scoped(.Glob, false); - -const CursorState = struct { - cursor: CodepointIterator.Cursor = .{}, - /// The index in terms of codepoints - // cp_idx: usize, - - fn init(iterator: *const CodepointIterator) CursorState { - var this_cursor: CodepointIterator.Cursor = .{}; - _ = iterator.next(&this_cursor); - return .{ - // .cp_idx = 0, - .cursor = this_cursor, - }; - } - - /// Return cursor pos of next codepoint without modifying the current. - /// - /// NOTE: If there is no next codepoint (cursor is at the last one), then - /// the returned cursor will have `c` as zero value and `i` will be >= - /// sourceBytes.len - fn peek(this: *const CursorState, iterator: *const CodepointIterator) CursorState { - var cpy = this.*; - // If outside of bounds - if (!iterator.next(&cpy.cursor)) { - // This will make `i >= sourceBytes.len` - cpy.cursor.i += cpy.cursor.width; - cpy.cursor.width = 1; - cpy.cursor.c = CodepointIterator.ZeroValue; - } - // cpy.cp_idx += 1; - return cpy; - } - - fn bump(this: *CursorState, iterator: *const CodepointIterator) void { - if (!iterator.next(&this.cursor)) { - this.cursor.i += this.cursor.width; - this.cursor.width = 1; - this.cursor.c = CodepointIterator.ZeroValue; - } - // this.cp_idx += 1; - } - - inline fn manualBumpAscii(this: *CursorState, i: u32, nextCp: Codepoint) void { - this.cursor.i += i; - this.cursor.c = nextCp; - this.cursor.width = 1; - } - - inline fn manualPeekAscii(this: *CursorState, i: u32, nextCp: Codepoint) CursorState { - return .{ - .cursor = CodepointIterator.Cursor{ - .i = this.cursor.i + i, - .c = @truncate(nextCp), - .width = 1, - }, - }; - } -}; - -pub const BunGlobWalker = GlobWalker_(null, SyscallAccessor, false); - -fn dummyFilterTrue(val: []const u8) bool { - _ = val; - return true; -} - -fn dummyFilterFalse(val: []const u8) bool { - _ = val; - return false; -} - -pub fn statatWindows(fd: bun.FileDescriptor, path: [:0]const u8) Maybe(bun.Stat) { - if (comptime !bun.Environment.isWindows) @compileError("oi don't use this"); - var buf: bun.PathBuffer = undefined; - const dir = switch (Syscall.getFdPath(fd, &buf)) { - .err => |e| return .{ .err = e }, - .result => |s| s, - }; - const parts: []const []const u8 = &.{ - dir[0..dir.len], - path, - }; - const statpath = ResolvePath.joinZBuf(&buf, parts, .auto); - return Syscall.stat(statpath); -} - -pub const SyscallAccessor = struct { - const count_fds = true; - - const Handle = struct { - value: bun.FileDescriptor, - - const zero = Handle{ .value = bun.FileDescriptor.zero }; - - pub fn isZero(this: Handle) bool { - return this.value == bun.FileDescriptor.zero; - } - - pub fn eql(this: Handle, other: Handle) bool { - return this.value == other.value; - } - }; - - const DirIter = struct { - value: DirIterator.WrappedIterator, - - pub inline fn next(self: *DirIter) Maybe(?DirIterator.IteratorResult) { - return self.value.next(); - } - - pub inline fn iterate(dir: Handle) DirIter { - return .{ .value = DirIterator.WrappedIterator.init(dir.value.asDir()) }; - } - }; - - pub fn open(path: [:0]const u8) !Maybe(Handle) { - return switch (Syscall.open(path, bun.O.DIRECTORY | bun.O.RDONLY, 0)) { - .err => |err| .{ .err = err }, - .result => |fd| .{ .result = Handle{ .value = fd } }, - }; - } - - pub fn statat(handle: Handle, path: [:0]const u8) Maybe(bun.Stat) { - if (comptime bun.Environment.isWindows) return statatWindows(handle.value, path); - return switch (Syscall.fstatat(handle.value, path)) { - .err => |err| .{ .err = err }, - .result => |s| .{ .result = s }, - }; - } - - pub fn openat(handle: Handle, path: [:0]const u8) !Maybe(Handle) { - return switch (Syscall.openat(handle.value, path, bun.O.DIRECTORY | bun.O.RDONLY, 0)) { - .err => |err| .{ .err = err }, - .result => |fd| .{ .result = Handle{ .value = fd } }, - }; - } - - pub fn close(handle: Handle) ?Syscall.Error { - return Syscall.close(handle.value); - } - - pub fn getcwd(path_buf: *bun.PathBuffer) Maybe([]const u8) { - return Syscall.getcwd(path_buf); - } -}; - -pub const DirEntryAccessor = struct { - const FS = bun.fs.FileSystem; - - const count_fds = false; - - const Handle = struct { - value: ?*FS.DirEntry, - - const zero = Handle{ .value = null }; - - pub fn isZero(this: Handle) bool { - return this.value == null; - } - - pub fn eql(this: Handle, other: Handle) bool { - // TODO this might not be quite right, we're comparing pointers, not the underlying directory - // On the other hand, DirEntries are only ever created once (per generation), so this should be fine? - // Realistically, as closing the handle is a no-op, this should be fine either way. - return this.value == other.value; - } - }; - - const DirIter = struct { - value: ?FS.DirEntry.EntryMap.Iterator, - - const IterResult = struct { - name: NameWrapper, - kind: std.fs.File.Kind, - - const NameWrapper = struct { - value: []const u8, - - pub fn slice(this: NameWrapper) []const u8 { - return this.value; - } - }; - }; - - pub inline fn next(self: *DirIter) Maybe(?IterResult) { - if (self.value) |*value| { - const nextval = value.next() orelse return .{ .result = null }; - const name = nextval.key_ptr.*; - const kind = nextval.value_ptr.*.kind(&FS.instance.fs, true); - const fskind = switch (kind) { - .file => std.fs.File.Kind.file, - .dir => std.fs.File.Kind.directory, - }; - return .{ - .result = .{ - .name = IterResult.NameWrapper{ .value = name }, - .kind = fskind, - }, - }; - } else { - return .{ .result = null }; - } - } - - pub inline fn iterate(dir: Handle) DirIter { - const entry = dir.value orelse return DirIter{ .value = null }; - return .{ .value = entry.data.iterator() }; - } - }; - - pub fn statat(handle: Handle, path_: [:0]const u8) Maybe(bun.Stat) { - var path: [:0]const u8 = path_; - var buf: bun.PathBuffer = undefined; - if (!bun.path.Platform.auto.isAbsolute(path)) { - if (handle.value) |entry| { - const slice = bun.path.joinStringBuf(&buf, [_][]const u8{ entry.dir, path }, .auto); - buf[slice.len] = 0; - path = buf[0..slice.len :0]; - } - } - return Syscall.stat(path); - } - - pub fn open(path: [:0]const u8) !Maybe(Handle) { - return openat(Handle.zero, path); - } - - pub fn openat(handle: Handle, path_: [:0]const u8) !Maybe(Handle) { - var path: []const u8 = path_; - var buf: bun.PathBuffer = undefined; - - if (!bun.path.Platform.auto.isAbsolute(path)) { - if (handle.value) |entry| { - path = bun.path.joinStringBuf(&buf, [_][]const u8{ entry.dir, path }, .auto); - } - } - // TODO do we want to propagate ENOTDIR through the 'Maybe' to match the SyscallAccessor? - // The glob implementation specifically checks for this error when dealing with symlinks - // return .{ .err = Syscall.Error.fromCode(bun.C.E.NOTDIR, Syscall.Tag.open) }; - const res = FS.instance.fs.readDirectory(path, null, 0, false) catch |err| { - return err; - }; - switch (res.*) { - .entries => |entry| { - return .{ .result = Handle{ .value = entry } }; - }, - .err => |err| { - return err.original_err; - }, - } - } - - pub inline fn close(handle: Handle) ?Syscall.Error { - // TODO is this a noop? - _ = handle; - return null; - } - - pub fn getcwd(path_buf: *bun.PathBuffer) Maybe([]const u8) { - @memcpy(path_buf, bun.fs.FileSystem.instance.fs.cwd); - } -}; - -pub fn GlobWalker_( - comptime ignore_filter_fn: ?*const fn ([]const u8) bool, - comptime Accessor: type, - comptime sentinel: bool, -) type { - const is_ignored: *const fn ([]const u8) bool = if (comptime ignore_filter_fn) |func| func else dummyFilterFalse; - - const count_fds = Accessor.count_fds and bun.Environment.isDebug; - - const stdJoin = comptime if (!sentinel) std.fs.path.join else std.fs.path.joinZ; - const bunJoin = comptime if (!sentinel) ResolvePath.join else ResolvePath.joinZ; - const MatchedPath = comptime if (!sentinel) []const u8 else [:0]const u8; - - return struct { - const GlobWalker = @This(); - pub const Result = Maybe(void); - - arena: Arena = undefined, - - /// not owned by this struct - pattern: []const u8 = "", - - pattern_codepoints: []u32 = &[_]u32{}, - cp_len: u32 = 0, - - /// If the pattern contains "./" or "../" - has_relative_components: bool = false, - - end_byte_of_basename_excluding_special_syntax: u32 = 0, - basename_excluding_special_syntax_component_idx: u32 = 0, - - patternComponents: ArrayList(Component) = .{}, - matchedPaths: MatchedMap = .{}, - i: u32 = 0, - - dot: bool = false, - absolute: bool = false, - - cwd: []const u8 = "", - follow_symlinks: bool = false, - error_on_broken_symlinks: bool = false, - only_files: bool = true, - - pathBuf: bun.PathBuffer = undefined, - // iteration state - workbuf: ArrayList(WorkItem) = ArrayList(WorkItem){}, - - /// Array hashmap used as a set (values are the keys) - /// to store matched paths and prevent duplicates - /// - /// BunString is used so that we can call BunString.toJSArray() - /// on the result of `.keys()` to give the result back to JS - /// - /// The only type of string impl we use is ZigString since - /// all matched paths are UTF-8 (DirIterator converts them on - /// windows) and allocated on the arnea - /// - /// Multiple patterns are not supported so right now this is - /// only possible when running a pattern like: - /// - /// `foo/**/*` - /// - /// Use `.keys()` to get the matched paths - const MatchedMap = std.ArrayHashMapUnmanaged(BunString, void, struct { - pub fn hash(_: @This(), this: BunString) u32 { - bun.assert(this.tag == .ZigString); - const slice = this.byteSlice(); - if (comptime sentinel) { - const slicez = slice[0 .. slice.len - 1 :0]; - return std.array_hash_map.hashString(slicez); - } - - return std.array_hash_map.hashString(slice); - } - - pub fn eql(_: @This(), this: BunString, other: BunString, _: usize) bool { - return this.eql(other); - } - }, true); - - /// The glob walker references the .directory.path so its not safe to - /// copy/move this - const IterState = union(enum) { - /// Pops the next item off the work stack - get_next, - - /// Currently iterating over a directory - directory: Directory, - - /// Two particular cases where this is used: - /// - /// 1. A pattern with no special glob syntax was supplied, for example: `/Users/zackradisic/foo/bar` - /// - /// In that case, the mere existence of the file/dir counts as a match, so we can eschew directory - /// iterating and walking for a simple stat call to the path. - /// - /// 2. Pattern ending in literal optimization - /// - /// With a pattern like: `packages/**/package.json`, once the iteration component index reaches - /// the final component, which is a literal string ("package.json"), we can similarly make a - /// single stat call to complete the pattern. - matched: MatchedPath, - - const Directory = struct { - fd: Accessor.Handle, - iter: Accessor.DirIter, - path: bun.PathBuffer, - dir_path: [:0]const u8, - - component_idx: u32, - pattern: *Component, - next_pattern: ?*Component, - is_last: bool, - - iter_closed: bool = false, - at_cwd: bool = false, - }; - }; - - pub const Iterator = struct { - walker: *GlobWalker, - iter_state: IterState = .get_next, - cwd_fd: Accessor.Handle = Accessor.Handle.zero, - empty_dir_path: [0:0]u8 = [0:0]u8{}, - /// This is to make sure in debug/tests that we are closing file descriptors - /// We should only have max 2 open at a time. One for the cwd, and one for the - /// directory being iterated on. - fds_open: if (count_fds) usize else u0 = 0, - - pub fn init(this: *Iterator) !Maybe(void) { - log("Iterator init pattern={s}", .{this.walker.pattern}); - var was_absolute = false; - const root_work_item = brk: { - var use_posix = bun.Environment.isPosix; - const is_absolute = if (bun.Environment.isPosix) std.fs.path.isAbsolute(this.walker.pattern) else std.fs.path.isAbsolute(this.walker.pattern) or is_absolute: { - use_posix = true; - break :is_absolute std.fs.path.isAbsolutePosix(this.walker.pattern); - }; - - if (!is_absolute) break :brk WorkItem.new(this.walker.cwd, 0, .directory); - - was_absolute = true; - - var path_without_special_syntax = this.walker.pattern[0..this.walker.end_byte_of_basename_excluding_special_syntax]; - var starting_component_idx = this.walker.basename_excluding_special_syntax_component_idx; - - if (path_without_special_syntax.len == 0) { - path_without_special_syntax = if (!bun.Environment.isWindows) "/" else ResolvePath.windowsFilesystemRoot(this.walker.cwd); - } else { - // Skip the components associated with the literal path - starting_component_idx += 1; - - // This means we got a pattern without any special glob syntax, for example: - // `/Users/zackradisic/foo/bar` - // - // In that case we don't need to do any walking and can just open up the FS entry - if (starting_component_idx >= this.walker.patternComponents.items.len) { - const path = try this.walker.arena.allocator().dupeZ(u8, path_without_special_syntax); - const fd = switch (try Accessor.open(path)) { - .err => |e| { - if (e.getErrno() == bun.C.E.NOTDIR) { - this.iter_state = .{ .matched = path }; - return Maybe(void).success; - } - // Doesn't exist - if (e.getErrno() == bun.C.E.NOENT) { - this.iter_state = .get_next; - return Maybe(void).success; - } - const errpath = try this.walker.arena.allocator().dupeZ(u8, path); - return .{ .err = e.withPath(errpath) }; - }, - .result => |fd| fd, - }; - _ = Accessor.close(fd); - this.iter_state = .{ .matched = path }; - return Maybe(void).success; - } - - // In the above branch, if `starting_compoennt_dix >= pattern_components.len` then - // it should also mean that `end_byte_of_basename_excluding_special_syntax >= pattern.len` - // - // So if we see that `end_byte_of_basename_excluding_special_syntax < this.walker.pattern.len` we - // miscalculated the values - bun.assert(this.walker.end_byte_of_basename_excluding_special_syntax < this.walker.pattern.len); - } - - break :brk WorkItem.new( - path_without_special_syntax, - starting_component_idx, - .directory, - ); - }; - - var path_buf: *bun.PathBuffer = &this.walker.pathBuf; - const root_path = root_work_item.path; - @memcpy(path_buf[0..root_path.len], root_path[0..root_path.len]); - path_buf[root_path.len] = 0; - const cwd_fd = switch (try Accessor.open(path_buf[0..root_path.len :0])) { - .err => |err| return .{ .err = this.walker.handleSysErrWithPath(err, @ptrCast(path_buf[0 .. root_path.len + 1])) }, - .result => |fd| fd, - }; - - if (comptime count_fds) { - this.fds_open += 1; - } - - this.cwd_fd = cwd_fd; - - switch (if (was_absolute) try this.transitionToDirIterState( - root_work_item, - false, - ) else try this.transitionToDirIterState( - root_work_item, - true, - )) { - .err => |err| return .{ .err = err }, - else => {}, - } - - return Maybe(void).success; - } - - pub fn deinit(this: *Iterator) void { - defer { - bun.debugAssert(this.fds_open == 0); - } - this.closeCwdFd(); - switch (this.iter_state) { - .directory => |dir| { - if (!dir.iter_closed) { - this.closeDisallowingCwd(dir.fd); - } - }, - else => {}, - } - - while (this.walker.workbuf.popOrNull()) |work_item| { - if (work_item.fd) |fd| { - this.closeDisallowingCwd(fd); - } - } - - if (comptime count_fds) { - bun.debugAssert(this.fds_open == 0); - } - } - - pub fn closeCwdFd(this: *Iterator) void { - if (this.cwd_fd.isZero()) return; - _ = Accessor.close(this.cwd_fd); - if (comptime count_fds) this.fds_open -= 1; - } - - pub fn closeDisallowingCwd(this: *Iterator, fd: Accessor.Handle) void { - if (fd.isZero() or fd.eql(this.cwd_fd)) return; - _ = Accessor.close(fd); - if (comptime count_fds) this.fds_open -= 1; - } - - pub fn bumpOpenFds(this: *Iterator) void { - if (comptime count_fds) { - this.fds_open += 1; - // If this is over 2 then this means that there is a bug in the iterator code - bun.debugAssert(this.fds_open <= 2); - } - } - - fn transitionToDirIterState( - this: *Iterator, - work_item: WorkItem, - comptime root: bool, - ) !Maybe(void) { - log("transition => {s}", .{work_item.path}); - this.iter_state = .{ .directory = .{ - .fd = Accessor.Handle.zero, - .iter = undefined, - .path = undefined, - .dir_path = undefined, - .component_idx = 0, - .pattern = undefined, - .next_pattern = null, - .is_last = false, - .iter_closed = false, - .at_cwd = false, - } }; - - var dir_path: [:0]u8 = dir_path: { - if (comptime root) { - if (!this.walker.absolute) { - this.iter_state.directory.path[0] = 0; - break :dir_path this.iter_state.directory.path[0..0 :0]; - } - } - // TODO Optimization: On posix systems filepaths are already null byte terminated so we can skip this if thats the case - @memcpy(this.iter_state.directory.path[0..work_item.path.len], work_item.path); - this.iter_state.directory.path[work_item.path.len] = 0; - break :dir_path this.iter_state.directory.path[0..work_item.path.len :0]; - }; - - var had_dot_dot = false; - const component_idx = this.walker.skipSpecialComponents(work_item.idx, &dir_path, &this.iter_state.directory.path, &had_dot_dot); - - const fd: Accessor.Handle = fd: { - if (work_item.fd) |fd| break :fd fd; - if (comptime root) { - if (had_dot_dot) break :fd switch (try Accessor.openat(this.cwd_fd, dir_path)) { - .err => |err| return .{ - .err = this.walker.handleSysErrWithPath(err, dir_path), - }, - .result => |fd_| brk: { - this.bumpOpenFds(); - break :brk fd_; - }, - }; - - this.iter_state.directory.at_cwd = true; - break :fd this.cwd_fd; - } - - break :fd switch (try Accessor.openat(this.cwd_fd, dir_path)) { - .err => |err| return .{ - .err = this.walker.handleSysErrWithPath(err, dir_path), - }, - .result => |fd_| brk: { - this.bumpOpenFds(); - break :brk fd_; - }, - }; - }; - - // Optimization: - // If we have a pattern like: - // `packages/*/package.json` - // ^ and we are at this component, with let's say - // a directory named: `packages/frontend/` - // - // Then we can just open `packages/frontend/package.json` without - // doing any iteration on the current directory. - // - // More generally, we can apply this optimization if we are on the - // last component and it is a literal with no special syntax. - if (component_idx == this.walker.patternComponents.items.len -| 1 and - this.walker.patternComponents.items[component_idx].syntax_hint == .Literal) - { - defer { - this.closeDisallowingCwd(fd); - } - const stackbuf_size = 256; - var stfb = std.heap.stackFallback(stackbuf_size, this.walker.arena.allocator()); - const pathz = try stfb.get().dupeZ(u8, this.walker.patternComponents.items[component_idx].patternSlice(this.walker.pattern)); - const stat_result: bun.Stat = switch (Accessor.statat(fd, pathz)) { - .err => |e_| { - var e: bun.sys.Error = e_; - if (e.getErrno() == bun.C.E.NOENT) { - this.iter_state = .get_next; - return Maybe(void).success; - } - return .{ .err = e.withPath(this.walker.patternComponents.items[component_idx].patternSlice(this.walker.pattern)) }; - }, - .result => |stat| stat, - }; - const matches = (bun.S.ISDIR(@intCast(stat_result.mode)) and !this.walker.only_files) or bun.S.ISREG(@intCast(stat_result.mode)) or !this.walker.only_files; - if (matches) { - if (try this.walker.prepareMatchedPath(pathz, dir_path)) |path| { - this.iter_state = .{ .matched = path }; - } else { - this.iter_state = .get_next; - } - } else { - this.iter_state = .get_next; - } - return Maybe(void).success; - } - - this.iter_state.directory.dir_path = dir_path; - this.iter_state.directory.component_idx = component_idx; - this.iter_state.directory.pattern = &this.walker.patternComponents.items[component_idx]; - this.iter_state.directory.next_pattern = if (component_idx + 1 < this.walker.patternComponents.items.len) &this.walker.patternComponents.items[component_idx + 1] else null; - this.iter_state.directory.is_last = component_idx == this.walker.patternComponents.items.len - 1; - this.iter_state.directory.at_cwd = false; - this.iter_state.directory.fd = Accessor.Handle.zero; - - log("Transition(dirpath={s}, fd={}, component_idx={d})", .{ dir_path, fd, component_idx }); - - this.iter_state.directory.fd = fd; - const iterator = Accessor.DirIter.iterate(fd); - this.iter_state.directory.iter = iterator; - this.iter_state.directory.iter_closed = false; - - return Maybe(void).success; - } - - pub fn next(this: *Iterator) !Maybe(?MatchedPath) { - while (true) { - switch (this.iter_state) { - .matched => |path| { - this.iter_state = .get_next; - return .{ .result = path }; - }, - .get_next => { - // Done - if (this.walker.workbuf.items.len == 0) return .{ .result = null }; - const work_item = this.walker.workbuf.pop(); - switch (work_item.kind) { - .directory => { - switch (try this.transitionToDirIterState(work_item, false)) { - .err => |err| return .{ .err = err }, - else => {}, - } - continue; - }, - .symlink => { - var scratch_path_buf: *bun.PathBuffer = &this.walker.pathBuf; - @memcpy(scratch_path_buf[0..work_item.path.len], work_item.path); - scratch_path_buf[work_item.path.len] = 0; - var symlink_full_path_z: [:0]u8 = scratch_path_buf[0..work_item.path.len :0]; - const entry_name = symlink_full_path_z[work_item.entry_start..symlink_full_path_z.len]; - - var has_dot_dot = false; - const component_idx = this.walker.skipSpecialComponents(work_item.idx, &symlink_full_path_z, scratch_path_buf, &has_dot_dot); - var pattern = this.walker.patternComponents.items[component_idx]; - const next_pattern = if (component_idx + 1 < this.walker.patternComponents.items.len) &this.walker.patternComponents.items[component_idx + 1] else null; - const is_last = component_idx == this.walker.patternComponents.items.len - 1; - - this.iter_state = .get_next; - const maybe_dir_fd: ?Accessor.Handle = switch (try Accessor.openat(this.cwd_fd, symlink_full_path_z)) { - .err => |err| brk: { - if (@as(usize, @intCast(err.errno)) == @as(usize, @intFromEnum(bun.C.E.NOTDIR))) { - break :brk null; - } - if (this.walker.error_on_broken_symlinks) return .{ .err = this.walker.handleSysErrWithPath(err, symlink_full_path_z) }; - // Broken symlink, but if `only_files` is false we still want to append - // it to the matched paths - if (!this.walker.only_files) { - // (See case A and B in the comment for `matchPatternFile()`) - // When we encounter a symlink we call the catch all - // matching function: `matchPatternImpl()` to see if we can avoid following the symlink. - // So for case A, we just need to check if the pattern is the last pattern. - if (is_last or - (pattern.syntax_hint == .Double and - component_idx + 1 == this.walker.patternComponents.items.len -| 1 and - next_pattern.?.syntax_hint != .Double and - this.walker.matchPatternImpl(next_pattern.?, entry_name))) - { - return .{ .result = try this.walker.prepareMatchedPathSymlink(symlink_full_path_z) orelse continue }; - } - } - continue; - }, - .result => |fd| brk: { - this.bumpOpenFds(); - break :brk fd; - }, - }; - - const dir_fd = maybe_dir_fd orelse { - // No directory file descriptor, it's a file - if (is_last) - return .{ .result = try this.walker.prepareMatchedPathSymlink(symlink_full_path_z) orelse continue }; - - if (pattern.syntax_hint == .Double and - component_idx + 1 == this.walker.patternComponents.items.len -| 1 and - next_pattern.?.syntax_hint != .Double and - this.walker.matchPatternImpl(next_pattern.?, entry_name)) - { - return .{ .result = try this.walker.prepareMatchedPathSymlink(symlink_full_path_z) orelse continue }; - } - - continue; - }; - - var add_dir: bool = false; - // TODO this function calls `matchPatternImpl(pattern, - // entry_name)` which is redundant because we already called - // that when we first encountered the symlink - const recursion_idx_bump_ = this.walker.matchPatternDir(&pattern, next_pattern, entry_name, component_idx, is_last, &add_dir); - - if (recursion_idx_bump_) |recursion_idx_bump| { - if (recursion_idx_bump == 2) { - try this.walker.workbuf.append( - this.walker.arena.allocator(), - WorkItem.newWithFd(work_item.path, component_idx + recursion_idx_bump, .directory, dir_fd), - ); - try this.walker.workbuf.append( - this.walker.arena.allocator(), - WorkItem.newWithFd(work_item.path, component_idx, .directory, dir_fd), - ); - } else { - try this.walker.workbuf.append( - this.walker.arena.allocator(), - WorkItem.newWithFd(work_item.path, component_idx + recursion_idx_bump, .directory, dir_fd), - ); - } - } - - if (add_dir and !this.walker.only_files) { - return .{ .result = try this.walker.prepareMatchedPathSymlink(symlink_full_path_z) orelse continue }; - } - - continue; - }, - } - }, - .directory => |*dir| { - const entry = switch (dir.iter.next()) { - .err => |err| { - if (!dir.at_cwd) this.closeDisallowingCwd(dir.fd); - dir.iter_closed = true; - return .{ .err = this.walker.handleSysErrWithPath(err, dir.dir_path) }; - }, - .result => |ent| ent, - } orelse { - if (!dir.at_cwd) this.closeDisallowingCwd(dir.fd); - dir.iter_closed = true; - this.iter_state = .get_next; - continue; - }; - log("dir: {s} entry: {s}", .{ dir.dir_path, entry.name.slice() }); - - const dir_iter_state: *const IterState.Directory = &this.iter_state.directory; - - const entry_name = entry.name.slice(); - switch (entry.kind) { - .file => { - const matches = this.walker.matchPatternFile(entry_name, dir_iter_state.component_idx, dir.is_last, dir_iter_state.pattern, dir_iter_state.next_pattern); - if (matches) { - const prepared = try this.walker.prepareMatchedPath(entry_name, dir.dir_path) orelse continue; - return .{ .result = prepared }; - } - continue; - }, - .directory => { - var add_dir: bool = false; - const recursion_idx_bump_ = this.walker.matchPatternDir(dir_iter_state.pattern, dir_iter_state.next_pattern, entry_name, dir_iter_state.component_idx, dir_iter_state.is_last, &add_dir); - - if (recursion_idx_bump_) |recursion_idx_bump| { - const subdir_parts: []const []const u8 = &[_][]const u8{ - dir.dir_path[0..dir.dir_path.len], - entry_name, - }; - - const subdir_entry_name = try this.walker.join(subdir_parts); - - if (recursion_idx_bump == 2) { - try this.walker.workbuf.append( - this.walker.arena.allocator(), - WorkItem.new(subdir_entry_name, dir_iter_state.component_idx + recursion_idx_bump, .directory), - ); - try this.walker.workbuf.append( - this.walker.arena.allocator(), - WorkItem.new(subdir_entry_name, dir_iter_state.component_idx, .directory), - ); - } else { - try this.walker.workbuf.append( - this.walker.arena.allocator(), - WorkItem.new(subdir_entry_name, dir_iter_state.component_idx + recursion_idx_bump, .directory), - ); - } - } - - if (add_dir and !this.walker.only_files) { - const prepared_path = try this.walker.prepareMatchedPath(entry_name, dir.dir_path) orelse continue; - return .{ .result = prepared_path }; - } - - continue; - }, - .sym_link => { - if (this.walker.follow_symlinks) { - // Following a symlink requires additional syscalls, so - // we first try it against our "catch-all" pattern match - // function - const matches = this.walker.matchPatternImpl(dir_iter_state.pattern, entry_name); - if (!matches) continue; - - const subdir_parts: []const []const u8 = &[_][]const u8{ - dir.dir_path[0..dir.dir_path.len], - entry_name, - }; - const entry_start: u32 = @intCast(if (dir.dir_path.len == 0) 0 else dir.dir_path.len + 1); - - // const subdir_entry_name = try this.arena.allocator().dupe(u8, ResolvePath.join(subdir_parts, .auto)); - const subdir_entry_name = try this.walker.join(subdir_parts); - - try this.walker.workbuf.append( - this.walker.arena.allocator(), - WorkItem.newSymlink(subdir_entry_name, dir_iter_state.component_idx, entry_start), - ); - - continue; - } - - if (this.walker.only_files) continue; - - const matches = this.walker.matchPatternFile(entry_name, dir_iter_state.component_idx, dir_iter_state.is_last, dir_iter_state.pattern, dir_iter_state.next_pattern); - if (matches) { - const prepared_path = try this.walker.prepareMatchedPath(entry_name, dir.dir_path) orelse continue; - return .{ .result = prepared_path }; - } - - continue; - }, - else => continue, - } - }, - } - } - } - }; - - const WorkItem = struct { - path: []const u8, - idx: u32, - kind: Kind, - entry_start: u32 = 0, - fd: ?Accessor.Handle = null, - - const Kind = enum { - directory, - symlink, - }; - - fn new(path: []const u8, idx: u32, kind: Kind) WorkItem { - return .{ - .path = path, - .idx = idx, - .kind = kind, - }; - } - - fn newWithFd(path: []const u8, idx: u32, kind: Kind, fd: Accessor.Handle) WorkItem { - return .{ - .path = path, - .idx = idx, - .kind = kind, - .fd = fd, - }; - } - - fn newSymlink(path: []const u8, idx: u32, entry_start: u32) WorkItem { - return .{ - .path = path, - .idx = idx, - .kind = .symlink, - .entry_start = entry_start, - }; - } - }; - - /// A component is each part of a glob pattern, separated by directory - /// separator: - /// `src/**/*.ts` -> `src`, `**`, `*.ts` - const Component = struct { - start: u32, - len: u32, - - syntax_hint: SyntaxHint = .None, - trailing_sep: bool = false, - is_ascii: bool = false, - - /// Only used when component is not ascii - unicode_set: bool = false, - start_cp: u32 = 0, - end_cp: u32 = 0, - - pub fn patternSlice(this: *const Component, pattern: []const u8) []const u8 { - return pattern[this.start .. this.start + this.len - @as(u1, @bitCast(this.trailing_sep))]; - } - - pub fn patternSliceCp(this: *const Component, pattern: []u32) []u32 { - return pattern[this.start_cp .. this.end_cp - @as(u1, @bitCast(this.trailing_sep))]; - } - - const SyntaxHint = enum { - None, - Single, - Double, - /// Uses special fast-path matching for components like: `*.ts` - WildcardFilepath, - /// Uses special fast-patch matching for literal components e.g. - /// "node_modules", becomes memcmp - Literal, - /// ./fixtures/*.ts - /// ^ - Dot, - /// ../ - DotBack, - - fn isSpecialSyntax(this: SyntaxHint) bool { - return switch (this) { - .Literal => false, - else => true, - }; - } - }; - }; - - /// The arena parameter is dereferenced and copied if all allocations go well and nothing goes wrong - pub fn init( - this: *GlobWalker, - arena: *Arena, - pattern: []const u8, - dot: bool, - absolute: bool, - follow_symlinks: bool, - error_on_broken_symlinks: bool, - only_files: bool, - ) !Maybe(void) { - return try this.initWithCwd( - arena, - pattern, - bun.fs.FileSystem.instance.top_level_dir, - dot, - absolute, - follow_symlinks, - error_on_broken_symlinks, - only_files, - ); - } - - pub fn convertUtf8ToCodepoints(codepoints: []u32, pattern: []const u8) void { - _ = bun.simdutf.convert.utf8.to.utf32.le(pattern, codepoints); - } - - pub fn debugPatternComopnents(this: *GlobWalker) void { - const pattern = this.pattern; - const components = &this.patternComponents; - const ptr = @intFromPtr(this); - log("GlobWalker(0x{x}) components:", .{ptr}); - for (components.items) |cmp| { - switch (cmp.syntax_hint) { - .Single => log(" *", .{}), - .Double => log(" **", .{}), - .Dot => log(" .", .{}), - .DotBack => log(" ../", .{}), - .Literal, .WildcardFilepath, .None => log(" hint={s} component_str={s}", .{ @tagName(cmp.syntax_hint), cmp.patternSlice(pattern) }), - } - } - } - - /// `cwd` should be allocated with the arena - /// The arena parameter is dereferenced and copied if all allocations go well and nothing goes wrong - pub fn initWithCwd( - this: *GlobWalker, - arena: *Arena, - pattern: []const u8, - cwd: []const u8, - dot: bool, - absolute: bool, - follow_symlinks: bool, - error_on_broken_symlinks: bool, - only_files: bool, - ) !Maybe(void) { - log("initWithCwd(cwd={s})", .{cwd}); - this.* = .{ - .cwd = cwd, - .pattern = pattern, - .dot = dot, - .absolute = absolute, - .follow_symlinks = follow_symlinks, - .error_on_broken_symlinks = error_on_broken_symlinks, - .only_files = only_files, - .basename_excluding_special_syntax_component_idx = 0, - .end_byte_of_basename_excluding_special_syntax = 0, - }; - - try GlobWalker.buildPatternComponents( - arena, - &this.patternComponents, - pattern, - &this.cp_len, - &this.pattern_codepoints, - &this.has_relative_components, - &this.end_byte_of_basename_excluding_special_syntax, - &this.basename_excluding_special_syntax_component_idx, - ); - - // copy arena after all allocations are successful - this.arena = arena.*; - - if (bun.Environment.allow_assert) { - this.debugPatternComopnents(); - } - - return Maybe(void).success; - } - - /// NOTE This also calls deinit on the arena, if you don't want to do that then - pub fn deinit(this: *GlobWalker, comptime clear_arena: bool) void { - log("GlobWalker.deinit", .{}); - if (comptime clear_arena) { - this.arena.deinit(); - } - } - - pub fn handleSysErrWithPath( - this: *GlobWalker, - err: Syscall.Error, - path_buf: [:0]const u8, - ) Syscall.Error { - std.mem.copyForwards(u8, this.pathBuf[0 .. path_buf.len + 1], @as([]const u8, @ptrCast(path_buf[0 .. path_buf.len + 1]))); - return err.withPath(this.pathBuf[0 .. path_buf.len + 1]); - } - - pub fn walk(this: *GlobWalker) !Maybe(void) { - if (this.patternComponents.items.len == 0) return Maybe(void).success; - - var iter = GlobWalker.Iterator{ .walker = this }; - defer iter.deinit(); - switch (try iter.init()) { - .err => |err| return .{ .err = err }, - else => {}, - } - - while (switch (try iter.next()) { - .err => |err| return .{ .err = err }, - .result => |matched_path| matched_path, - }) |path| { - log("walker: matched path: {s}", .{path}); - // The paths are already put into this.matchedPaths, which we use for the output, - // so we don't need to do anything here - } - - return Maybe(void).success; - } - - // NOTE you must check that the pattern at `idx` has `syntax_hint == .Dot` or - // `syntax_hint == .DotBack` first - fn collapseDots( - this: *GlobWalker, - idx: u32, - dir_path: *[:0]u8, - path_buf: *bun.PathBuffer, - encountered_dot_dot: *bool, - ) u32 { - var component_idx = idx; - var len = dir_path.len; - while (component_idx < this.patternComponents.items.len) { - switch (this.patternComponents.items[component_idx].syntax_hint) { - .Dot => { - defer component_idx += 1; - if (len + 2 >= bun.MAX_PATH_BYTES) @panic("Invalid path"); - if (len == 0) { - path_buf[len] = '.'; - path_buf[len + 1] = 0; - len += 1; - } else { - path_buf[len] = '/'; - path_buf[len + 1] = '.'; - path_buf[len + 2] = 0; - len += 2; - } - }, - .DotBack => { - defer component_idx += 1; - encountered_dot_dot.* = true; - if (dir_path.len + 3 >= bun.MAX_PATH_BYTES) @panic("Invalid path"); - if (len == 0) { - path_buf[len] = '.'; - path_buf[len + 1] = '.'; - path_buf[len + 2] = 0; - len += 2; - } else { - path_buf[len] = '/'; - path_buf[len + 1] = '.'; - path_buf[len + 2] = '.'; - path_buf[len + 3] = 0; - len += 3; - } - }, - else => break, - } - } - - dir_path.len = len; - - return component_idx; - } - - // NOTE you must check that the pattern at `idx` has `syntax_hint == .Double` first - fn collapseSuccessiveDoubleWildcards(this: *GlobWalker, idx: u32) u32 { - var component_idx = idx; - const pattern = this.patternComponents.items[idx]; - _ = pattern; - // Collapse successive double wildcards - while (component_idx + 1 < this.patternComponents.items.len and - this.patternComponents.items[component_idx + 1].syntax_hint == .Double) : (component_idx += 1) - {} - return component_idx; - } - - pub fn skipSpecialComponents( - this: *GlobWalker, - work_item_idx: u32, - dir_path: *[:0]u8, - scratch_path_buf: *bun.PathBuffer, - encountered_dot_dot: *bool, - ) u32 { - var component_idx = work_item_idx; - - // Skip `.` and `..` while also appending them to `dir_path` - component_idx = switch (this.patternComponents.items[component_idx].syntax_hint) { - .Dot => this.collapseDots( - component_idx, - dir_path, - scratch_path_buf, - encountered_dot_dot, - ), - .DotBack => this.collapseDots( - component_idx, - dir_path, - scratch_path_buf, - encountered_dot_dot, - ), - else => component_idx, - }; - - // Skip to the last `**` if there is a chain of them - component_idx = switch (this.patternComponents.items[component_idx].syntax_hint) { - .Double => this.collapseSuccessiveDoubleWildcards(component_idx), - else => component_idx, - }; - - return component_idx; - } - - fn matchPatternDir( - this: *GlobWalker, - pattern: *Component, - next_pattern: ?*Component, - entry_name: []const u8, - component_idx: u32, - is_last: bool, - add: *bool, - ) ?u32 { - if (!this.dot and GlobWalker.startsWithDot(entry_name)) return null; - if (is_ignored(entry_name)) return null; - - // Handle double wildcard `**`, this could possibly - // propagate the `**` to the directory's children - if (pattern.syntax_hint == .Double) { - // Stop the double wildcard if it matches the pattern afer it - // Example: src/**/*.js - // - Matches: src/bun.js/ - // src/bun.js/foo/bar/baz.js - if (!is_last and this.matchPatternImpl(next_pattern.?, entry_name)) { - // But if the next pattern is the last - // component, it should match and propagate the - // double wildcard recursion to the directory's - // children - if (component_idx + 1 == this.patternComponents.items.len - 1) { - add.* = true; - return 0; - } - - // In the normal case skip over the next pattern - // since we matched it, example: - // BEFORE: src/**/node_modules/**/*.js - // ^ - // AFTER: src/**/node_modules/**/*.js - // ^ - return 2; - } - - if (is_last) { - add.* = true; - } - - return 0; - } - - const matches = this.matchPatternImpl(pattern, entry_name); - if (matches) { - if (is_last) { - add.* = true; - return null; - } - return 1; - } - - return null; - } - - /// A file can only match if: - /// a) it matches against the last pattern, or - /// b) it matches the next pattern, provided the current - /// pattern is a double wildcard and the next pattern is - /// not a double wildcard - /// - /// Examples: - /// a -> `src/foo/index.ts` matches - /// b -> `src/**/*.ts` (on 2nd pattern) matches - fn matchPatternFile( - this: *GlobWalker, - entry_name: []const u8, - component_idx: u32, - is_last: bool, - pattern: *Component, - next_pattern: ?*Component, - ) bool { - if (pattern.trailing_sep) return false; - - // Handle case b) - if (!is_last) return pattern.syntax_hint == .Double and - component_idx + 1 == this.patternComponents.items.len -| 1 and - next_pattern.?.syntax_hint != .Double and - this.matchPatternImpl(next_pattern.?, entry_name); - - // Handle case a) - return this.matchPatternImpl(pattern, entry_name); - } - - fn matchPatternImpl( - this: *GlobWalker, - pattern_component: *Component, - filepath: []const u8, - ) bool { - log("matchPatternImpl: {s}", .{filepath}); - if (!this.dot and GlobWalker.startsWithDot(filepath)) return false; - if (is_ignored(filepath)) return false; - - return switch (pattern_component.syntax_hint) { - .Double, .Single => true, - .WildcardFilepath => if (comptime !isWindows) - matchWildcardFilepath(pattern_component.patternSlice(this.pattern), filepath) - else - this.matchPatternSlow(pattern_component, filepath), - .Literal => if (comptime !isWindows) - matchWildcardLiteral(pattern_component.patternSlice(this.pattern), filepath) - else - this.matchPatternSlow(pattern_component, filepath), - else => this.matchPatternSlow(pattern_component, filepath), - }; - } - - fn matchPatternSlow(this: *GlobWalker, pattern_component: *Component, filepath: []const u8) bool { - // windows filepaths are utf-16 so GlobAscii.match will never work - if (comptime !isWindows) { - if (pattern_component.is_ascii and isAllAscii(filepath)) - return GlobAscii.match( - pattern_component.patternSlice(this.pattern), - filepath, - ); - } - const codepoints = this.componentStringUnicode(pattern_component); - return matchImpl( - codepoints, - filepath, - ).matches(); - } - - fn componentStringUnicode(this: *GlobWalker, pattern_component: *Component) []const u32 { - if (comptime isWindows) { - return this.componentStringUnicodeWindows(pattern_component); - } else { - return this.componentStringUnicodePosix(pattern_component); - } - } - - fn componentStringUnicodeWindows(this: *GlobWalker, pattern_component: *Component) []const u32 { - return pattern_component.patternSliceCp(this.pattern_codepoints); - } - - fn componentStringUnicodePosix(this: *GlobWalker, pattern_component: *Component) []const u32 { - if (pattern_component.unicode_set) return pattern_component.patternSliceCp(this.pattern_codepoints); - - const codepoints = pattern_component.patternSliceCp(this.pattern_codepoints); - GlobWalker.convertUtf8ToCodepoints( - codepoints, - pattern_component.patternSlice(this.pattern), - ); - pattern_component.unicode_set = true; - return codepoints; - } - - inline fn matchedPathToBunString(matched_path: MatchedPath) BunString { - if (comptime sentinel) { - return BunString.fromBytes(matched_path[0 .. matched_path.len + 1]); - } - return BunString.fromBytes(matched_path); - } - - fn prepareMatchedPathSymlink(this: *GlobWalker, symlink_full_path: []const u8) !?MatchedPath { - const result = try this.matchedPaths.getOrPut(this.arena.allocator(), BunString.fromBytes(symlink_full_path)); - if (result.found_existing) { - log("(dupe) prepared match: {s}", .{symlink_full_path}); - return null; - } - if (comptime !sentinel) { - const slice = try this.arena.allocator().dupe(u8, symlink_full_path); - result.key_ptr.* = matchedPathToBunString(slice); - return slice; - } - const slicez = try this.arena.allocator().dupeZ(u8, symlink_full_path); - result.key_ptr.* = matchedPathToBunString(slicez); - return slicez; - } - - fn prepareMatchedPath(this: *GlobWalker, entry_name: []const u8, dir_name: []const u8) !?MatchedPath { - const subdir_parts: []const []const u8 = &[_][]const u8{ - dir_name[0..dir_name.len], - entry_name, - }; - const name_matched_path = try this.join(subdir_parts); - const name = matchedPathToBunString(name_matched_path); - const result = try this.matchedPaths.getOrPutValue(this.arena.allocator(), name, {}); - if (result.found_existing) { - log("(dupe) prepared match: {s}", .{name_matched_path}); - this.arena.allocator().free(name_matched_path); - return null; - } - result.key_ptr.* = name; - // if (comptime sentinel) return name[0 .. name.len - 1 :0]; - log("prepared match: {s}", .{name_matched_path}); - return name_matched_path; - } - - fn appendMatchedPath( - this: *GlobWalker, - entry_name: []const u8, - dir_name: [:0]const u8, - ) !void { - const subdir_parts: []const []const u8 = &[_][]const u8{ - dir_name[0..dir_name.len], - entry_name, - }; - const name_matched_path = try this.join(subdir_parts); - const name = matchedPathToBunString(name_matched_path); - const result = try this.matchedPaths.getOrPut(this.arena.allocator(), name); - if (result.found_existing) { - this.arena.allocator().free(name_matched_path); - log("(dupe) prepared match: {s}", .{name_matched_path}); - return; - } - result.key_ptr.* = name; - } - - fn appendMatchedPathSymlink(this: *GlobWalker, symlink_full_path: []const u8) !void { - const name = try this.arena.allocator().dupe(u8, symlink_full_path); - try this.matchedPaths.put(this.arena.allocator(), BunString.fromBytes(name), {}); - } - - inline fn join(this: *GlobWalker, subdir_parts: []const []const u8) !MatchedPath { - if (!this.absolute) { - // If relative paths enabled, stdlib join is preferred over - // ResolvePath.joinBuf because it doesn't try to normalize the path - return try stdJoin(this.arena.allocator(), subdir_parts); - } - - const out = try this.arena.allocator().dupe(u8, bunJoin(subdir_parts, .auto)); - if (comptime sentinel) return out[0 .. out.len - 1 :0]; - - return out; - } - - inline fn startsWithDot(filepath: []const u8) bool { - return filepath.len > 0 and filepath[0] == '.'; - } - - fn checkSpecialSyntax(pattern: []const u8) bool { - if (pattern.len < 16) { - for (pattern[0..]) |c| { - switch (c) { - '*', '[', '{', '?', '!' => return true, - else => {}, - } - } - return false; - } - - const syntax_tokens = comptime [_]u8{ '*', '[', '{', '?', '!' }; - const needles: [syntax_tokens.len]@Vector(16, u8) = comptime needles: { - var needles: [syntax_tokens.len]@Vector(16, u8) = undefined; - for (syntax_tokens, 0..) |tok, i| { - needles[i] = @splat(tok); - } - break :needles needles; - }; - - var i: usize = 0; - while (i + 16 <= pattern.len) : (i += 16) { - const haystack: @Vector(16, u8) = pattern[i..][0..16].*; - inline for (needles) |needle| { - if (std.simd.firstTrue(needle == haystack) != null) return true; - } - } - - if (i < pattern.len) { - for (pattern[i..]) |c| { - inline for (syntax_tokens) |tok| { - if (c == tok) return true; - } - } - } - - return false; - } - - fn makeComponent( - pattern: []const u8, - start_cp: u32, - end_cp: u32, - start_byte: u32, - end_byte: u32, - has_relative_patterns: *bool, - ) ?Component { - var component: Component = .{ - .start = start_byte, - .len = end_byte - start_byte, - .start_cp = start_cp, - .end_cp = end_cp, - }; - if (component.len == 0) return null; - - out: { - if (component.len == 1 and pattern[component.start] == '.') { - component.syntax_hint = .Dot; - has_relative_patterns.* = true; - break :out; - } - if (component.len == 2 and pattern[component.start] == '.' and pattern[component.start] == '.') { - component.syntax_hint = .DotBack; - has_relative_patterns.* = true; - break :out; - } - - if (!GlobWalker.checkSpecialSyntax(pattern[component.start .. component.start + component.len])) { - component.syntax_hint = .Literal; - break :out; - } - - switch (component.len) { - 1 => { - if (pattern[component.start] == '*') { - component.syntax_hint = .Single; - } - break :out; - }, - 2 => { - if (pattern[component.start] == '*' and pattern[component.start + 1] == '*') { - component.syntax_hint = .Double; - break :out; - } - }, - else => {}, - } - - out_of_check_wildcard_filepath: { - if (component.len > 1 and - pattern[component.start] == '*' and - pattern[component.start + 1] == '.' and - component.start + 2 < pattern.len) - { - for (pattern[component.start + 2 ..]) |c| { - switch (c) { - // The fast path checks that path[1..] == pattern[1..], - // this will obviously not work if additional - // glob syntax is present in the pattern, so we - // must not apply this optimization if we see - // special glob syntax. - // - // This is not a complete check, there can be - // false negatives, but that's okay, it just - // means we don't apply the optimization. - // - // We also don't need to look for the `!` token, - // because that only applies negation if at the - // beginning of the string. - '[', '{', '?', '*' => break :out_of_check_wildcard_filepath, - else => {}, - } - } - component.syntax_hint = .WildcardFilepath; - break :out; - } - } - } - - if (component.syntax_hint != .Single and component.syntax_hint != .Double) { - if (isAllAscii(pattern[component.start .. component.start + component.len])) { - component.is_ascii = true; - } - } else { - component.is_ascii = true; - } - - if (pattern[component.start + component.len -| 1] == '/') { - component.trailing_sep = true; - } else if (comptime bun.Environment.isWindows) { - component.trailing_sep = pattern[component.start + component.len -| 1] == '\\'; - } - - return component; - } - - fn buildPatternComponents( - arena: *Arena, - patternComponents: *ArrayList(Component), - pattern: []const u8, - out_cp_len: *u32, - out_pattern_cp: *[]u32, - has_relative_patterns: *bool, - end_byte_of_basename_excluding_special_syntax: *u32, - basename_excluding_special_syntax_component_idx: *u32, - ) !void { - var start_cp: u32 = 0; - var start_byte: u32 = 0; - - const iter = CodepointIterator.init(pattern); - var cursor = CodepointIterator.Cursor{}; - - var cp_len: u32 = 0; - var prevIsBackslash = false; - var saw_special = false; - while (iter.next(&cursor)) : (cp_len += 1) { - const c = cursor.c; - - switch (c) { - '\\' => { - if (comptime isWindows) { - var end_cp = cp_len; - var end_byte = cursor.i; - // is last char - if (cursor.i + cursor.width == pattern.len) { - end_cp += 1; - end_byte += cursor.width; - } - if (makeComponent( - pattern, - start_cp, - end_cp, - start_byte, - end_byte, - has_relative_patterns, - )) |component| { - saw_special = saw_special or component.syntax_hint.isSpecialSyntax(); - if (!saw_special) { - basename_excluding_special_syntax_component_idx.* = @intCast(patternComponents.items.len); - end_byte_of_basename_excluding_special_syntax.* = cursor.i + cursor.width; - } - try patternComponents.append(arena.allocator(), component); - } - start_cp = cp_len + 1; - start_byte = cursor.i + cursor.width; - continue; - } - - if (prevIsBackslash) { - prevIsBackslash = false; - continue; - } - - prevIsBackslash = true; - }, - '/' => { - var end_cp = cp_len; - var end_byte = cursor.i; - // is last char - if (cursor.i + cursor.width == pattern.len) { - end_cp += 1; - end_byte += cursor.width; - } - if (makeComponent( - pattern, - start_cp, - end_cp, - start_byte, - end_byte, - has_relative_patterns, - )) |component| { - saw_special = saw_special or component.syntax_hint.isSpecialSyntax(); - if (!saw_special) { - basename_excluding_special_syntax_component_idx.* = @intCast(patternComponents.items.len); - end_byte_of_basename_excluding_special_syntax.* = cursor.i + cursor.width; - } - try patternComponents.append(arena.allocator(), component); - } - start_cp = cp_len + 1; - start_byte = cursor.i + cursor.width; - }, - // TODO: Support other escaping glob syntax - else => {}, - } - } - - out_cp_len.* = cp_len; - - const codepoints = try arena.allocator().alloc(u32, cp_len); - // On Windows filepaths are UTF-16 so its better to fill the codepoints buffer upfront - if (comptime isWindows) { - GlobWalker.convertUtf8ToCodepoints(codepoints, pattern); - } - out_pattern_cp.* = codepoints; - - const end_cp = cp_len; - if (makeComponent( - pattern, - start_cp, - end_cp, - start_byte, - @intCast(pattern.len), - has_relative_patterns, - )) |component| { - saw_special = saw_special or component.syntax_hint.isSpecialSyntax(); - if (!saw_special) { - basename_excluding_special_syntax_component_idx.* = @intCast(patternComponents.items.len); - end_byte_of_basename_excluding_special_syntax.* = cursor.i + cursor.width; - } - try patternComponents.append(arena.allocator(), component); - } else if (!saw_special) { - basename_excluding_special_syntax_component_idx.* = @intCast(patternComponents.items.len); - end_byte_of_basename_excluding_special_syntax.* = cursor.i + cursor.width; - } - } - }; -} - -// From: https://github.com/The-King-of-Toasters/globlin -/// State for matching a glob against a string -pub const GlobState = struct { - // These store character indices into the glob and path strings. - path_index: CursorState = .{}, - glob_index: u32 = 0, - // When we hit a * or **, we store the state for backtracking. - wildcard: Wildcard = .{}, - globstar: Wildcard = .{}, - - fn init(path_iter: *const CodepointIterator) GlobState { - var this = GlobState{}; - // this.glob_index = CursorState.init(glob_iter); - this.path_index = CursorState.init(path_iter); - return this; - } - - fn skipBraces(self: *GlobState, glob: []const u32, stop_on_comma: bool) BraceState { - var braces: u32 = 1; - var in_brackets = false; - while (self.glob_index < glob.len and braces > 0) : (self.glob_index += 1) { - switch (glob[self.glob_index]) { - // Skip nested braces - '{' => if (!in_brackets) { - braces += 1; - }, - '}' => if (!in_brackets) { - braces -= 1; - }, - ',' => if (stop_on_comma and braces == 1 and !in_brackets) { - self.glob_index += 1; - return .Comma; - }, - '*', '?', '[' => |c| if (!in_brackets) { - if (c == '[') - in_brackets = true; - }, - ']' => in_brackets = false, - '\\' => self.glob_index += 1, - else => {}, - } - } - - if (braces != 0) - return .Invalid; - return .EndBrace; - } - - inline fn backtrack(self: *GlobState) void { - self.glob_index = self.wildcard.glob_index; - self.path_index = self.wildcard.path_index; - } -}; - -const Wildcard = struct { - // Using u32 rather than usize for these results in 10% faster performance. - // glob_index: CursorState = .{}, - glob_index: u32 = 0, - path_index: CursorState = .{}, -}; - -const BraceState = enum { Invalid, Comma, EndBrace }; - -const BraceStack = struct { - stack: [10]GlobState = undefined, - len: u32 = 0, - longest_brace_match: CursorState = .{}, - - inline fn push(self: *BraceStack, state: *const GlobState) GlobState { - self.stack[self.len] = state.*; - self.len += 1; - return GlobState{ - .path_index = state.path_index, - .glob_index = state.glob_index + 1, - }; - } - - inline fn pop(self: *BraceStack, state: *const GlobState) GlobState { - self.len -= 1; - const s = GlobState{ - .glob_index = state.glob_index, - .path_index = self.longest_brace_match, - // Restore star state if needed later. - .wildcard = self.stack[self.len].wildcard, - .globstar = self.stack[self.len].globstar, - }; - if (self.len == 0) - self.longest_brace_match = .{}; - return s; - } - - inline fn last(self: *const BraceStack) *const GlobState { - return &self.stack[self.len - 1]; - } -}; - -pub const MatchResult = enum { - no_match, - match, - - negate_no_match, - negate_match, - - pub fn matches(this: MatchResult) bool { - return this == .match or this == .negate_match; - } -}; - -/// This function checks returns a boolean value if the pathname `path` matches -/// the pattern `glob`. -/// -/// The supported pattern syntax for `glob` is: -/// -/// "?" -/// Matches any single character. -/// "*" -/// Matches zero or more characters, except for path separators ('/' or '\'). -/// "**" -/// Matches zero or more characters, including path separators. -/// Must match a complete path segment, i.e. followed by a path separator or -/// at the end of the pattern. -/// "[ab]" -/// Matches one of the characters contained in the brackets. -/// Character ranges (e.g. "[a-z]") are also supported. -/// Use "[!ab]" or "[^ab]" to match any character *except* those contained -/// in the brackets. -/// "{a,b}" -/// Match one of the patterns contained in the braces. -/// Any of the wildcards listed above can be used in the sub patterns. -/// Braces may be nested up to 10 levels deep. -/// "!" -/// Negates the result when at the start of the pattern. -/// Multiple "!" characters negate the pattern multiple times. -/// "\" -/// Used to escape any of the special characters above. -pub fn matchImpl(glob: []const u32, path: []const u8) MatchResult { - const path_iter = CodepointIterator.init(path); - - // This algorithm is based on https://research.swtch.com/glob - var state = GlobState.init(&path_iter); - // Store the state when we see an opening '{' brace in a stack. - // Up to 10 nested braces are supported. - var brace_stack = BraceStack{}; - - // First, check if the pattern is negated with a leading '!' character. - // Multiple negations can occur. - var negated = false; - while (state.glob_index < glob.len and glob[state.glob_index] == '!') { - negated = !negated; - state.glob_index += 1; - } - - while (state.glob_index < glob.len or state.path_index.cursor.i < path.len) { - if (state.glob_index < glob.len) { - switch (glob[state.glob_index]) { - '*' => { - const is_globstar = state.glob_index + 1 < glob.len and glob[state.glob_index + 1] == '*'; - // const is_globstar = state.glob_index.cursor.i + state.glob_index.cursor.width < glob.len and - // state.glob_index.peek(&glob_iter).cursor.c == '*'; - if (is_globstar) { - // Coalesce multiple ** segments into one. - var index = state.glob_index + 2; - state.glob_index = skipGlobstars(glob, &index) - 2; - } - - state.wildcard.glob_index = state.glob_index; - state.wildcard.path_index = state.path_index.peek(&path_iter); - - // ** allows path separators, whereas * does not. - // However, ** must be a full path component, i.e. a/**/b not a**b. - if (is_globstar) { - // Skip wildcards - state.glob_index += 2; - - if (glob.len == state.glob_index) { - // A trailing ** segment without a following separator. - state.globstar = state.wildcard; - } else if (glob[state.glob_index] == '/' and - (state.glob_index < 3 or glob[state.glob_index - 3] == '/')) - { - // Matched a full /**/ segment. If the last character in the path was a separator, - // skip the separator in the glob so we search for the next character. - // In effect, this makes the whole segment optional so that a/**/b matches a/b. - if (state.path_index.cursor.i == 0 or - (state.path_index.cursor.i < path.len and - isSeparator(path[state.path_index.cursor.i - 1]))) - { - state.glob_index += 1; - } - - // The allows_sep flag allows separator characters in ** matches. - // one is a '/', which prevents a/**/b from matching a/bb. - state.globstar = state.wildcard; - } - } else { - state.glob_index += 1; - } - - // If we are in a * segment and hit a separator, - // either jump back to a previous ** or end the wildcard. - if (state.globstar.path_index.cursor.i != state.wildcard.path_index.cursor.i and - state.path_index.cursor.i < path.len and - isSeparator(state.path_index.cursor.c)) - { - // Special case: don't jump back for a / at the end of the glob. - if (state.globstar.path_index.cursor.i > 0 and state.path_index.cursor.i + state.path_index.cursor.width < path.len) { - state.glob_index = state.globstar.glob_index; - state.wildcard.glob_index = state.globstar.glob_index; - } else { - state.wildcard.path_index.cursor.i = 0; - } - } - - // If the next char is a special brace separator, - // skip to the end of the braces so we don't try to match it. - if (brace_stack.len > 0 and - state.glob_index < glob.len and - (glob[state.glob_index] == ',' or glob[state.glob_index] == '}')) - { - if (state.skipBraces(glob, false) == .Invalid) - return .no_match; // invalid pattern! - } - - continue; - }, - '?' => if (state.path_index.cursor.i < path.len) { - if (!isSeparator(state.path_index.cursor.c)) { - state.glob_index += 1; - state.path_index.bump(&path_iter); - continue; - } - }, - '[' => if (state.path_index.cursor.i < path.len) { - state.glob_index += 1; - const c = state.path_index.cursor.c; - - // Check if the character class is negated. - var class_negated = false; - if (state.glob_index < glob.len and - (glob[state.glob_index] == '^' or glob[state.glob_index] == '!')) - { - class_negated = true; - state.glob_index += 1; - } - - // Try each range. - var first = true; - var is_match = false; - while (state.glob_index < glob.len and (first or glob[state.glob_index] != ']')) { - var low = glob[state.glob_index]; - if (!unescape(&low, glob, &state.glob_index)) - return .no_match; // Invalid pattern - state.glob_index += 1; - - // If there is a - and the following character is not ], - // read the range end character. - const high = if (state.glob_index + 1 < glob.len and - glob[state.glob_index] == '-' and glob[state.glob_index + 1] != ']') - blk: { - state.glob_index += 1; - var h = glob[state.glob_index]; - if (!unescape(&h, glob, &state.glob_index)) - return .no_match; // Invalid pattern! - state.glob_index += 1; - break :blk h; - } else low; - - if (low <= c and c <= high) - is_match = true; - first = false; - } - if (state.glob_index >= glob.len) - return .no_match; // Invalid pattern! - state.glob_index += 1; - if (is_match != class_negated) { - state.path_index.bump(&path_iter); - continue; - } - }, - '{' => if (state.path_index.cursor.i < path.len) { - if (brace_stack.len >= brace_stack.stack.len) - return .no_match; // Invalid pattern! Too many nested braces. - - // Push old state to the stack, and reset current state. - state = brace_stack.push(&state); - continue; - }, - '}' => if (brace_stack.len > 0) { - // If we hit the end of the braces, we matched the last option. - brace_stack.longest_brace_match = if (state.path_index.cursor.i >= brace_stack.longest_brace_match.cursor.i) - state.path_index - else - brace_stack.longest_brace_match; - state.glob_index += 1; - state = brace_stack.pop(&state); - continue; - }, - ',' => if (brace_stack.len > 0) { - // If we hit a comma, we matched one of the options! - // But we still need to check the others in case there is a longer match. - brace_stack.longest_brace_match = if (state.path_index.cursor.i >= brace_stack.longest_brace_match.cursor.i) - state.path_index - else - brace_stack.longest_brace_match; - state.path_index = brace_stack.last().path_index; - state.glob_index += 1; - state.wildcard = Wildcard{}; - state.globstar = Wildcard{}; - continue; - }, - else => |c| if (state.path_index.cursor.i < path.len) { - var cc = c; - // Match escaped characters as literals. - if (!unescape(&cc, glob, &state.glob_index)) - return .no_match; // Invalid pattern; - - const is_match = if (cc == '/') - isSeparator(state.path_index.cursor.c) - else - state.path_index.cursor.c == cc; - - if (is_match) { - if (brace_stack.len > 0 and - state.glob_index > 0 and - glob[state.glob_index - 1] == '}') - { - brace_stack.longest_brace_match = state.path_index; - state = brace_stack.pop(&state); - } - state.glob_index += 1; - state.path_index.bump(&path_iter); - - // If this is not a separator, lock in the previous globstar. - if (cc != '/') - state.globstar.path_index.cursor.i = 0; - - continue; - } - }, - } - } - // If we didn't match, restore state to the previous star pattern. - if (state.wildcard.path_index.cursor.i > 0 and state.wildcard.path_index.cursor.i <= path.len) { - state.backtrack(); - continue; - } - - if (brace_stack.len > 0) { - // If in braces, find next option and reset path to index where we saw the '{' - switch (state.skipBraces(glob, true)) { - .Invalid => return .no_match, - .Comma => { - state.path_index = brace_stack.last().path_index; - continue; - }, - .EndBrace => {}, - } - - // Hit the end. Pop the stack. - // If we matched a previous option, use that. - if (brace_stack.longest_brace_match.cursor.i > 0) { - state = brace_stack.pop(&state); - continue; - } else { - // Didn't match. Restore state, and check if we need to jump back to a star pattern. - state = brace_stack.last().*; - brace_stack.len -= 1; - if (state.wildcard.path_index.cursor.i > 0 and state.wildcard.path_index.cursor.i <= path.len) { - state.backtrack(); - continue; - } - } - } - - return if (negated) .negate_match else .no_match; - } - - return if (!negated) .match else .negate_no_match; -} - -pub inline fn isSeparator(c: Codepoint) bool { - if (comptime @import("builtin").os.tag == .windows) return c == '/' or c == '\\'; - return c == '/'; -} - -inline fn unescape(c: *u32, glob: []const u32, glob_index: *u32) bool { - if (c.* == '\\') { - glob_index.* += 1; - if (glob_index.* >= glob.len) - return false; // Invalid pattern! - - c.* = switch (glob[glob_index.*]) { - 'a' => '\x61', - 'b' => '\x08', - 'n' => '\n', - 'r' => '\r', - 't' => '\t', - else => |cc| cc, - }; - } - - return true; -} - -const GLOB_STAR_MATCH_STR: []const u32 = &[_]u32{ '/', '*', '*' }; -// src/**/**/foo.ts -inline fn skipGlobstars(glob: []const u32, glob_index: *u32) u32 { - // Coalesce multiple ** segments into one. - while (glob_index.* + 3 <= glob.len and - // std.mem.eql(u8, glob[glob_index.*..][0..3], "/**")) - std.mem.eql(u32, glob[glob_index.*..][0..3], GLOB_STAR_MATCH_STR)) - { - glob_index.* += 3; - } - - return glob_index.*; -} - -const MatchAscii = struct {}; - -pub fn matchWildcardFilepath(glob: []const u8, path: []const u8) bool { - const needle = glob[1..]; - const needle_len: u32 = @intCast(needle.len); - if (path.len < needle_len) return false; - return std.mem.eql(u8, needle, path[path.len - needle_len ..]); -} - -pub fn matchWildcardLiteral(literal: []const u8, path: []const u8) bool { - return std.mem.eql(u8, literal, path); -} - -/// Returns true if the given string contains glob syntax, -/// excluding those escaped with backslashes -/// TODO: this doesn't play nicely with Windows directory separator and -/// backslashing, should we just require the user to supply posix filepaths? -pub fn detectGlobSyntax(potential_pattern: []const u8) bool { - // Negation only allowed in the beginning of the pattern - if (potential_pattern.len > 0 and potential_pattern[0] == '!') return true; - - // In descending order of how popular the token is - const SPECIAL_SYNTAX: [4]u8 = comptime [_]u8{ '*', '{', '[', '?' }; - - inline for (SPECIAL_SYNTAX) |token| { - var slice = potential_pattern[0..]; - while (slice.len > 0) { - if (std.mem.indexOfScalar(u8, slice, token)) |idx| { - // Check for even number of backslashes preceding the - // token to know that it's not escaped - var i = idx; - var backslash_count: u16 = 0; - - while (i > 0 and potential_pattern[i - 1] == '\\') : (i -= 1) { - backslash_count += 1; - } - - if (backslash_count % 2 == 0) return true; - slice = slice[idx + 1 ..]; - } else break; - } - } - - return false; -} +pub const GlobWalker = walk.GlobWalker_; +pub const BunGlobWalker = GlobWalker(null, walk.SyscallAccessor, false); +pub const BunGlobWalkerZ = GlobWalker(null, walk.SyscallAccessor, true); diff --git a/src/glob/GlobWalker.zig b/src/glob/GlobWalker.zig new file mode 100644 index 0000000000..f41b47f7a6 --- /dev/null +++ b/src/glob/GlobWalker.zig @@ -0,0 +1,2191 @@ +// Portions of this file are derived from works under the MIT License: +// +// Copyright (c) 2023 Devon Govett +// Copyright (c) 2023 Stephen Gregoratto +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +const std = @import("std"); +const bun = @import("root").bun; + +const eqlComptime = @import("../string_immutable.zig").eqlComptime; +const expect = std.testing.expect; +const isAllAscii = @import("../string_immutable.zig").isAllASCII; +const math = std.math; +const mem = std.mem; +const isWindows = @import("builtin").os.tag == .windows; + +const Allocator = std.mem.Allocator; +const Arena = std.heap.ArenaAllocator; +const ArrayList = std.ArrayListUnmanaged; +const ArrayListManaged = std.ArrayList; +const BunString = bun.String; +const C = @import("../c.zig"); +const CodepointIterator = @import("../string_immutable.zig").PackedCodepointIterator; +const Codepoint = CodepointIterator.Cursor.CodePointType; +const Dirent = @import("../bun.js/node/types.zig").Dirent; +const DirIterator = @import("../bun.js/node/dir_iterator.zig"); +const EntryKind = @import("../bun.js/node/types.zig").Dirent.Kind; +const GlobAscii = @import("./ascii.zig"); +const JSC = bun.JSC; +const Maybe = JSC.Maybe; +const PathLike = @import("../bun.js/node/types.zig").PathLike; +const PathString = @import("../string_types.zig").PathString; +const ResolvePath = @import("../resolver/resolve_path.zig"); +const Syscall = bun.sys; +const ZigString = @import("../bun.js/bindings/bindings.zig").ZigString; + +// const Codepoint = u32; +const Cursor = CodepointIterator.Cursor; + +const log = bun.Output.scoped(.Glob, false); + +const CursorState = struct { + cursor: CodepointIterator.Cursor = .{}, + /// The index in terms of codepoints + // cp_idx: usize, + + fn init(iterator: *const CodepointIterator) CursorState { + var this_cursor: CodepointIterator.Cursor = .{}; + _ = iterator.next(&this_cursor); + return .{ + // .cp_idx = 0, + .cursor = this_cursor, + }; + } + + /// Return cursor pos of next codepoint without modifying the current. + /// + /// NOTE: If there is no next codepoint (cursor is at the last one), then + /// the returned cursor will have `c` as zero value and `i` will be >= + /// sourceBytes.len + fn peek(this: *const CursorState, iterator: *const CodepointIterator) CursorState { + var cpy = this.*; + // If outside of bounds + if (!iterator.next(&cpy.cursor)) { + // This will make `i >= sourceBytes.len` + cpy.cursor.i += cpy.cursor.width; + cpy.cursor.width = 1; + cpy.cursor.c = CodepointIterator.ZeroValue; + } + // cpy.cp_idx += 1; + return cpy; + } + + fn bump(this: *CursorState, iterator: *const CodepointIterator) void { + if (!iterator.next(&this.cursor)) { + this.cursor.i += this.cursor.width; + this.cursor.width = 1; + this.cursor.c = CodepointIterator.ZeroValue; + } + // this.cp_idx += 1; + } + + inline fn manualBumpAscii(this: *CursorState, i: u32, nextCp: Codepoint) void { + this.cursor.i += i; + this.cursor.c = nextCp; + this.cursor.width = 1; + } + + inline fn manualPeekAscii(this: *CursorState, i: u32, nextCp: Codepoint) CursorState { + return .{ + .cursor = CodepointIterator.Cursor{ + .i = this.cursor.i + i, + .c = @truncate(nextCp), + .width = 1, + }, + }; + } +}; + +fn dummyFilterTrue(val: []const u8) bool { + _ = val; + return true; +} + +fn dummyFilterFalse(val: []const u8) bool { + _ = val; + return false; +} + +pub fn statatWindows(fd: bun.FileDescriptor, path: [:0]const u8) Maybe(bun.Stat) { + if (comptime !bun.Environment.isWindows) @compileError("oi don't use this"); + var buf: bun.PathBuffer = undefined; + const dir = switch (Syscall.getFdPath(fd, &buf)) { + .err => |e| return .{ .err = e }, + .result => |s| s, + }; + const parts: []const []const u8 = &.{ + dir[0..dir.len], + path, + }; + const statpath = ResolvePath.joinZBuf(&buf, parts, .auto); + return Syscall.stat(statpath); +} + +pub const SyscallAccessor = struct { + const count_fds = true; + + const Handle = struct { + value: bun.FileDescriptor, + + const zero = Handle{ .value = bun.FileDescriptor.zero }; + + pub fn isZero(this: Handle) bool { + return this.value == bun.FileDescriptor.zero; + } + + pub fn eql(this: Handle, other: Handle) bool { + return this.value == other.value; + } + }; + + const DirIter = struct { + value: DirIterator.WrappedIterator, + + pub inline fn next(self: *DirIter) Maybe(?DirIterator.IteratorResult) { + return self.value.next(); + } + + pub inline fn iterate(dir: Handle) DirIter { + return .{ .value = DirIterator.WrappedIterator.init(dir.value.asDir()) }; + } + }; + + pub fn open(path: [:0]const u8) !Maybe(Handle) { + return switch (Syscall.open(path, bun.O.DIRECTORY | bun.O.RDONLY, 0)) { + .err => |err| .{ .err = err }, + .result => |fd| .{ .result = Handle{ .value = fd } }, + }; + } + + pub fn statat(handle: Handle, path: [:0]const u8) Maybe(bun.Stat) { + if (comptime bun.Environment.isWindows) return statatWindows(handle.value, path); + return switch (Syscall.fstatat(handle.value, path)) { + .err => |err| .{ .err = err }, + .result => |s| .{ .result = s }, + }; + } + + pub fn openat(handle: Handle, path: [:0]const u8) !Maybe(Handle) { + return switch (Syscall.openat(handle.value, path, bun.O.DIRECTORY | bun.O.RDONLY, 0)) { + .err => |err| .{ .err = err }, + .result => |fd| .{ .result = Handle{ .value = fd } }, + }; + } + + pub fn close(handle: Handle) ?Syscall.Error { + return Syscall.close(handle.value); + } + + pub fn getcwd(path_buf: *bun.PathBuffer) Maybe([]const u8) { + return Syscall.getcwd(path_buf); + } +}; + +pub const DirEntryAccessor = struct { + const FS = bun.fs.FileSystem; + + const count_fds = false; + + const Handle = struct { + value: ?*FS.DirEntry, + + const zero = Handle{ .value = null }; + + pub fn isZero(this: Handle) bool { + return this.value == null; + } + + pub fn eql(this: Handle, other: Handle) bool { + // TODO this might not be quite right, we're comparing pointers, not the underlying directory + // On the other hand, DirEntries are only ever created once (per generation), so this should be fine? + // Realistically, as closing the handle is a no-op, this should be fine either way. + return this.value == other.value; + } + }; + + const DirIter = struct { + value: ?FS.DirEntry.EntryMap.Iterator, + + const IterResult = struct { + name: NameWrapper, + kind: std.fs.File.Kind, + + const NameWrapper = struct { + value: []const u8, + + pub fn slice(this: NameWrapper) []const u8 { + return this.value; + } + }; + }; + + pub inline fn next(self: *DirIter) Maybe(?IterResult) { + if (self.value) |*value| { + const nextval = value.next() orelse return .{ .result = null }; + const name = nextval.key_ptr.*; + const kind = nextval.value_ptr.*.kind(&FS.instance.fs, true); + const fskind = switch (kind) { + .file => std.fs.File.Kind.file, + .dir => std.fs.File.Kind.directory, + }; + return .{ + .result = .{ + .name = IterResult.NameWrapper{ .value = name }, + .kind = fskind, + }, + }; + } else { + return .{ .result = null }; + } + } + + pub inline fn iterate(dir: Handle) DirIter { + const entry = dir.value orelse return DirIter{ .value = null }; + return .{ .value = entry.data.iterator() }; + } + }; + + pub fn statat(handle: Handle, path_: [:0]const u8) Maybe(bun.Stat) { + var path: [:0]const u8 = path_; + var buf: bun.PathBuffer = undefined; + if (!bun.path.Platform.auto.isAbsolute(path)) { + if (handle.value) |entry| { + const slice = bun.path.joinStringBuf(&buf, [_][]const u8{ entry.dir, path }, .auto); + buf[slice.len] = 0; + path = buf[0..slice.len :0]; + } + } + return Syscall.stat(path); + } + + pub fn open(path: [:0]const u8) !Maybe(Handle) { + return openat(Handle.zero, path); + } + + pub fn openat(handle: Handle, path_: [:0]const u8) !Maybe(Handle) { + var path: []const u8 = path_; + var buf: bun.PathBuffer = undefined; + + if (!bun.path.Platform.auto.isAbsolute(path)) { + if (handle.value) |entry| { + path = bun.path.joinStringBuf(&buf, [_][]const u8{ entry.dir, path }, .auto); + } + } + // TODO do we want to propagate ENOTDIR through the 'Maybe' to match the SyscallAccessor? + // The glob implementation specifically checks for this error when dealing with symlinks + // return .{ .err = Syscall.Error.fromCode(bun.C.E.NOTDIR, Syscall.Tag.open) }; + const res = FS.instance.fs.readDirectory(path, null, 0, false) catch |err| { + return err; + }; + switch (res.*) { + .entries => |entry| { + return .{ .result = Handle{ .value = entry } }; + }, + .err => |err| { + return err.original_err; + }, + } + } + + pub inline fn close(handle: Handle) ?Syscall.Error { + // TODO is this a noop? + _ = handle; + return null; + } + + pub fn getcwd(path_buf: *bun.PathBuffer) Maybe([]const u8) { + @memcpy(path_buf, bun.fs.FileSystem.instance.fs.cwd); + } +}; + +pub fn GlobWalker_( + comptime ignore_filter_fn: ?*const fn ([]const u8) bool, + comptime Accessor: type, + comptime sentinel: bool, +) type { + const is_ignored: *const fn ([]const u8) bool = if (comptime ignore_filter_fn) |func| func else dummyFilterFalse; + + const count_fds = Accessor.count_fds and bun.Environment.isDebug; + + const stdJoin = comptime if (!sentinel) std.fs.path.join else std.fs.path.joinZ; + const bunJoin = comptime if (!sentinel) ResolvePath.join else ResolvePath.joinZ; + const MatchedPath = comptime if (!sentinel) []const u8 else [:0]const u8; + + return struct { + const GlobWalker = @This(); + pub const Result = Maybe(void); + + arena: Arena = undefined, + + /// not owned by this struct + pattern: []const u8 = "", + + pattern_codepoints: []u32 = &[_]u32{}, + cp_len: u32 = 0, + + /// If the pattern contains "./" or "../" + has_relative_components: bool = false, + + end_byte_of_basename_excluding_special_syntax: u32 = 0, + basename_excluding_special_syntax_component_idx: u32 = 0, + + patternComponents: ArrayList(Component) = .{}, + matchedPaths: MatchedMap = .{}, + i: u32 = 0, + + dot: bool = false, + absolute: bool = false, + + cwd: []const u8 = "", + follow_symlinks: bool = false, + error_on_broken_symlinks: bool = false, + only_files: bool = true, + + pathBuf: bun.PathBuffer = undefined, + // iteration state + workbuf: ArrayList(WorkItem) = ArrayList(WorkItem){}, + + /// Array hashmap used as a set (values are the keys) + /// to store matched paths and prevent duplicates + /// + /// BunString is used so that we can call BunString.toJSArray() + /// on the result of `.keys()` to give the result back to JS + /// + /// The only type of string impl we use is ZigString since + /// all matched paths are UTF-8 (DirIterator converts them on + /// windows) and allocated on the arnea + /// + /// Multiple patterns are not supported so right now this is + /// only possible when running a pattern like: + /// + /// `foo/**/*` + /// + /// Use `.keys()` to get the matched paths + const MatchedMap = std.ArrayHashMapUnmanaged(BunString, void, struct { + pub fn hash(_: @This(), this: BunString) u32 { + bun.assert(this.tag == .ZigString); + const slice = this.byteSlice(); + if (comptime sentinel) { + const slicez = slice[0 .. slice.len - 1 :0]; + return std.array_hash_map.hashString(slicez); + } + + return std.array_hash_map.hashString(slice); + } + + pub fn eql(_: @This(), this: BunString, other: BunString, _: usize) bool { + return this.eql(other); + } + }, true); + + /// The glob walker references the .directory.path so its not safe to + /// copy/move this + const IterState = union(enum) { + /// Pops the next item off the work stack + get_next, + + /// Currently iterating over a directory + directory: Directory, + + /// Two particular cases where this is used: + /// + /// 1. A pattern with no special glob syntax was supplied, for example: `/Users/zackradisic/foo/bar` + /// + /// In that case, the mere existence of the file/dir counts as a match, so we can eschew directory + /// iterating and walking for a simple stat call to the path. + /// + /// 2. Pattern ending in literal optimization + /// + /// With a pattern like: `packages/**/package.json`, once the iteration component index reaches + /// the final component, which is a literal string ("package.json"), we can similarly make a + /// single stat call to complete the pattern. + matched: MatchedPath, + + const Directory = struct { + fd: Accessor.Handle, + iter: Accessor.DirIter, + path: bun.PathBuffer, + dir_path: [:0]const u8, + + component_idx: u32, + pattern: *Component, + next_pattern: ?*Component, + is_last: bool, + + iter_closed: bool = false, + at_cwd: bool = false, + }; + }; + + pub const Iterator = struct { + walker: *GlobWalker, + iter_state: IterState = .get_next, + cwd_fd: Accessor.Handle = Accessor.Handle.zero, + empty_dir_path: [0:0]u8 = [0:0]u8{}, + /// This is to make sure in debug/tests that we are closing file descriptors + /// We should only have max 2 open at a time. One for the cwd, and one for the + /// directory being iterated on. + fds_open: if (count_fds) usize else u0 = 0, + + pub fn init(this: *Iterator) !Maybe(void) { + log("Iterator init pattern={s}", .{this.walker.pattern}); + var was_absolute = false; + const root_work_item = brk: { + var use_posix = bun.Environment.isPosix; + const is_absolute = if (bun.Environment.isPosix) std.fs.path.isAbsolute(this.walker.pattern) else std.fs.path.isAbsolute(this.walker.pattern) or is_absolute: { + use_posix = true; + break :is_absolute std.fs.path.isAbsolutePosix(this.walker.pattern); + }; + + if (!is_absolute) break :brk WorkItem.new(this.walker.cwd, 0, .directory); + + was_absolute = true; + + var path_without_special_syntax = this.walker.pattern[0..this.walker.end_byte_of_basename_excluding_special_syntax]; + var starting_component_idx = this.walker.basename_excluding_special_syntax_component_idx; + + if (path_without_special_syntax.len == 0) { + path_without_special_syntax = if (!bun.Environment.isWindows) "/" else ResolvePath.windowsFilesystemRoot(this.walker.cwd); + } else { + // Skip the components associated with the literal path + starting_component_idx += 1; + + // This means we got a pattern without any special glob syntax, for example: + // `/Users/zackradisic/foo/bar` + // + // In that case we don't need to do any walking and can just open up the FS entry + if (starting_component_idx >= this.walker.patternComponents.items.len) { + const path = try this.walker.arena.allocator().dupeZ(u8, path_without_special_syntax); + const fd = switch (try Accessor.open(path)) { + .err => |e| { + if (e.getErrno() == bun.C.E.NOTDIR) { + this.iter_state = .{ .matched = path }; + return Maybe(void).success; + } + // Doesn't exist + if (e.getErrno() == bun.C.E.NOENT) { + this.iter_state = .get_next; + return Maybe(void).success; + } + const errpath = try this.walker.arena.allocator().dupeZ(u8, path); + return .{ .err = e.withPath(errpath) }; + }, + .result => |fd| fd, + }; + _ = Accessor.close(fd); + this.iter_state = .{ .matched = path }; + return Maybe(void).success; + } + + // In the above branch, if `starting_compoennt_dix >= pattern_components.len` then + // it should also mean that `end_byte_of_basename_excluding_special_syntax >= pattern.len` + // + // So if we see that `end_byte_of_basename_excluding_special_syntax < this.walker.pattern.len` we + // miscalculated the values + bun.assert(this.walker.end_byte_of_basename_excluding_special_syntax < this.walker.pattern.len); + } + + break :brk WorkItem.new( + path_without_special_syntax, + starting_component_idx, + .directory, + ); + }; + + var path_buf: *bun.PathBuffer = &this.walker.pathBuf; + const root_path = root_work_item.path; + @memcpy(path_buf[0..root_path.len], root_path[0..root_path.len]); + path_buf[root_path.len] = 0; + const cwd_fd = switch (try Accessor.open(path_buf[0..root_path.len :0])) { + .err => |err| return .{ .err = this.walker.handleSysErrWithPath(err, @ptrCast(path_buf[0 .. root_path.len + 1])) }, + .result => |fd| fd, + }; + + if (comptime count_fds) { + this.fds_open += 1; + } + + this.cwd_fd = cwd_fd; + + switch (if (was_absolute) try this.transitionToDirIterState( + root_work_item, + false, + ) else try this.transitionToDirIterState( + root_work_item, + true, + )) { + .err => |err| return .{ .err = err }, + else => {}, + } + + return Maybe(void).success; + } + + pub fn deinit(this: *Iterator) void { + defer { + bun.debugAssert(this.fds_open == 0); + } + this.closeCwdFd(); + switch (this.iter_state) { + .directory => |dir| { + if (!dir.iter_closed) { + this.closeDisallowingCwd(dir.fd); + } + }, + else => {}, + } + + while (this.walker.workbuf.popOrNull()) |work_item| { + if (work_item.fd) |fd| { + this.closeDisallowingCwd(fd); + } + } + + if (comptime count_fds) { + bun.debugAssert(this.fds_open == 0); + } + } + + pub fn closeCwdFd(this: *Iterator) void { + if (this.cwd_fd.isZero()) return; + _ = Accessor.close(this.cwd_fd); + if (comptime count_fds) this.fds_open -= 1; + } + + pub fn closeDisallowingCwd(this: *Iterator, fd: Accessor.Handle) void { + if (fd.isZero() or fd.eql(this.cwd_fd)) return; + _ = Accessor.close(fd); + if (comptime count_fds) this.fds_open -= 1; + } + + pub fn bumpOpenFds(this: *Iterator) void { + if (comptime count_fds) { + this.fds_open += 1; + // If this is over 2 then this means that there is a bug in the iterator code + bun.debugAssert(this.fds_open <= 2); + } + } + + fn transitionToDirIterState( + this: *Iterator, + work_item: WorkItem, + comptime root: bool, + ) !Maybe(void) { + log("transition => {s}", .{work_item.path}); + this.iter_state = .{ .directory = .{ + .fd = Accessor.Handle.zero, + .iter = undefined, + .path = undefined, + .dir_path = undefined, + .component_idx = 0, + .pattern = undefined, + .next_pattern = null, + .is_last = false, + .iter_closed = false, + .at_cwd = false, + } }; + + var dir_path: [:0]u8 = dir_path: { + if (comptime root) { + if (!this.walker.absolute) { + this.iter_state.directory.path[0] = 0; + break :dir_path this.iter_state.directory.path[0..0 :0]; + } + } + // TODO Optimization: On posix systems filepaths are already null byte terminated so we can skip this if thats the case + @memcpy(this.iter_state.directory.path[0..work_item.path.len], work_item.path); + this.iter_state.directory.path[work_item.path.len] = 0; + break :dir_path this.iter_state.directory.path[0..work_item.path.len :0]; + }; + + var had_dot_dot = false; + const component_idx = this.walker.skipSpecialComponents(work_item.idx, &dir_path, &this.iter_state.directory.path, &had_dot_dot); + + const fd: Accessor.Handle = fd: { + if (work_item.fd) |fd| break :fd fd; + if (comptime root) { + if (had_dot_dot) break :fd switch (try Accessor.openat(this.cwd_fd, dir_path)) { + .err => |err| return .{ + .err = this.walker.handleSysErrWithPath(err, dir_path), + }, + .result => |fd_| brk: { + this.bumpOpenFds(); + break :brk fd_; + }, + }; + + this.iter_state.directory.at_cwd = true; + break :fd this.cwd_fd; + } + + break :fd switch (try Accessor.openat(this.cwd_fd, dir_path)) { + .err => |err| return .{ + .err = this.walker.handleSysErrWithPath(err, dir_path), + }, + .result => |fd_| brk: { + this.bumpOpenFds(); + break :brk fd_; + }, + }; + }; + + // Optimization: + // If we have a pattern like: + // `packages/*/package.json` + // ^ and we are at this component, with let's say + // a directory named: `packages/frontend/` + // + // Then we can just open `packages/frontend/package.json` without + // doing any iteration on the current directory. + // + // More generally, we can apply this optimization if we are on the + // last component and it is a literal with no special syntax. + if (component_idx == this.walker.patternComponents.items.len -| 1 and + this.walker.patternComponents.items[component_idx].syntax_hint == .Literal) + { + defer { + this.closeDisallowingCwd(fd); + } + const stackbuf_size = 256; + var stfb = std.heap.stackFallback(stackbuf_size, this.walker.arena.allocator()); + const pathz = try stfb.get().dupeZ(u8, this.walker.patternComponents.items[component_idx].patternSlice(this.walker.pattern)); + const stat_result: bun.Stat = switch (Accessor.statat(fd, pathz)) { + .err => |e_| { + var e: bun.sys.Error = e_; + if (e.getErrno() == bun.C.E.NOENT) { + this.iter_state = .get_next; + return Maybe(void).success; + } + return .{ .err = e.withPath(this.walker.patternComponents.items[component_idx].patternSlice(this.walker.pattern)) }; + }, + .result => |stat| stat, + }; + const matches = (bun.S.ISDIR(@intCast(stat_result.mode)) and !this.walker.only_files) or bun.S.ISREG(@intCast(stat_result.mode)) or !this.walker.only_files; + if (matches) { + if (try this.walker.prepareMatchedPath(pathz, dir_path)) |path| { + this.iter_state = .{ .matched = path }; + } else { + this.iter_state = .get_next; + } + } else { + this.iter_state = .get_next; + } + return Maybe(void).success; + } + + this.iter_state.directory.dir_path = dir_path; + this.iter_state.directory.component_idx = component_idx; + this.iter_state.directory.pattern = &this.walker.patternComponents.items[component_idx]; + this.iter_state.directory.next_pattern = if (component_idx + 1 < this.walker.patternComponents.items.len) &this.walker.patternComponents.items[component_idx + 1] else null; + this.iter_state.directory.is_last = component_idx == this.walker.patternComponents.items.len - 1; + this.iter_state.directory.at_cwd = false; + this.iter_state.directory.fd = Accessor.Handle.zero; + + log("Transition(dirpath={s}, fd={}, component_idx={d})", .{ dir_path, fd, component_idx }); + + this.iter_state.directory.fd = fd; + const iterator = Accessor.DirIter.iterate(fd); + this.iter_state.directory.iter = iterator; + this.iter_state.directory.iter_closed = false; + + return Maybe(void).success; + } + + pub fn next(this: *Iterator) !Maybe(?MatchedPath) { + while (true) { + switch (this.iter_state) { + .matched => |path| { + this.iter_state = .get_next; + return .{ .result = path }; + }, + .get_next => { + // Done + if (this.walker.workbuf.items.len == 0) return .{ .result = null }; + const work_item = this.walker.workbuf.pop(); + switch (work_item.kind) { + .directory => { + switch (try this.transitionToDirIterState(work_item, false)) { + .err => |err| return .{ .err = err }, + else => {}, + } + continue; + }, + .symlink => { + var scratch_path_buf: *bun.PathBuffer = &this.walker.pathBuf; + @memcpy(scratch_path_buf[0..work_item.path.len], work_item.path); + scratch_path_buf[work_item.path.len] = 0; + var symlink_full_path_z: [:0]u8 = scratch_path_buf[0..work_item.path.len :0]; + const entry_name = symlink_full_path_z[work_item.entry_start..symlink_full_path_z.len]; + + var has_dot_dot = false; + const component_idx = this.walker.skipSpecialComponents(work_item.idx, &symlink_full_path_z, scratch_path_buf, &has_dot_dot); + var pattern = this.walker.patternComponents.items[component_idx]; + const next_pattern = if (component_idx + 1 < this.walker.patternComponents.items.len) &this.walker.patternComponents.items[component_idx + 1] else null; + const is_last = component_idx == this.walker.patternComponents.items.len - 1; + + this.iter_state = .get_next; + const maybe_dir_fd: ?Accessor.Handle = switch (try Accessor.openat(this.cwd_fd, symlink_full_path_z)) { + .err => |err| brk: { + if (@as(usize, @intCast(err.errno)) == @as(usize, @intFromEnum(bun.C.E.NOTDIR))) { + break :brk null; + } + if (this.walker.error_on_broken_symlinks) return .{ .err = this.walker.handleSysErrWithPath(err, symlink_full_path_z) }; + // Broken symlink, but if `only_files` is false we still want to append + // it to the matched paths + if (!this.walker.only_files) { + // (See case A and B in the comment for `matchPatternFile()`) + // When we encounter a symlink we call the catch all + // matching function: `matchPatternImpl()` to see if we can avoid following the symlink. + // So for case A, we just need to check if the pattern is the last pattern. + if (is_last or + (pattern.syntax_hint == .Double and + component_idx + 1 == this.walker.patternComponents.items.len -| 1 and + next_pattern.?.syntax_hint != .Double and + this.walker.matchPatternImpl(next_pattern.?, entry_name))) + { + return .{ .result = try this.walker.prepareMatchedPathSymlink(symlink_full_path_z) orelse continue }; + } + } + continue; + }, + .result => |fd| brk: { + this.bumpOpenFds(); + break :brk fd; + }, + }; + + const dir_fd = maybe_dir_fd orelse { + // No directory file descriptor, it's a file + if (is_last) + return .{ .result = try this.walker.prepareMatchedPathSymlink(symlink_full_path_z) orelse continue }; + + if (pattern.syntax_hint == .Double and + component_idx + 1 == this.walker.patternComponents.items.len -| 1 and + next_pattern.?.syntax_hint != .Double and + this.walker.matchPatternImpl(next_pattern.?, entry_name)) + { + return .{ .result = try this.walker.prepareMatchedPathSymlink(symlink_full_path_z) orelse continue }; + } + + continue; + }; + + var add_dir: bool = false; + // TODO this function calls `matchPatternImpl(pattern, + // entry_name)` which is redundant because we already called + // that when we first encountered the symlink + const recursion_idx_bump_ = this.walker.matchPatternDir(&pattern, next_pattern, entry_name, component_idx, is_last, &add_dir); + + if (recursion_idx_bump_) |recursion_idx_bump| { + if (recursion_idx_bump == 2) { + try this.walker.workbuf.append( + this.walker.arena.allocator(), + WorkItem.newWithFd(work_item.path, component_idx + recursion_idx_bump, .directory, dir_fd), + ); + try this.walker.workbuf.append( + this.walker.arena.allocator(), + WorkItem.newWithFd(work_item.path, component_idx, .directory, dir_fd), + ); + } else { + try this.walker.workbuf.append( + this.walker.arena.allocator(), + WorkItem.newWithFd(work_item.path, component_idx + recursion_idx_bump, .directory, dir_fd), + ); + } + } + + if (add_dir and !this.walker.only_files) { + return .{ .result = try this.walker.prepareMatchedPathSymlink(symlink_full_path_z) orelse continue }; + } + + continue; + }, + } + }, + .directory => |*dir| { + const entry = switch (dir.iter.next()) { + .err => |err| { + if (!dir.at_cwd) this.closeDisallowingCwd(dir.fd); + dir.iter_closed = true; + return .{ .err = this.walker.handleSysErrWithPath(err, dir.dir_path) }; + }, + .result => |ent| ent, + } orelse { + if (!dir.at_cwd) this.closeDisallowingCwd(dir.fd); + dir.iter_closed = true; + this.iter_state = .get_next; + continue; + }; + log("dir: {s} entry: {s}", .{ dir.dir_path, entry.name.slice() }); + + const dir_iter_state: *const IterState.Directory = &this.iter_state.directory; + + const entry_name = entry.name.slice(); + switch (entry.kind) { + .file => { + const matches = this.walker.matchPatternFile(entry_name, dir_iter_state.component_idx, dir.is_last, dir_iter_state.pattern, dir_iter_state.next_pattern); + if (matches) { + const prepared = try this.walker.prepareMatchedPath(entry_name, dir.dir_path) orelse continue; + return .{ .result = prepared }; + } + continue; + }, + .directory => { + var add_dir: bool = false; + const recursion_idx_bump_ = this.walker.matchPatternDir(dir_iter_state.pattern, dir_iter_state.next_pattern, entry_name, dir_iter_state.component_idx, dir_iter_state.is_last, &add_dir); + + if (recursion_idx_bump_) |recursion_idx_bump| { + const subdir_parts: []const []const u8 = &[_][]const u8{ + dir.dir_path[0..dir.dir_path.len], + entry_name, + }; + + const subdir_entry_name = try this.walker.join(subdir_parts); + + if (recursion_idx_bump == 2) { + try this.walker.workbuf.append( + this.walker.arena.allocator(), + WorkItem.new(subdir_entry_name, dir_iter_state.component_idx + recursion_idx_bump, .directory), + ); + try this.walker.workbuf.append( + this.walker.arena.allocator(), + WorkItem.new(subdir_entry_name, dir_iter_state.component_idx, .directory), + ); + } else { + try this.walker.workbuf.append( + this.walker.arena.allocator(), + WorkItem.new(subdir_entry_name, dir_iter_state.component_idx + recursion_idx_bump, .directory), + ); + } + } + + if (add_dir and !this.walker.only_files) { + const prepared_path = try this.walker.prepareMatchedPath(entry_name, dir.dir_path) orelse continue; + return .{ .result = prepared_path }; + } + + continue; + }, + .sym_link => { + if (this.walker.follow_symlinks) { + // Following a symlink requires additional syscalls, so + // we first try it against our "catch-all" pattern match + // function + const matches = this.walker.matchPatternImpl(dir_iter_state.pattern, entry_name); + if (!matches) continue; + + const subdir_parts: []const []const u8 = &[_][]const u8{ + dir.dir_path[0..dir.dir_path.len], + entry_name, + }; + const entry_start: u32 = @intCast(if (dir.dir_path.len == 0) 0 else dir.dir_path.len + 1); + + // const subdir_entry_name = try this.arena.allocator().dupe(u8, ResolvePath.join(subdir_parts, .auto)); + const subdir_entry_name = try this.walker.join(subdir_parts); + + try this.walker.workbuf.append( + this.walker.arena.allocator(), + WorkItem.newSymlink(subdir_entry_name, dir_iter_state.component_idx, entry_start), + ); + + continue; + } + + if (this.walker.only_files) continue; + + const matches = this.walker.matchPatternFile(entry_name, dir_iter_state.component_idx, dir_iter_state.is_last, dir_iter_state.pattern, dir_iter_state.next_pattern); + if (matches) { + const prepared_path = try this.walker.prepareMatchedPath(entry_name, dir.dir_path) orelse continue; + return .{ .result = prepared_path }; + } + + continue; + }, + else => continue, + } + }, + } + } + } + }; + + const WorkItem = struct { + path: []const u8, + idx: u32, + kind: Kind, + entry_start: u32 = 0, + fd: ?Accessor.Handle = null, + + const Kind = enum { + directory, + symlink, + }; + + fn new(path: []const u8, idx: u32, kind: Kind) WorkItem { + return .{ + .path = path, + .idx = idx, + .kind = kind, + }; + } + + fn newWithFd(path: []const u8, idx: u32, kind: Kind, fd: Accessor.Handle) WorkItem { + return .{ + .path = path, + .idx = idx, + .kind = kind, + .fd = fd, + }; + } + + fn newSymlink(path: []const u8, idx: u32, entry_start: u32) WorkItem { + return .{ + .path = path, + .idx = idx, + .kind = .symlink, + .entry_start = entry_start, + }; + } + }; + + /// A component is each part of a glob pattern, separated by directory + /// separator: + /// `src/**/*.ts` -> `src`, `**`, `*.ts` + const Component = struct { + start: u32, + len: u32, + + syntax_hint: SyntaxHint = .None, + trailing_sep: bool = false, + is_ascii: bool = false, + + /// Only used when component is not ascii + unicode_set: bool = false, + start_cp: u32 = 0, + end_cp: u32 = 0, + + pub fn patternSlice(this: *const Component, pattern: []const u8) []const u8 { + return pattern[this.start .. this.start + this.len - @as(u1, @bitCast(this.trailing_sep))]; + } + + pub fn patternSliceCp(this: *const Component, pattern: []u32) []u32 { + return pattern[this.start_cp .. this.end_cp - @as(u1, @bitCast(this.trailing_sep))]; + } + + const SyntaxHint = enum { + None, + Single, + Double, + /// Uses special fast-path matching for components like: `*.ts` + WildcardFilepath, + /// Uses special fast-patch matching for literal components e.g. + /// "node_modules", becomes memcmp + Literal, + /// ./fixtures/*.ts + /// ^ + Dot, + /// ../ + DotBack, + + fn isSpecialSyntax(this: SyntaxHint) bool { + return switch (this) { + .Literal => false, + else => true, + }; + } + }; + }; + + /// The arena parameter is dereferenced and copied if all allocations go well and nothing goes wrong + pub fn init( + this: *GlobWalker, + arena: *Arena, + pattern: []const u8, + dot: bool, + absolute: bool, + follow_symlinks: bool, + error_on_broken_symlinks: bool, + only_files: bool, + ) !Maybe(void) { + return try this.initWithCwd( + arena, + pattern, + bun.fs.FileSystem.instance.top_level_dir, + dot, + absolute, + follow_symlinks, + error_on_broken_symlinks, + only_files, + ); + } + + pub fn convertUtf8ToCodepoints(codepoints: []u32, pattern: []const u8) void { + _ = bun.simdutf.convert.utf8.to.utf32.le(pattern, codepoints); + } + + pub fn debugPatternComopnents(this: *GlobWalker) void { + const pattern = this.pattern; + const components = &this.patternComponents; + const ptr = @intFromPtr(this); + log("GlobWalker(0x{x}) components:", .{ptr}); + for (components.items) |cmp| { + switch (cmp.syntax_hint) { + .Single => log(" *", .{}), + .Double => log(" **", .{}), + .Dot => log(" .", .{}), + .DotBack => log(" ../", .{}), + .Literal, .WildcardFilepath, .None => log(" hint={s} component_str={s}", .{ @tagName(cmp.syntax_hint), cmp.patternSlice(pattern) }), + } + } + } + + /// `cwd` should be allocated with the arena + /// The arena parameter is dereferenced and copied if all allocations go well and nothing goes wrong + pub fn initWithCwd( + this: *GlobWalker, + arena: *Arena, + pattern: []const u8, + cwd: []const u8, + dot: bool, + absolute: bool, + follow_symlinks: bool, + error_on_broken_symlinks: bool, + only_files: bool, + ) !Maybe(void) { + log("initWithCwd(cwd={s})", .{cwd}); + this.* = .{ + .cwd = cwd, + .pattern = pattern, + .dot = dot, + .absolute = absolute, + .follow_symlinks = follow_symlinks, + .error_on_broken_symlinks = error_on_broken_symlinks, + .only_files = only_files, + .basename_excluding_special_syntax_component_idx = 0, + .end_byte_of_basename_excluding_special_syntax = 0, + }; + + try GlobWalker.buildPatternComponents( + arena, + &this.patternComponents, + pattern, + &this.cp_len, + &this.pattern_codepoints, + &this.has_relative_components, + &this.end_byte_of_basename_excluding_special_syntax, + &this.basename_excluding_special_syntax_component_idx, + ); + + // copy arena after all allocations are successful + this.arena = arena.*; + + if (bun.Environment.allow_assert) { + this.debugPatternComopnents(); + } + + return Maybe(void).success; + } + + /// NOTE This also calls deinit on the arena, if you don't want to do that then + pub fn deinit(this: *GlobWalker, comptime clear_arena: bool) void { + log("GlobWalker.deinit", .{}); + if (comptime clear_arena) { + this.arena.deinit(); + } + } + + pub fn handleSysErrWithPath( + this: *GlobWalker, + err: Syscall.Error, + path_buf: [:0]const u8, + ) Syscall.Error { + std.mem.copyForwards(u8, this.pathBuf[0 .. path_buf.len + 1], @as([]const u8, @ptrCast(path_buf[0 .. path_buf.len + 1]))); + return err.withPath(this.pathBuf[0 .. path_buf.len + 1]); + } + + pub fn walk(this: *GlobWalker) !Maybe(void) { + if (this.patternComponents.items.len == 0) return Maybe(void).success; + + var iter = GlobWalker.Iterator{ .walker = this }; + defer iter.deinit(); + switch (try iter.init()) { + .err => |err| return .{ .err = err }, + else => {}, + } + + while (switch (try iter.next()) { + .err => |err| return .{ .err = err }, + .result => |matched_path| matched_path, + }) |path| { + log("walker: matched path: {s}", .{path}); + // The paths are already put into this.matchedPaths, which we use for the output, + // so we don't need to do anything here + } + + return Maybe(void).success; + } + + // NOTE you must check that the pattern at `idx` has `syntax_hint == .Dot` or + // `syntax_hint == .DotBack` first + fn collapseDots( + this: *GlobWalker, + idx: u32, + dir_path: *[:0]u8, + path_buf: *bun.PathBuffer, + encountered_dot_dot: *bool, + ) u32 { + var component_idx = idx; + var len = dir_path.len; + while (component_idx < this.patternComponents.items.len) { + switch (this.patternComponents.items[component_idx].syntax_hint) { + .Dot => { + defer component_idx += 1; + if (len + 2 >= bun.MAX_PATH_BYTES) @panic("Invalid path"); + if (len == 0) { + path_buf[len] = '.'; + path_buf[len + 1] = 0; + len += 1; + } else { + path_buf[len] = '/'; + path_buf[len + 1] = '.'; + path_buf[len + 2] = 0; + len += 2; + } + }, + .DotBack => { + defer component_idx += 1; + encountered_dot_dot.* = true; + if (dir_path.len + 3 >= bun.MAX_PATH_BYTES) @panic("Invalid path"); + if (len == 0) { + path_buf[len] = '.'; + path_buf[len + 1] = '.'; + path_buf[len + 2] = 0; + len += 2; + } else { + path_buf[len] = '/'; + path_buf[len + 1] = '.'; + path_buf[len + 2] = '.'; + path_buf[len + 3] = 0; + len += 3; + } + }, + else => break, + } + } + + dir_path.len = len; + + return component_idx; + } + + // NOTE you must check that the pattern at `idx` has `syntax_hint == .Double` first + fn collapseSuccessiveDoubleWildcards(this: *GlobWalker, idx: u32) u32 { + var component_idx = idx; + const pattern = this.patternComponents.items[idx]; + _ = pattern; + // Collapse successive double wildcards + while (component_idx + 1 < this.patternComponents.items.len and + this.patternComponents.items[component_idx + 1].syntax_hint == .Double) : (component_idx += 1) + {} + return component_idx; + } + + pub fn skipSpecialComponents( + this: *GlobWalker, + work_item_idx: u32, + dir_path: *[:0]u8, + scratch_path_buf: *bun.PathBuffer, + encountered_dot_dot: *bool, + ) u32 { + var component_idx = work_item_idx; + + // Skip `.` and `..` while also appending them to `dir_path` + component_idx = switch (this.patternComponents.items[component_idx].syntax_hint) { + .Dot => this.collapseDots( + component_idx, + dir_path, + scratch_path_buf, + encountered_dot_dot, + ), + .DotBack => this.collapseDots( + component_idx, + dir_path, + scratch_path_buf, + encountered_dot_dot, + ), + else => component_idx, + }; + + // Skip to the last `**` if there is a chain of them + component_idx = switch (this.patternComponents.items[component_idx].syntax_hint) { + .Double => this.collapseSuccessiveDoubleWildcards(component_idx), + else => component_idx, + }; + + return component_idx; + } + + fn matchPatternDir( + this: *GlobWalker, + pattern: *Component, + next_pattern: ?*Component, + entry_name: []const u8, + component_idx: u32, + is_last: bool, + add: *bool, + ) ?u32 { + if (!this.dot and GlobWalker.startsWithDot(entry_name)) return null; + if (is_ignored(entry_name)) return null; + + // Handle double wildcard `**`, this could possibly + // propagate the `**` to the directory's children + if (pattern.syntax_hint == .Double) { + // Stop the double wildcard if it matches the pattern afer it + // Example: src/**/*.js + // - Matches: src/bun.js/ + // src/bun.js/foo/bar/baz.js + if (!is_last and this.matchPatternImpl(next_pattern.?, entry_name)) { + // But if the next pattern is the last + // component, it should match and propagate the + // double wildcard recursion to the directory's + // children + if (component_idx + 1 == this.patternComponents.items.len - 1) { + add.* = true; + return 0; + } + + // In the normal case skip over the next pattern + // since we matched it, example: + // BEFORE: src/**/node_modules/**/*.js + // ^ + // AFTER: src/**/node_modules/**/*.js + // ^ + return 2; + } + + if (is_last) { + add.* = true; + } + + return 0; + } + + const matches = this.matchPatternImpl(pattern, entry_name); + if (matches) { + if (is_last) { + add.* = true; + return null; + } + return 1; + } + + return null; + } + + /// A file can only match if: + /// a) it matches against the last pattern, or + /// b) it matches the next pattern, provided the current + /// pattern is a double wildcard and the next pattern is + /// not a double wildcard + /// + /// Examples: + /// a -> `src/foo/index.ts` matches + /// b -> `src/**/*.ts` (on 2nd pattern) matches + fn matchPatternFile( + this: *GlobWalker, + entry_name: []const u8, + component_idx: u32, + is_last: bool, + pattern: *Component, + next_pattern: ?*Component, + ) bool { + if (pattern.trailing_sep) return false; + + // Handle case b) + if (!is_last) return pattern.syntax_hint == .Double and + component_idx + 1 == this.patternComponents.items.len -| 1 and + next_pattern.?.syntax_hint != .Double and + this.matchPatternImpl(next_pattern.?, entry_name); + + // Handle case a) + return this.matchPatternImpl(pattern, entry_name); + } + + fn matchPatternImpl( + this: *GlobWalker, + pattern_component: *Component, + filepath: []const u8, + ) bool { + log("matchPatternImpl: {s}", .{filepath}); + if (!this.dot and GlobWalker.startsWithDot(filepath)) return false; + if (is_ignored(filepath)) return false; + + return switch (pattern_component.syntax_hint) { + .Double, .Single => true, + .WildcardFilepath => if (comptime !isWindows) + matchWildcardFilepath(pattern_component.patternSlice(this.pattern), filepath) + else + this.matchPatternSlow(pattern_component, filepath), + .Literal => if (comptime !isWindows) + matchWildcardLiteral(pattern_component.patternSlice(this.pattern), filepath) + else + this.matchPatternSlow(pattern_component, filepath), + else => this.matchPatternSlow(pattern_component, filepath), + }; + } + + fn matchPatternSlow(this: *GlobWalker, pattern_component: *Component, filepath: []const u8) bool { + // windows filepaths are utf-16 so GlobAscii.match will never work + if (comptime !isWindows) { + if (pattern_component.is_ascii and isAllAscii(filepath)) + return GlobAscii.match( + pattern_component.patternSlice(this.pattern), + filepath, + ); + } + const codepoints = this.componentStringUnicode(pattern_component); + return matchImpl( + codepoints, + filepath, + ).matches(); + } + + fn componentStringUnicode(this: *GlobWalker, pattern_component: *Component) []const u32 { + if (comptime isWindows) { + return this.componentStringUnicodeWindows(pattern_component); + } else { + return this.componentStringUnicodePosix(pattern_component); + } + } + + fn componentStringUnicodeWindows(this: *GlobWalker, pattern_component: *Component) []const u32 { + return pattern_component.patternSliceCp(this.pattern_codepoints); + } + + fn componentStringUnicodePosix(this: *GlobWalker, pattern_component: *Component) []const u32 { + if (pattern_component.unicode_set) return pattern_component.patternSliceCp(this.pattern_codepoints); + + const codepoints = pattern_component.patternSliceCp(this.pattern_codepoints); + GlobWalker.convertUtf8ToCodepoints( + codepoints, + pattern_component.patternSlice(this.pattern), + ); + pattern_component.unicode_set = true; + return codepoints; + } + + inline fn matchedPathToBunString(matched_path: MatchedPath) BunString { + if (comptime sentinel) { + return BunString.fromBytes(matched_path[0 .. matched_path.len + 1]); + } + return BunString.fromBytes(matched_path); + } + + fn prepareMatchedPathSymlink(this: *GlobWalker, symlink_full_path: []const u8) !?MatchedPath { + const result = try this.matchedPaths.getOrPut(this.arena.allocator(), BunString.fromBytes(symlink_full_path)); + if (result.found_existing) { + log("(dupe) prepared match: {s}", .{symlink_full_path}); + return null; + } + if (comptime !sentinel) { + const slice = try this.arena.allocator().dupe(u8, symlink_full_path); + result.key_ptr.* = matchedPathToBunString(slice); + return slice; + } + const slicez = try this.arena.allocator().dupeZ(u8, symlink_full_path); + result.key_ptr.* = matchedPathToBunString(slicez); + return slicez; + } + + fn prepareMatchedPath(this: *GlobWalker, entry_name: []const u8, dir_name: []const u8) !?MatchedPath { + const subdir_parts: []const []const u8 = &[_][]const u8{ + dir_name[0..dir_name.len], + entry_name, + }; + const name_matched_path = try this.join(subdir_parts); + const name = matchedPathToBunString(name_matched_path); + const result = try this.matchedPaths.getOrPutValue(this.arena.allocator(), name, {}); + if (result.found_existing) { + log("(dupe) prepared match: {s}", .{name_matched_path}); + this.arena.allocator().free(name_matched_path); + return null; + } + result.key_ptr.* = name; + // if (comptime sentinel) return name[0 .. name.len - 1 :0]; + log("prepared match: {s}", .{name_matched_path}); + return name_matched_path; + } + + fn appendMatchedPath( + this: *GlobWalker, + entry_name: []const u8, + dir_name: [:0]const u8, + ) !void { + const subdir_parts: []const []const u8 = &[_][]const u8{ + dir_name[0..dir_name.len], + entry_name, + }; + const name_matched_path = try this.join(subdir_parts); + const name = matchedPathToBunString(name_matched_path); + const result = try this.matchedPaths.getOrPut(this.arena.allocator(), name); + if (result.found_existing) { + this.arena.allocator().free(name_matched_path); + log("(dupe) prepared match: {s}", .{name_matched_path}); + return; + } + result.key_ptr.* = name; + } + + fn appendMatchedPathSymlink(this: *GlobWalker, symlink_full_path: []const u8) !void { + const name = try this.arena.allocator().dupe(u8, symlink_full_path); + try this.matchedPaths.put(this.arena.allocator(), BunString.fromBytes(name), {}); + } + + inline fn join(this: *GlobWalker, subdir_parts: []const []const u8) !MatchedPath { + if (!this.absolute) { + // If relative paths enabled, stdlib join is preferred over + // ResolvePath.joinBuf because it doesn't try to normalize the path + return try stdJoin(this.arena.allocator(), subdir_parts); + } + + const out = try this.arena.allocator().dupe(u8, bunJoin(subdir_parts, .auto)); + if (comptime sentinel) return out[0 .. out.len - 1 :0]; + + return out; + } + + inline fn startsWithDot(filepath: []const u8) bool { + return filepath.len > 0 and filepath[0] == '.'; + } + + fn checkSpecialSyntax(pattern: []const u8) bool { + if (pattern.len < 16) { + for (pattern[0..]) |c| { + switch (c) { + '*', '[', '{', '?', '!' => return true, + else => {}, + } + } + return false; + } + + const syntax_tokens = comptime [_]u8{ '*', '[', '{', '?', '!' }; + const needles: [syntax_tokens.len]@Vector(16, u8) = comptime needles: { + var needles: [syntax_tokens.len]@Vector(16, u8) = undefined; + for (syntax_tokens, 0..) |tok, i| { + needles[i] = @splat(tok); + } + break :needles needles; + }; + + var i: usize = 0; + while (i + 16 <= pattern.len) : (i += 16) { + const haystack: @Vector(16, u8) = pattern[i..][0..16].*; + inline for (needles) |needle| { + if (std.simd.firstTrue(needle == haystack) != null) return true; + } + } + + if (i < pattern.len) { + for (pattern[i..]) |c| { + inline for (syntax_tokens) |tok| { + if (c == tok) return true; + } + } + } + + return false; + } + + fn makeComponent( + pattern: []const u8, + start_cp: u32, + end_cp: u32, + start_byte: u32, + end_byte: u32, + has_relative_patterns: *bool, + ) ?Component { + var component: Component = .{ + .start = start_byte, + .len = end_byte - start_byte, + .start_cp = start_cp, + .end_cp = end_cp, + }; + if (component.len == 0) return null; + + out: { + if (component.len == 1 and pattern[component.start] == '.') { + component.syntax_hint = .Dot; + has_relative_patterns.* = true; + break :out; + } + if (component.len == 2 and pattern[component.start] == '.' and pattern[component.start] == '.') { + component.syntax_hint = .DotBack; + has_relative_patterns.* = true; + break :out; + } + + if (!GlobWalker.checkSpecialSyntax(pattern[component.start .. component.start + component.len])) { + component.syntax_hint = .Literal; + break :out; + } + + switch (component.len) { + 1 => { + if (pattern[component.start] == '*') { + component.syntax_hint = .Single; + } + break :out; + }, + 2 => { + if (pattern[component.start] == '*' and pattern[component.start + 1] == '*') { + component.syntax_hint = .Double; + break :out; + } + }, + else => {}, + } + + out_of_check_wildcard_filepath: { + if (component.len > 1 and + pattern[component.start] == '*' and + pattern[component.start + 1] == '.' and + component.start + 2 < pattern.len) + { + for (pattern[component.start + 2 ..]) |c| { + switch (c) { + // The fast path checks that path[1..] == pattern[1..], + // this will obviously not work if additional + // glob syntax is present in the pattern, so we + // must not apply this optimization if we see + // special glob syntax. + // + // This is not a complete check, there can be + // false negatives, but that's okay, it just + // means we don't apply the optimization. + // + // We also don't need to look for the `!` token, + // because that only applies negation if at the + // beginning of the string. + '[', '{', '?', '*' => break :out_of_check_wildcard_filepath, + else => {}, + } + } + component.syntax_hint = .WildcardFilepath; + break :out; + } + } + } + + if (component.syntax_hint != .Single and component.syntax_hint != .Double) { + if (isAllAscii(pattern[component.start .. component.start + component.len])) { + component.is_ascii = true; + } + } else { + component.is_ascii = true; + } + + if (pattern[component.start + component.len -| 1] == '/') { + component.trailing_sep = true; + } else if (comptime bun.Environment.isWindows) { + component.trailing_sep = pattern[component.start + component.len -| 1] == '\\'; + } + + return component; + } + + /// Build an ad-hoc glob pattern. Useful when you don't need to traverse + /// a directory. + pub fn buildPattern( + arena: *Arena, + patternComponents: *ArrayList(Component), + pattern: []const u8, + out_cp_len: ?*u32, + out_pattern_cp: *[]u32, + has_relative_patterns: *bool, + end_byte_of_basename_excluding_special_syntax: ?*u32, + basename_excluding_special_syntax_component_idx: ?*u32, + ) !void { + // in case the consumer doesn't care about some outputs. + const scratchpad: [3]u32 = .{0} ** 3; + return buildPatternComponents( + arena, + patternComponents, + pattern, + out_cp_len orelse &scratchpad[0], + out_pattern_cp, + has_relative_patterns, + end_byte_of_basename_excluding_special_syntax orelse scratchpad[1], + basename_excluding_special_syntax_component_idx orelse scratchpad[2], + ); + } + + fn buildPatternComponents( + arena: *Arena, + patternComponents: *ArrayList(Component), + pattern: []const u8, + out_cp_len: *u32, + out_pattern_cp: *[]u32, + has_relative_patterns: *bool, + end_byte_of_basename_excluding_special_syntax: *u32, + basename_excluding_special_syntax_component_idx: *u32, + ) !void { + var start_cp: u32 = 0; + var start_byte: u32 = 0; + + const iter = CodepointIterator.init(pattern); + var cursor = CodepointIterator.Cursor{}; + + var cp_len: u32 = 0; + var prevIsBackslash = false; + var saw_special = false; + while (iter.next(&cursor)) : (cp_len += 1) { + const c = cursor.c; + + switch (c) { + '\\' => { + if (comptime isWindows) { + var end_cp = cp_len; + var end_byte = cursor.i; + // is last char + if (cursor.i + cursor.width == pattern.len) { + end_cp += 1; + end_byte += cursor.width; + } + if (makeComponent( + pattern, + start_cp, + end_cp, + start_byte, + end_byte, + has_relative_patterns, + )) |component| { + saw_special = saw_special or component.syntax_hint.isSpecialSyntax(); + if (!saw_special) { + basename_excluding_special_syntax_component_idx.* = @intCast(patternComponents.items.len); + end_byte_of_basename_excluding_special_syntax.* = cursor.i + cursor.width; + } + try patternComponents.append(arena.allocator(), component); + } + start_cp = cp_len + 1; + start_byte = cursor.i + cursor.width; + continue; + } + + if (prevIsBackslash) { + prevIsBackslash = false; + continue; + } + + prevIsBackslash = true; + }, + '/' => { + var end_cp = cp_len; + var end_byte = cursor.i; + // is last char + if (cursor.i + cursor.width == pattern.len) { + end_cp += 1; + end_byte += cursor.width; + } + if (makeComponent( + pattern, + start_cp, + end_cp, + start_byte, + end_byte, + has_relative_patterns, + )) |component| { + saw_special = saw_special or component.syntax_hint.isSpecialSyntax(); + if (!saw_special) { + basename_excluding_special_syntax_component_idx.* = @intCast(patternComponents.items.len); + end_byte_of_basename_excluding_special_syntax.* = cursor.i + cursor.width; + } + try patternComponents.append(arena.allocator(), component); + } + start_cp = cp_len + 1; + start_byte = cursor.i + cursor.width; + }, + // TODO: Support other escaping glob syntax + else => {}, + } + } + + out_cp_len.* = cp_len; + + const codepoints = try arena.allocator().alloc(u32, cp_len); + // On Windows filepaths are UTF-16 so its better to fill the codepoints buffer upfront + if (comptime isWindows) { + GlobWalker.convertUtf8ToCodepoints(codepoints, pattern); + } + out_pattern_cp.* = codepoints; + + const end_cp = cp_len; + if (makeComponent( + pattern, + start_cp, + end_cp, + start_byte, + @intCast(pattern.len), + has_relative_patterns, + )) |component| { + saw_special = saw_special or component.syntax_hint.isSpecialSyntax(); + if (!saw_special) { + basename_excluding_special_syntax_component_idx.* = @intCast(patternComponents.items.len); + end_byte_of_basename_excluding_special_syntax.* = cursor.i + cursor.width; + } + try patternComponents.append(arena.allocator(), component); + } else if (!saw_special) { + basename_excluding_special_syntax_component_idx.* = @intCast(patternComponents.items.len); + end_byte_of_basename_excluding_special_syntax.* = cursor.i + cursor.width; + } + } + }; +} + +// From: https://github.com/The-King-of-Toasters/globlin +/// State for matching a glob against a string +pub const GlobState = struct { + // These store character indices into the glob and path strings. + path_index: CursorState = .{}, + glob_index: u32 = 0, + // When we hit a * or **, we store the state for backtracking. + wildcard: Wildcard = .{}, + globstar: Wildcard = .{}, + + fn init(path_iter: *const CodepointIterator) GlobState { + var this = GlobState{}; + // this.glob_index = CursorState.init(glob_iter); + this.path_index = CursorState.init(path_iter); + return this; + } + + fn skipBraces(self: *GlobState, glob: []const u32, stop_on_comma: bool) BraceState { + var braces: u32 = 1; + var in_brackets = false; + while (self.glob_index < glob.len and braces > 0) : (self.glob_index += 1) { + switch (glob[self.glob_index]) { + // Skip nested braces + '{' => if (!in_brackets) { + braces += 1; + }, + '}' => if (!in_brackets) { + braces -= 1; + }, + ',' => if (stop_on_comma and braces == 1 and !in_brackets) { + self.glob_index += 1; + return .Comma; + }, + '*', '?', '[' => |c| if (!in_brackets) { + if (c == '[') + in_brackets = true; + }, + ']' => in_brackets = false, + '\\' => self.glob_index += 1, + else => {}, + } + } + + if (braces != 0) + return .Invalid; + return .EndBrace; + } + + inline fn backtrack(self: *GlobState) void { + self.glob_index = self.wildcard.glob_index; + self.path_index = self.wildcard.path_index; + } +}; + +const Wildcard = struct { + // Using u32 rather than usize for these results in 10% faster performance. + // glob_index: CursorState = .{}, + glob_index: u32 = 0, + path_index: CursorState = .{}, +}; + +const BraceState = enum { Invalid, Comma, EndBrace }; + +const BraceStack = struct { + stack: [10]GlobState = undefined, + len: u32 = 0, + longest_brace_match: CursorState = .{}, + + inline fn push(self: *BraceStack, state: *const GlobState) GlobState { + self.stack[self.len] = state.*; + self.len += 1; + return GlobState{ + .path_index = state.path_index, + .glob_index = state.glob_index + 1, + }; + } + + inline fn pop(self: *BraceStack, state: *const GlobState) GlobState { + self.len -= 1; + const s = GlobState{ + .glob_index = state.glob_index, + .path_index = self.longest_brace_match, + // Restore star state if needed later. + .wildcard = self.stack[self.len].wildcard, + .globstar = self.stack[self.len].globstar, + }; + if (self.len == 0) + self.longest_brace_match = .{}; + return s; + } + + inline fn last(self: *const BraceStack) *const GlobState { + return &self.stack[self.len - 1]; + } +}; + +pub const MatchResult = enum { + no_match, + match, + + negate_no_match, + negate_match, + + pub fn matches(this: MatchResult) bool { + return this == .match or this == .negate_match; + } +}; + +/// This function checks returns a boolean value if the pathname `path` matches +/// the pattern `glob`. +/// +/// The supported pattern syntax for `glob` is: +/// +/// "?" +/// Matches any single character. +/// "*" +/// Matches zero or more characters, except for path separators ('/' or '\'). +/// "**" +/// Matches zero or more characters, including path separators. +/// Must match a complete path segment, i.e. followed by a path separator or +/// at the end of the pattern. +/// "[ab]" +/// Matches one of the characters contained in the brackets. +/// Character ranges (e.g. "[a-z]") are also supported. +/// Use "[!ab]" or "[^ab]" to match any character *except* those contained +/// in the brackets. +/// "{a,b}" +/// Match one of the patterns contained in the braces. +/// Any of the wildcards listed above can be used in the sub patterns. +/// Braces may be nested up to 10 levels deep. +/// "!" +/// Negates the result when at the start of the pattern. +/// Multiple "!" characters negate the pattern multiple times. +/// "\" +/// Used to escape any of the special characters above. +pub fn matchImpl(glob: []const u32, path: []const u8) MatchResult { + const path_iter = CodepointIterator.init(path); + + // This algorithm is based on https://research.swtch.com/glob + var state = GlobState.init(&path_iter); + // Store the state when we see an opening '{' brace in a stack. + // Up to 10 nested braces are supported. + var brace_stack = BraceStack{}; + + // First, check if the pattern is negated with a leading '!' character. + // Multiple negations can occur. + var negated = false; + while (state.glob_index < glob.len and glob[state.glob_index] == '!') { + negated = !negated; + state.glob_index += 1; + } + + while (state.glob_index < glob.len or state.path_index.cursor.i < path.len) { + if (state.glob_index < glob.len) { + switch (glob[state.glob_index]) { + '*' => { + const is_globstar = state.glob_index + 1 < glob.len and glob[state.glob_index + 1] == '*'; + // const is_globstar = state.glob_index.cursor.i + state.glob_index.cursor.width < glob.len and + // state.glob_index.peek(&glob_iter).cursor.c == '*'; + if (is_globstar) { + // Coalesce multiple ** segments into one. + var index = state.glob_index + 2; + state.glob_index = skipGlobstars(glob, &index) - 2; + } + + state.wildcard.glob_index = state.glob_index; + state.wildcard.path_index = state.path_index.peek(&path_iter); + + // ** allows path separators, whereas * does not. + // However, ** must be a full path component, i.e. a/**/b not a**b. + if (is_globstar) { + // Skip wildcards + state.glob_index += 2; + + if (glob.len == state.glob_index) { + // A trailing ** segment without a following separator. + state.globstar = state.wildcard; + } else if (glob[state.glob_index] == '/' and + (state.glob_index < 3 or glob[state.glob_index - 3] == '/')) + { + // Matched a full /**/ segment. If the last character in the path was a separator, + // skip the separator in the glob so we search for the next character. + // In effect, this makes the whole segment optional so that a/**/b matches a/b. + if (state.path_index.cursor.i == 0 or + (state.path_index.cursor.i < path.len and + isSeparator(path[state.path_index.cursor.i - 1]))) + { + state.glob_index += 1; + } + + // The allows_sep flag allows separator characters in ** matches. + // one is a '/', which prevents a/**/b from matching a/bb. + state.globstar = state.wildcard; + } + } else { + state.glob_index += 1; + } + + // If we are in a * segment and hit a separator, + // either jump back to a previous ** or end the wildcard. + if (state.globstar.path_index.cursor.i != state.wildcard.path_index.cursor.i and + state.path_index.cursor.i < path.len and + isSeparator(state.path_index.cursor.c)) + { + // Special case: don't jump back for a / at the end of the glob. + if (state.globstar.path_index.cursor.i > 0 and state.path_index.cursor.i + state.path_index.cursor.width < path.len) { + state.glob_index = state.globstar.glob_index; + state.wildcard.glob_index = state.globstar.glob_index; + } else { + state.wildcard.path_index.cursor.i = 0; + } + } + + // If the next char is a special brace separator, + // skip to the end of the braces so we don't try to match it. + if (brace_stack.len > 0 and + state.glob_index < glob.len and + (glob[state.glob_index] == ',' or glob[state.glob_index] == '}')) + { + if (state.skipBraces(glob, false) == .Invalid) + return .no_match; // invalid pattern! + } + + continue; + }, + '?' => if (state.path_index.cursor.i < path.len) { + if (!isSeparator(state.path_index.cursor.c)) { + state.glob_index += 1; + state.path_index.bump(&path_iter); + continue; + } + }, + '[' => if (state.path_index.cursor.i < path.len) { + state.glob_index += 1; + const c = state.path_index.cursor.c; + + // Check if the character class is negated. + var class_negated = false; + if (state.glob_index < glob.len and + (glob[state.glob_index] == '^' or glob[state.glob_index] == '!')) + { + class_negated = true; + state.glob_index += 1; + } + + // Try each range. + var first = true; + var is_match = false; + while (state.glob_index < glob.len and (first or glob[state.glob_index] != ']')) { + var low = glob[state.glob_index]; + if (!unescape(&low, glob, &state.glob_index)) + return .no_match; // Invalid pattern + state.glob_index += 1; + + // If there is a - and the following character is not ], + // read the range end character. + const high = if (state.glob_index + 1 < glob.len and + glob[state.glob_index] == '-' and glob[state.glob_index + 1] != ']') + blk: { + state.glob_index += 1; + var h = glob[state.glob_index]; + if (!unescape(&h, glob, &state.glob_index)) + return .no_match; // Invalid pattern! + state.glob_index += 1; + break :blk h; + } else low; + + if (low <= c and c <= high) + is_match = true; + first = false; + } + if (state.glob_index >= glob.len) + return .no_match; // Invalid pattern! + state.glob_index += 1; + if (is_match != class_negated) { + state.path_index.bump(&path_iter); + continue; + } + }, + '{' => if (state.path_index.cursor.i < path.len) { + if (brace_stack.len >= brace_stack.stack.len) + return .no_match; // Invalid pattern! Too many nested braces. + + // Push old state to the stack, and reset current state. + state = brace_stack.push(&state); + continue; + }, + '}' => if (brace_stack.len > 0) { + // If we hit the end of the braces, we matched the last option. + brace_stack.longest_brace_match = if (state.path_index.cursor.i >= brace_stack.longest_brace_match.cursor.i) + state.path_index + else + brace_stack.longest_brace_match; + state.glob_index += 1; + state = brace_stack.pop(&state); + continue; + }, + ',' => if (brace_stack.len > 0) { + // If we hit a comma, we matched one of the options! + // But we still need to check the others in case there is a longer match. + brace_stack.longest_brace_match = if (state.path_index.cursor.i >= brace_stack.longest_brace_match.cursor.i) + state.path_index + else + brace_stack.longest_brace_match; + state.path_index = brace_stack.last().path_index; + state.glob_index += 1; + state.wildcard = Wildcard{}; + state.globstar = Wildcard{}; + continue; + }, + else => |c| if (state.path_index.cursor.i < path.len) { + var cc = c; + // Match escaped characters as literals. + if (!unescape(&cc, glob, &state.glob_index)) + return .no_match; // Invalid pattern; + + const is_match = if (cc == '/') + isSeparator(state.path_index.cursor.c) + else + state.path_index.cursor.c == cc; + + if (is_match) { + if (brace_stack.len > 0 and + state.glob_index > 0 and + glob[state.glob_index - 1] == '}') + { + brace_stack.longest_brace_match = state.path_index; + state = brace_stack.pop(&state); + } + state.glob_index += 1; + state.path_index.bump(&path_iter); + + // If this is not a separator, lock in the previous globstar. + if (cc != '/') + state.globstar.path_index.cursor.i = 0; + + continue; + } + }, + } + } + // If we didn't match, restore state to the previous star pattern. + if (state.wildcard.path_index.cursor.i > 0 and state.wildcard.path_index.cursor.i <= path.len) { + state.backtrack(); + continue; + } + + if (brace_stack.len > 0) { + // If in braces, find next option and reset path to index where we saw the '{' + switch (state.skipBraces(glob, true)) { + .Invalid => return .no_match, + .Comma => { + state.path_index = brace_stack.last().path_index; + continue; + }, + .EndBrace => {}, + } + + // Hit the end. Pop the stack. + // If we matched a previous option, use that. + if (brace_stack.longest_brace_match.cursor.i > 0) { + state = brace_stack.pop(&state); + continue; + } else { + // Didn't match. Restore state, and check if we need to jump back to a star pattern. + state = brace_stack.last().*; + brace_stack.len -= 1; + if (state.wildcard.path_index.cursor.i > 0 and state.wildcard.path_index.cursor.i <= path.len) { + state.backtrack(); + continue; + } + } + } + + return if (negated) .negate_match else .no_match; + } + + return if (!negated) .match else .negate_no_match; +} + +pub inline fn isSeparator(c: Codepoint) bool { + if (comptime @import("builtin").os.tag == .windows) return c == '/' or c == '\\'; + return c == '/'; +} + +inline fn unescape(c: *u32, glob: []const u32, glob_index: *u32) bool { + if (c.* == '\\') { + glob_index.* += 1; + if (glob_index.* >= glob.len) + return false; // Invalid pattern! + + c.* = switch (glob[glob_index.*]) { + 'a' => '\x61', + 'b' => '\x08', + 'n' => '\n', + 'r' => '\r', + 't' => '\t', + else => |cc| cc, + }; + } + + return true; +} + +const GLOB_STAR_MATCH_STR: []const u32 = &[_]u32{ '/', '*', '*' }; +// src/**/**/foo.ts +inline fn skipGlobstars(glob: []const u32, glob_index: *u32) u32 { + // Coalesce multiple ** segments into one. + while (glob_index.* + 3 <= glob.len and + // std.mem.eql(u8, glob[glob_index.*..][0..3], "/**")) + std.mem.eql(u32, glob[glob_index.*..][0..3], GLOB_STAR_MATCH_STR)) + { + glob_index.* += 3; + } + + return glob_index.*; +} + +const MatchAscii = struct {}; + +pub fn matchWildcardFilepath(glob: []const u8, path: []const u8) bool { + const needle = glob[1..]; + const needle_len: u32 = @intCast(needle.len); + if (path.len < needle_len) return false; + return std.mem.eql(u8, needle, path[path.len - needle_len ..]); +} + +pub fn matchWildcardLiteral(literal: []const u8, path: []const u8) bool { + return std.mem.eql(u8, literal, path); +} diff --git a/src/glob_ascii.zig b/src/glob/ascii.zig similarity index 93% rename from src/glob_ascii.zig rename to src/glob/ascii.zig index 38914eface..69413f9505 100644 --- a/src/glob_ascii.zig +++ b/src/glob/ascii.zig @@ -480,3 +480,36 @@ inline fn skipGlobstars(glob: []const u8, glob_index: *usize) usize { return glob_index.*; } + +/// Returns true if the given string contains glob syntax, +/// excluding those escaped with backslashes +/// TODO: this doesn't play nicely with Windows directory separator and +/// backslashing, should we just require the user to supply posix filepaths? +pub fn detectGlobSyntax(potential_pattern: []const u8) bool { + // Negation only allowed in the beginning of the pattern + if (potential_pattern.len > 0 and potential_pattern[0] == '!') return true; + + // In descending order of how popular the token is + const SPECIAL_SYNTAX: [4]u8 = comptime [_]u8{ '*', '{', '[', '?' }; + + inline for (SPECIAL_SYNTAX) |token| { + var slice = potential_pattern[0..]; + while (slice.len > 0) { + if (std.mem.indexOfScalar(u8, slice, token)) |idx| { + // Check for even number of backslashes preceding the + // token to know that it's not escaped + var i = idx; + var backslash_count: u16 = 0; + + while (i > 0 and potential_pattern[i - 1] == '\\') : (i -= 1) { + backslash_count += 1; + } + + if (backslash_count % 2 == 0) return true; + slice = slice[idx + 1 ..]; + } else break; + } + } + + return false; +} diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 515cc803ad..9f64fe8207 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -7,6 +7,7 @@ const Output = bun.Output; const Global = bun.Global; const Environment = bun.Environment; const strings = bun.strings; +const Glob = bun.glob; const MutableString = bun.MutableString; const stringZ = bun.stringZ; const default_allocator = bun.default_allocator; @@ -126,7 +127,7 @@ fn ignoredWorkspacePaths(path: []const u8) bool { return false; } -const GlobWalker = bun.glob.GlobWalker_(ignoredWorkspacePaths, bun.glob.SyscallAccessor, false); +const GlobWalker = Glob.GlobWalker(ignoredWorkspacePaths, Glob.walk.SyscallAccessor, false); // Serialized data /// The version of the lockfile format, intended to prevent data corruption for format changes. @@ -4822,7 +4823,7 @@ pub const Package = extern struct { if (input_path.len == 0 or input_path.len == 1 and input_path[0] == '.') continue; - if (bun.glob.detectGlobSyntax(input_path)) { + if (Glob.Ascii.detectGlobSyntax(input_path)) { workspace_globs.append(input_path) catch bun.outOfMemory(); continue; } diff --git a/src/shell/interpreter.zig b/src/shell/interpreter.zig index 38b8976520..7fb55877d0 100644 --- a/src/shell/interpreter.zig +++ b/src/shell/interpreter.zig @@ -50,7 +50,7 @@ const ShellError = shell.ShellError; const ast = shell.AST; const SmolList = shell.SmolList; -const GlobWalker = Glob.GlobWalker_(null, Glob.SyscallAccessor, true); +const GlobWalker = Glob.BunGlobWalkerZ; const stdin_no = 0; const stdout_no = 1; From 3c37b7f806edcc81499172eaa3a580de6946748a Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Fri, 20 Dec 2024 20:57:42 -0800 Subject: [PATCH 080/125] fix(lexer): do not treat '#bun' in a url as a pragma (#15912) Co-authored-by: Don Isaac Co-authored-by: DonIsaac --- src/js_lexer.zig | 23 +----- src/js_parser.zig | 76 ++++++++++++++++--- test/bundler/transpiler/bun-pragma.test.ts | 45 +++++++++++ .../fail/bun-pragma-before-hashbang.ts | 5 ++ .../bun-pragma/fail/ts-with-pragma.ts | 2 + .../fixtures/bun-pragma/pass/bun-in-url.ts | 5 ++ .../fixtures/bun-pragma/pass/not-a-pragma.ts | 2 + .../bun-pragma/pass/pragma-only-no-newline.ts | 1 + .../pass/pragma-only-with-newline.ts | 2 + .../pass/valid-pragma-without-bun-prefix.ts | 5 ++ 10 files changed, 134 insertions(+), 32 deletions(-) create mode 100644 test/bundler/transpiler/bun-pragma.test.ts create mode 100644 test/bundler/transpiler/fixtures/bun-pragma/fail/bun-pragma-before-hashbang.ts create mode 100644 test/bundler/transpiler/fixtures/bun-pragma/fail/ts-with-pragma.ts create mode 100644 test/bundler/transpiler/fixtures/bun-pragma/pass/bun-in-url.ts create mode 100644 test/bundler/transpiler/fixtures/bun-pragma/pass/not-a-pragma.ts create mode 100644 test/bundler/transpiler/fixtures/bun-pragma/pass/pragma-only-no-newline.ts create mode 100644 test/bundler/transpiler/fixtures/bun-pragma/pass/pragma-only-with-newline.ts create mode 100644 test/bundler/transpiler/fixtures/bun-pragma/pass/valid-pragma-without-bun-prefix.ts diff --git a/src/js_lexer.zig b/src/js_lexer.zig index ca946482f3..de7cfc2283 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -153,13 +153,6 @@ fn NewLexer_( code_point: CodePoint = -1, identifier: []const u8 = "", jsx_pragma: JSXPragma = .{}, - bun_pragma: enum { - none, - bun, - bun_cjs, - bytecode, - bytecode_cjs, - } = .none, source_mapping_url: ?js_ast.Span = null, number: f64 = 0.0, rescan_close_brace_as_template_token: bool = false, @@ -1957,9 +1950,7 @@ fn NewLexer_( // } } - if (lexer.bun_pragma == .none and strings.hasPrefixWithWordBoundary(chunk, "bun")) { - lexer.bun_pragma = .bun; - } else if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { + if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { if (PragmaArg.scan(.skip_space_first, lexer.start + i + 1, "jsx", chunk)) |span| { lexer.jsx_pragma._jsx = span; } @@ -1979,10 +1970,6 @@ fn NewLexer_( if (PragmaArg.scan(.no_space_first, lexer.start + i + 1, " sourceMappingURL=", chunk)) |span| { lexer.source_mapping_url = span; } - } else if ((lexer.bun_pragma == .bun or lexer.bun_pragma == .bun_cjs) and strings.hasPrefixWithWordBoundary(chunk, "bytecode")) { - lexer.bun_pragma = if (lexer.bun_pragma == .bun) .bytecode else .bytecode_cjs; - } else if ((lexer.bun_pragma == .bytecode or lexer.bun_pragma == .bun) and strings.hasPrefixWithWordBoundary(chunk, "bun-cjs")) { - lexer.bun_pragma = if (lexer.bun_pragma == .bytecode) .bytecode_cjs else .bun_cjs; } }, else => {}, @@ -2012,9 +1999,7 @@ fn NewLexer_( } } - if (lexer.bun_pragma == .none and strings.hasPrefixWithWordBoundary(chunk, "bun")) { - lexer.bun_pragma = .bun; - } else if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { + if (strings.hasPrefixWithWordBoundary(chunk, "jsx")) { if (PragmaArg.scan(.skip_space_first, lexer.start + i + 1, "jsx", chunk)) |span| { lexer.jsx_pragma._jsx = span; } @@ -2034,10 +2019,6 @@ fn NewLexer_( if (PragmaArg.scan(.no_space_first, lexer.start + i + 1, " sourceMappingURL=", chunk)) |span| { lexer.source_mapping_url = span; } - } else if ((lexer.bun_pragma == .bun or lexer.bun_pragma == .bun_cjs) and strings.hasPrefixWithWordBoundary(chunk, "bytecode")) { - lexer.bun_pragma = if (lexer.bun_pragma == .bun) .bytecode else .bytecode_cjs; - } else if ((lexer.bun_pragma == .bytecode or lexer.bun_pragma == .bun) and strings.hasPrefixWithWordBoundary(chunk, "bun-cjs")) { - lexer.bun_pragma = if (lexer.bun_pragma == .bytecode) .bytecode_cjs else .bun_cjs; } }, else => {}, diff --git a/src/js_parser.zig b/src/js_parser.zig index 43c7e3f33c..d225194424 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -3,6 +3,7 @@ /// ** you must also increment the `expected_version` in RuntimeTranspilerCache.zig ** /// ** IMPORTANT ** pub const std = @import("std"); +const bun = @import("root").bun; pub const logger = bun.logger; pub const js_lexer = bun.js_lexer; pub const importRecord = @import("./import_record.zig"); @@ -15,7 +16,6 @@ pub const RuntimeImports = _runtime.Runtime.Imports; pub const RuntimeFeatures = _runtime.Runtime.Features; pub const RuntimeNames = _runtime.Runtime.Names; pub const fs = @import("./fs.zig"); -const bun = @import("root").bun; const string = bun.string; const Output = bun.Output; const Global = bun.Global; @@ -3226,16 +3226,12 @@ pub const Parser = struct { } // Detect a leading "// @bun" pragma - if (p.lexer.bun_pragma != .none and p.options.features.dont_bundle_twice) { - return js_ast.Result{ - .already_bundled = switch (p.lexer.bun_pragma) { - .bun => .bun, - .bytecode => .bytecode, - .bytecode_cjs => .bytecode_cjs, - .bun_cjs => .bun_cjs, - else => unreachable, - }, - }; + if (self.options.features.dont_bundle_twice) { + if (self.hasBunPragma(hashbang.len > 0)) |pragma| { + return js_ast.Result{ + .already_bundled = pragma, + }; + } } // We must check the cache only after we've consumed the hashbang and leading // @bun pragma @@ -4262,6 +4258,64 @@ pub const Parser = struct { .log = log, }; } + + const PragmaState = packed struct { seen_cjs: bool = false, seen_bytecode: bool = false }; + + fn hasBunPragma(self: *const Parser, has_hashbang: bool) ?js_ast.Result.AlreadyBundled { + const BUN_PRAGMA = "// @bun"; + const contents = self.lexer.source.contents; + const end = contents.len; + + // pragmas may appear after a hashbang comment + // + // ```js + // #!/usr/bin/env bun + // // @bun + // const myCode = 1; + // ``` + var cursor: usize = 0; + if (has_hashbang) { + while (contents[cursor] != '\n') { + cursor += 1; + if (cursor >= end) return null; + } + + // eat the last newline + // NOTE: in windows, \n comes after \r so no extra work needs to be done + cursor += 1; + } + + if (!bun.strings.startsWith(contents[cursor..], BUN_PRAGMA)) return null; + cursor += BUN_PRAGMA.len; + + var state: PragmaState = .{}; + + while (cursor < self.lexer.end) : (cursor += 1) { + switch (contents[cursor]) { + '\n' => break, + '@' => { + cursor += 1; + if (cursor >= contents.len) break; + if (contents[cursor] != 'b') continue; + const slice = contents[cursor..]; + if (bun.strings.startsWith(slice, "bun-cjs")) { + state.seen_cjs = true; + cursor += "bun-cjs".len; + } else if (bun.strings.startsWith(slice, "bytecode")) { + state.seen_bytecode = true; + cursor += "bytecode".len; + } + }, + else => {}, + } + } + + if (state.seen_cjs) { + return if (state.seen_bytecode) .bytecode_cjs else .bun_cjs; + } else { + return if (state.seen_bytecode) .bytecode else .bun; + } + } }; const FindLabelSymbolResult = struct { ref: Ref, is_loop: bool, found: bool = false }; diff --git a/test/bundler/transpiler/bun-pragma.test.ts b/test/bundler/transpiler/bun-pragma.test.ts new file mode 100644 index 0000000000..71d5e87f32 --- /dev/null +++ b/test/bundler/transpiler/bun-pragma.test.ts @@ -0,0 +1,45 @@ +import path from "path"; +import { promises as fs } from "fs"; +import { bunExe, bunEnv } from "harness"; + +const fixturePath = (...segs: string[]): string => path.join(import.meta.dirname, "fixtures", "bun-pragma", ...segs); + +const OK = 0; +const ERR = 1; + +const runFixture = async (path: string): Promise => { + const child = Bun.spawn({ + cmd: [bunExe(), "run", path], + env: bunEnv, + stdio: ["ignore", "ignore", "ignore"], + }); + await child.exited; + expect(child.exitCode).not.toBeNull(); + return child.exitCode!; +}; + +describe("@bun pragma", () => { + describe("valid files", async () => { + const passPath = fixturePath("pass"); + const passFiles: string[] = await fs.readdir(passPath, { encoding: "utf-8" }); + expect(passFiles).not.toHaveLength(0); + + it.each(passFiles)("bun run %s", async file => { + const fullpath = path.join(passPath, file); + const exitCode = await runFixture(fullpath); + expect(exitCode).toBe(OK); + }); + }); + + describe("invalid files", async () => { + const failPath = fixturePath("fail"); + const failFiles: string[] = await fs.readdir(failPath, { encoding: "utf-8" }); + expect(failFiles).not.toHaveLength(0); + + it.each(failFiles)("bun run %s", async file => { + const fullpath = path.join(failPath, file); + const exitCode = await runFixture(fullpath); + expect(exitCode).toBe(ERR); + }); + }); +}); diff --git a/test/bundler/transpiler/fixtures/bun-pragma/fail/bun-pragma-before-hashbang.ts b/test/bundler/transpiler/fixtures/bun-pragma/fail/bun-pragma-before-hashbang.ts new file mode 100644 index 0000000000..f2ed8f50d4 --- /dev/null +++ b/test/bundler/transpiler/fixtures/bun-pragma/fail/bun-pragma-before-hashbang.ts @@ -0,0 +1,5 @@ +#!/usr/bin/env bun +// @bun +export const foo: number = 123; + +// Not valid syntax. Bun pragma must be at the top of the file. diff --git a/test/bundler/transpiler/fixtures/bun-pragma/fail/ts-with-pragma.ts b/test/bundler/transpiler/fixtures/bun-pragma/fail/ts-with-pragma.ts new file mode 100644 index 0000000000..27e7c411d2 --- /dev/null +++ b/test/bundler/transpiler/fixtures/bun-pragma/fail/ts-with-pragma.ts @@ -0,0 +1,2 @@ +// @bun +export const foo: number = 123; diff --git a/test/bundler/transpiler/fixtures/bun-pragma/pass/bun-in-url.ts b/test/bundler/transpiler/fixtures/bun-pragma/pass/bun-in-url.ts new file mode 100644 index 0000000000..64af8d8e3b --- /dev/null +++ b/test/bundler/transpiler/fixtures/bun-pragma/pass/bun-in-url.ts @@ -0,0 +1,5 @@ +// https://bun.sh/docs/api/http#bun-serve +const a: string = "hello"; +console.log(a); + +// '#bun' spotted in first comment but it's not a valid bun pragma diff --git a/test/bundler/transpiler/fixtures/bun-pragma/pass/not-a-pragma.ts b/test/bundler/transpiler/fixtures/bun-pragma/pass/not-a-pragma.ts new file mode 100644 index 0000000000..47e995f78d --- /dev/null +++ b/test/bundler/transpiler/fixtures/bun-pragma/pass/not-a-pragma.ts @@ -0,0 +1,2 @@ +// @not-bun @bytecode +export const foo: number = 123; diff --git a/test/bundler/transpiler/fixtures/bun-pragma/pass/pragma-only-no-newline.ts b/test/bundler/transpiler/fixtures/bun-pragma/pass/pragma-only-no-newline.ts new file mode 100644 index 0000000000..aaa250af21 --- /dev/null +++ b/test/bundler/transpiler/fixtures/bun-pragma/pass/pragma-only-no-newline.ts @@ -0,0 +1 @@ +// @bun diff --git a/test/bundler/transpiler/fixtures/bun-pragma/pass/pragma-only-with-newline.ts b/test/bundler/transpiler/fixtures/bun-pragma/pass/pragma-only-with-newline.ts new file mode 100644 index 0000000000..440005bdd3 --- /dev/null +++ b/test/bundler/transpiler/fixtures/bun-pragma/pass/pragma-only-with-newline.ts @@ -0,0 +1,2 @@ +// @bun + diff --git a/test/bundler/transpiler/fixtures/bun-pragma/pass/valid-pragma-without-bun-prefix.ts b/test/bundler/transpiler/fixtures/bun-pragma/pass/valid-pragma-without-bun-prefix.ts new file mode 100644 index 0000000000..23d4025f62 --- /dev/null +++ b/test/bundler/transpiler/fixtures/bun-pragma/pass/valid-pragma-without-bun-prefix.ts @@ -0,0 +1,5 @@ +// @bytecode +export const foo: number = 122; + +// explanation: @bytecode is a valid pragma checked by the parser, but only if +// @bun is found before it. From d6b9c444c106c4ead66b8e8bd375316b127ae6d7 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 21 Dec 2024 00:59:37 -0800 Subject: [PATCH 081/125] Rename src/bundler.zig to src/transpiler.zig (#15921) Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> --- src/bake/DevServer.zig | 12 +- src/bake/FrameworkRouter.zig | 2 +- src/bake/bake.zig | 4 +- src/bake/production.zig | 24 +- src/bun.js/api/BunObject.zig | 31 +- src/bun.js/api/JSBundler.zig | 8 +- src/bun.js/api/JSTranspiler.zig | 178 ++++---- src/bun.js/api/bun/subprocess.zig | 6 +- src/bun.js/api/ffi.zig | 8 +- src/bun.js/api/filesystem_router.zig | 44 +- src/bun.js/api/server.zig | 22 +- src/bun.js/config.zig | 2 +- src/bun.js/event_loop.zig | 10 +- src/bun.js/javascript.zig | 178 ++++---- src/bun.js/module_loader.zig | 132 +++--- src/bun.js/node/path_watcher.zig | 2 +- src/bun.js/node/types.zig | 2 +- src/bun.js/test/snapshot.zig | 8 +- src/bun.js/web_worker.zig | 18 +- src/bun.js/webcore/response.zig | 6 +- src/bun.zig | 4 +- src/bun_js.zig | 16 +- src/bundler/bundle_v2.zig | 560 ++++++++++++------------ src/bundler/entry_points.zig | 18 +- src/cli.zig | 2 +- src/cli/build_command.zig | 150 +++---- src/cli/bunx_command.zig | 100 ++--- src/cli/create_command.zig | 1 - src/cli/exec_command.zig | 2 +- src/cli/filter_run.zig | 16 +- src/cli/install_completions_command.zig | 1 - src/cli/pack_command.zig | 14 +- src/cli/run_command.zig | 172 ++++---- src/cli/test_command.zig | 30 +- src/cli/upgrade_command.zig | 1 - src/css/targets.zig | 2 +- src/ini.zig | 4 +- src/install/install.zig | 42 +- src/install/lockfile.zig | 1 - src/js_ast.zig | 14 +- src/json_parser.zig | 4 +- src/linker.zig | 20 +- src/resolver/resolve_path.zig | 2 +- src/resolver/resolver.zig | 4 +- src/shell/interpreter.zig | 2 +- src/shell/shell.zig | 6 +- src/shell/subproc.zig | 4 +- src/{bundler.zig => transpiler.zig} | 479 ++++++++++---------- test/bundler/expectBundled.ts | 2 +- 49 files changed, 1178 insertions(+), 1192 deletions(-) rename src/{bundler.zig => transpiler.zig} (79%) diff --git a/src/bake/DevServer.zig b/src/bake/DevServer.zig index 47ba7fac54..ff74bb0c69 100644 --- a/src/bake/DevServer.zig +++ b/src/bake/DevServer.zig @@ -96,9 +96,9 @@ bundles_since_last_error: usize = 0, framework: bake.Framework, bundler_options: bake.SplitBundlerOptions, // Each logical graph gets its own bundler configuration -server_bundler: Bundler, -client_bundler: Bundler, -ssr_bundler: Bundler, +server_bundler: Transpiler, +client_bundler: Transpiler, +ssr_bundler: Transpiler, /// The log used by all `server_bundler`, `client_bundler` and `ssr_bundler`. /// Note that it is rarely correct to write messages into it. Instead, associate /// messages with the IncrementalGraph file or Route using `SerializedFailure` @@ -837,7 +837,7 @@ pub fn onSrcRequest(dev: *DevServer, req: *uws.Request, resp: *App.Response) voi } const ctx = &dev.vm.rareData().editor_context; - ctx.autoDetectEditor(JSC.VirtualMachine.get().bundler.env); + ctx.autoDetectEditor(JSC.VirtualMachine.get().transpiler.env); const line: ?[]const u8 = req.header("editor-line"); const column: ?[]const u8 = req.header("editor-column"); @@ -3431,7 +3431,7 @@ pub const SerializedFailure = struct { // TODO: syntax highlighted line text + give more context lines try writeString32(loc.line_text orelse "", w); - // The file is not specified here. Since the bundler runs every file + // The file is not specified here. Since the transpiler runs every file // in isolation, it would be impossible to reference any other file // in this Log. Thus, it is not serialized. } else { @@ -4463,7 +4463,7 @@ const OpaqueFileId = FrameworkRouter.OpaqueFileId; const Log = bun.logger.Log; const Output = bun.Output; -const Bundler = bun.bundler.Bundler; +const Transpiler = bun.transpiler.Transpiler; const BundleV2 = bun.bundle_v2.BundleV2; const Define = bun.options.Define; diff --git a/src/bake/FrameworkRouter.zig b/src/bake/FrameworkRouter.zig index ed7b2cc258..bab239a9f6 100644 --- a/src/bake/FrameworkRouter.zig +++ b/src/bake/FrameworkRouter.zig @@ -1129,7 +1129,7 @@ pub const JSFrameworkRouter = struct { try jsfr.router.scan( bun.default_allocator, Type.Index.init(0), - &global.bunVM().bundler.resolver, + &global.bunVM().transpiler.resolver, InsertionContext.wrap(JSFrameworkRouter, jsfr), ); if (jsfr.stored_parse_errors.items.len > 0) { diff --git a/src/bake/bake.zig b/src/bake/bake.zig index 134acce3d9..f48bd46d87 100644 --- a/src/bake/bake.zig +++ b/src/bake/bake.zig @@ -544,9 +544,9 @@ pub const Framework = struct { log: *bun.logger.Log, mode: Mode, comptime renderer: Graph, - out: *bun.bundler.Bundler, + out: *bun.transpiler.Transpiler, ) !void { - out.* = try bun.Bundler.init( + out.* = try bun.Transpiler.init( allocator, // TODO: this is likely a memory leak log, std.mem.zeroes(bun.Schema.Api.TransformOptions), diff --git a/src/bake/production.zig b/src/bake/production.zig index edeedd1de1..f9414927d1 100644 --- a/src/bake/production.zig +++ b/src/bake/production.zig @@ -42,7 +42,7 @@ pub fn buildCommand(ctx: bun.CLI.Command.Context) !void { vm.regular_event_loop.global = vm.global; vm.jsc = vm.global.vm(); vm.event_loop.ensureWaker(); - const b = &vm.bundler; + const b = &vm.transpiler; vm.preload = ctx.preloads; vm.argv = ctx.passthrough; vm.arena = &arena; @@ -99,7 +99,7 @@ pub fn buildCommand(ctx: bun.CLI.Command.Context) !void { pub fn buildWithVm(ctx: bun.CLI.Command.Context, cwd: []const u8, vm: *VirtualMachine) !void { // Load and evaluate the configuration module const global = vm.global; - const b = &vm.bundler; + const b = &vm.transpiler; const allocator = bun.default_allocator; Output.prettyErrorln("Loading configuration", .{}); @@ -171,9 +171,9 @@ pub fn buildWithVm(ctx: bun.CLI.Command.Context, cwd: []const u8, vm: *VirtualMa try loader.map.put("NODE_ENV", "production"); bun.DotEnv.instance = loader; - var client_bundler: bun.bundler.Bundler = undefined; - var server_bundler: bun.bundler.Bundler = undefined; - var ssr_bundler: bun.bundler.Bundler = undefined; + var client_bundler: bun.transpiler.Transpiler = undefined; + var server_bundler: bun.transpiler.Transpiler = undefined; + var ssr_bundler: bun.transpiler.Transpiler = undefined; try framework.initBundler(allocator, vm.log, .production_static, .server, &server_bundler); try framework.initBundler(allocator, vm.log, .production_static, .client, &client_bundler); if (separate_ssr_graph) { @@ -181,13 +181,13 @@ pub fn buildWithVm(ctx: bun.CLI.Command.Context, cwd: []const u8, vm: *VirtualMa } if (ctx.bundler_options.bake_debug_disable_minify) { - for ([_]*bun.bundler.Bundler{ &client_bundler, &server_bundler, &ssr_bundler }) |bundler| { - bundler.options.minify_syntax = false; - bundler.options.minify_identifiers = false; - bundler.options.minify_whitespace = false; - bundler.resolver.opts.entry_naming = "_bun/[dir]/[name].[hash].[ext]"; - bundler.resolver.opts.chunk_naming = "_bun/[dir]/[name].[hash].chunk.[ext]"; - bundler.resolver.opts.asset_naming = "_bun/[dir]/[name].[hash].asset.[ext]"; + for ([_]*bun.transpiler.Transpiler{ &client_bundler, &server_bundler, &ssr_bundler }) |transpiler| { + transpiler.options.minify_syntax = false; + transpiler.options.minify_identifiers = false; + transpiler.options.minify_whitespace = false; + transpiler.resolver.opts.entry_naming = "_bun/[dir]/[name].[hash].[ext]"; + transpiler.resolver.opts.chunk_naming = "_bun/[dir]/[name].[hash].chunk.[ext]"; + transpiler.resolver.opts.asset_naming = "_bun/[dir]/[name].[hash].asset.[ext]"; } } diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index 9f1345b3d8..13d6f66d79 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -186,12 +186,11 @@ const Fs = @import("../../fs.zig"); const Resolver = @import("../../resolver/resolver.zig"); const ast = @import("../../import_record.zig"); -const MacroEntryPoint = bun.bundler.MacroEntryPoint; +const MacroEntryPoint = bun.transpiler.MacroEntryPoint; const logger = bun.logger; const Api = @import("../../api/schema.zig").Api; const options = @import("../../options.zig"); -const Bundler = bun.Bundler; -const ServerEntryPoint = bun.bundler.ServerEntryPoint; +const ServerEntryPoint = bun.transpiler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; @@ -203,7 +202,7 @@ const Runtime = @import("../../runtime.zig"); const Router = @import("./filesystem_router.zig"); const ImportRecord = ast.ImportRecord; const DotEnv = @import("../../env_loader.zig"); -const ParseResult = bun.bundler.ParseResult; +const ParseResult = bun.transpiler.ParseResult; const PackageJSON = @import("../../resolver/package_json.zig").PackageJSON; const MacroRemap = @import("../../resolver/package_json.zig").MacroMap; const WebCore = bun.JSC.WebCore; @@ -379,10 +378,10 @@ pub fn which(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSE } path_str = ZigString.Slice.fromUTF8NeverFree( - globalThis.bunVM().bundler.env.get("PATH") orelse "", + globalThis.bunVM().transpiler.env.get("PATH") orelse "", ); cwd_str = ZigString.Slice.fromUTF8NeverFree( - globalThis.bunVM().bundler.fs.top_level_dir, + globalThis.bunVM().transpiler.fs.top_level_dir, ); if (arguments.nextEat()) |arg| { @@ -572,7 +571,7 @@ pub fn registerMacro(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFram } pub fn getCWD(globalThis: *JSC.JSGlobalObject, _: *JSC.JSObject) JSC.JSValue { - return ZigString.init(VirtualMachine.get().bundler.fs.top_level_dir).toJS(globalThis); + return ZigString.init(VirtualMachine.get().transpiler.fs.top_level_dir).toJS(globalThis); } pub fn getOrigin(globalThis: *JSC.JSGlobalObject, _: *JSC.JSObject) JSC.JSValue { @@ -696,7 +695,7 @@ pub fn openInEditor(globalThis: js.JSContextRef, callframe: *JSC.CallFrame) bun. if (!strings.eqlLong(prev_name, sliced.slice(), true)) { const prev = edit.*; edit.name = sliced.slice(); - edit.detectEditor(VirtualMachine.get().bundler.env); + edit.detectEditor(VirtualMachine.get().transpiler.env); editor_choice = edit.editor; if (editor_choice == null) { edit.* = prev; @@ -719,7 +718,7 @@ pub fn openInEditor(globalThis: js.JSContextRef, callframe: *JSC.CallFrame) bun. } const editor = editor_choice orelse edit.editor orelse brk: { - edit.autoDetectEditor(VirtualMachine.get().bundler.env); + edit.autoDetectEditor(VirtualMachine.get().transpiler.env); if (edit.editor == null) { return globalThis.throw("Failed to auto-detect editor", .{}); } @@ -741,7 +740,7 @@ pub fn openInEditor(globalThis: js.JSContextRef, callframe: *JSC.CallFrame) bun. pub fn getPublicPath(to: string, origin: URL, comptime Writer: type, writer: Writer) void { return getPublicPathWithAssetPrefix( to, - VirtualMachine.get().bundler.fs.top_level_dir, + VirtualMachine.get().transpiler.fs.top_level_dir, origin, "", comptime Writer, @@ -762,7 +761,7 @@ pub fn getPublicPathWithAssetPrefix( const relative_path = if (strings.hasPrefix(to, dir)) strings.withoutTrailingSlash(to[dir.len..]) else - VirtualMachine.get().bundler.fs.relativePlatform(dir, to, platform); + VirtualMachine.get().transpiler.fs.relativePlatform(dir, to, platform); if (origin.isAbsolute()) { if (strings.hasPrefix(relative_path, "..") or strings.hasPrefix(relative_path, "./")) { writer.writeAll(origin.origin) catch return; @@ -770,7 +769,7 @@ pub fn getPublicPathWithAssetPrefix( if (std.fs.path.isAbsolute(to)) { writer.writeAll(to) catch return; } else { - writer.writeAll(VirtualMachine.get().bundler.fs.abs(&[_]string{to})) catch return; + writer.writeAll(VirtualMachine.get().transpiler.fs.abs(&[_]string{to})) catch return; } } else { origin.joinWrite( @@ -4193,8 +4192,8 @@ pub fn stringWidth(str: bun.String, opts: gen.StringWidthOptions) usize { pub const EnvironmentVariables = struct { pub export fn Bun__getEnvCount(globalObject: *JSC.JSGlobalObject, ptr: *[*][]const u8) usize { const bunVM = globalObject.bunVM(); - ptr.* = bunVM.bundler.env.map.map.keys().ptr; - return bunVM.bundler.env.map.map.unmanaged.entries.len; + ptr.* = bunVM.transpiler.env.map.map.keys().ptr; + return bunVM.transpiler.env.map.map.unmanaged.entries.len; } pub export fn Bun__getEnvKey(ptr: [*][]const u8, i: usize, data_ptr: *[*]const u8) usize { @@ -4214,7 +4213,7 @@ pub const EnvironmentVariables = struct { pub fn getEnvNames(globalObject: *JSC.JSGlobalObject, names: []ZigString) usize { var vm = globalObject.bunVM(); - const keys = vm.bundler.env.map.map.keys(); + const keys = vm.transpiler.env.map.map.keys(); const len = @min(names.len, keys.len); for (keys[0..len], names[0..len]) |key, *name| { name.* = ZigString.initUTF8(key); @@ -4226,7 +4225,7 @@ pub const EnvironmentVariables = struct { var vm = globalObject.bunVM(); var sliced = name.toSlice(vm.allocator); defer sliced.deinit(); - const value = vm.bundler.env.get(sliced.slice()) orelse return null; + const value = vm.transpiler.env.get(sliced.slice()) orelse return null; return ZigString.initUTF8(value); } }; diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig index d122808bde..7aa8cbe9c1 100644 --- a/src/bun.js/api/JSBundler.zig +++ b/src/bun.js/api/JSBundler.zig @@ -8,7 +8,7 @@ const string = bun.string; const JSC = bun.JSC; const js = JSC.C; const WebCore = @import("../webcore/response.zig"); -const Bundler = bun.bundler; +const Transpiler = bun.transpiler; const options = @import("../../options.zig"); const resolve_path = @import("../../resolver/resolve_path.zig"); const VirtualMachine = JavaScript.VirtualMachine; @@ -44,7 +44,7 @@ const JSLexer = bun.js_lexer; const Expr = JSAst.Expr; const Index = @import("../../ast/base.zig").Index; -const debug = bun.Output.scoped(.Bundler, false); +const debug = bun.Output.scoped(.Transpiler, false); pub const JSBundler = struct { const OwnedString = bun.MutableString; @@ -389,7 +389,7 @@ pub const JSBundler = struct { // defer slice.deinit(); // this.appendSliceExact(slice.slice()) catch unreachable; // } else { - // this.appendSliceExact(globalThis.bunVM().bundler.fs.top_level_dir) catch unreachable; + // this.appendSliceExact(globalThis.bunVM().transpiler.fs.top_level_dir) catch unreachable; // } if (try config.getOptional(globalThis, "publicPath", ZigString.Slice)) |slice| { @@ -748,7 +748,7 @@ pub const JSBundler = struct { .bv2 = bv2, .parse_task = parse, .source_index = parse.source_index, - .default_loader = parse.path.loader(&bv2.bundler.options.loaders) orelse .js, + .default_loader = parse.path.loader(&bv2.transpiler.options.loaders) orelse .js, .value = .pending, .path = parse.path.text, .namespace = parse.path.namespace, diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig index e13490d497..d53c20996d 100644 --- a/src/bun.js/api/JSTranspiler.zig +++ b/src/bun.js/api/JSTranspiler.zig @@ -8,7 +8,7 @@ const string = bun.string; const JSC = bun.JSC; const js = JSC.C; const WebCore = @import("../webcore/response.zig"); -const Bundler = bun.bundler; +const Transpiler = bun.transpiler; const options = @import("../../options.zig"); const VirtualMachine = JavaScript.VirtualMachine; const ScriptSrcStream = std.io.FixedBufferStream([]u8); @@ -33,7 +33,6 @@ const logger = bun.logger; const Loader = options.Loader; const Target = options.Target; const JSAst = bun.JSAst; -const Transpiler = @This(); const JSParser = bun.js_parser; const JSPrinter = bun.js_printer; const ScanPassResult = JSParser.ScanPassResult; @@ -42,9 +41,10 @@ const Runtime = @import("../../runtime.zig").Runtime; const JSLexer = bun.js_lexer; const Expr = JSAst.Expr; +const JSTranspiler = @This(); pub usingnamespace JSC.Codegen.JSTranspiler; -bundler: Bundler.Bundler, +transpiler: bun.transpiler.Transpiler, arena: bun.ArenaAllocator, transpiler_options: TranspilerOptions, scan_pass_result: ScanPassResult, @@ -86,7 +86,7 @@ const TranspilerOptions = struct { pub const TransformTask = struct { input_code: JSC.Node.StringOrBuffer = JSC.Node.StringOrBuffer{ .buffer = .{} }, output_code: bun.String = bun.String.empty, - bundler: Bundler.Bundler = undefined, + transpiler: Transpiler.Transpiler = undefined, log: logger.Log, err: ?anyerror = null, macro_map: MacroMap = MacroMap{}, @@ -100,10 +100,10 @@ pub const TransformTask = struct { pub const AsyncTransformTask = JSC.ConcurrentPromiseTask(TransformTask); pub const AsyncTransformEventLoopTask = AsyncTransformTask.EventLoopTask; - pub fn create(transpiler: *Transpiler, input_code: bun.JSC.Node.StringOrBuffer, globalThis: *JSGlobalObject, loader: Loader) !*AsyncTransformTask { + pub fn create(transpiler: *JSTranspiler, input_code: bun.JSC.Node.StringOrBuffer, globalThis: *JSGlobalObject, loader: Loader) !*AsyncTransformTask { var transform_task = TransformTask.new(.{ .input_code = input_code, - .bundler = undefined, + .transpiler = undefined, .global = globalThis, .macro_map = transpiler.transpiler_options.macro_map, .tsconfig = transpiler.transpiler_options.tsconfig, @@ -112,11 +112,11 @@ pub const TransformTask = struct { .replace_exports = transpiler.transpiler_options.runtime.replace_exports, }); transform_task.log.level = transpiler.transpiler_options.log.level; - transform_task.bundler = transpiler.bundler; - transform_task.bundler.linker.resolver = &transform_task.bundler.resolver; + transform_task.transpiler = transpiler.transpiler; + transform_task.transpiler.linker.resolver = &transform_task.transpiler.resolver; - transform_task.bundler.setLog(&transform_task.log); - transform_task.bundler.setAllocator(bun.default_allocator); + transform_task.transpiler.setLog(&transform_task.log); + transform_task.transpiler.setAllocator(bun.default_allocator); return try AsyncTransformTask.createOnJSThread(bun.default_allocator, globalThis, transform_task); } @@ -149,16 +149,16 @@ pub const TransformTask = struct { arena.deinit(); } - this.bundler.setAllocator(allocator); - this.bundler.setLog(&this.log); + this.transpiler.setAllocator(allocator); + this.transpiler.setLog(&this.log); this.log.msgs.allocator = bun.default_allocator; const jsx = if (this.tsconfig != null) - this.tsconfig.?.mergeJSX(this.bundler.options.jsx) + this.tsconfig.?.mergeJSX(this.transpiler.options.jsx) else - this.bundler.options.jsx; + this.transpiler.options.jsx; - const parse_options = Bundler.Bundler.ParseOptions{ + const parse_options = Transpiler.Transpiler.ParseOptions{ .allocator = allocator, .macro_remappings = this.macro_map, .dirname_fd = .zero, @@ -171,7 +171,7 @@ pub const TransformTask = struct { // .allocator = this. }; - const parse_result = this.bundler.parse(parse_options, null) orelse { + const parse_result = this.transpiler.parse(parse_options, null) orelse { this.err = error.ParseError; return; }; @@ -193,7 +193,7 @@ pub const TransformTask = struct { // } var printer = JSPrinter.BufferPrinter.init(buffer_writer); - const printed = this.bundler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| { + const printed = this.transpiler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| { this.err = err; return; }; @@ -454,7 +454,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std allocator, &transpiler.log, logger.Source.initPathString("tsconfig.json", transpiler.tsconfig_buf), - &VirtualMachine.get().bundler.resolver.caches.json, + &VirtualMachine.get().transpiler.resolver.caches.json, ) catch null) |parsed_tsconfig| { transpiler.tsconfig = parsed_tsconfig; } @@ -492,7 +492,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std if (out.isEmpty()) break :macros; transpiler.macros_buf = out.toOwnedSlice(allocator) catch bun.outOfMemory(); const source = logger.Source.initPathString("macros.json", transpiler.macros_buf); - const json = (VirtualMachine.get().bundler.resolver.caches.json.parseJSON( + const json = (VirtualMachine.get().transpiler.resolver.caches.json.parseJSON( &transpiler.log, source, allocator, @@ -706,7 +706,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std return transpiler; } -pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!*Transpiler { +pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!*JSTranspiler { var temp = bun.ArenaAllocator.init(getAllocator(globalThis)); const arguments = callframe.arguments_old(3); var args = JSC.Node.ArgumentsSlice.init( @@ -732,11 +732,11 @@ pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) b var log = try allocator.create(logger.Log); log.* = transpiler_options.log; - var bundler = Bundler.Bundler.init( + var transpiler = Transpiler.Transpiler.init( allocator, log, transpiler_options.transform, - JavaScript.VirtualMachine.get().bundler.env, + JavaScript.VirtualMachine.get().transpiler.env, ) catch |err| { if ((log.warnings + log.errors) > 0) { return globalThis.throwValue(log.toJS(globalThis, allocator, "Failed to create transpiler")); @@ -744,10 +744,10 @@ pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) b return globalThis.throwError(err, "Error creating transpiler"); }; - bundler.options.no_macros = transpiler_options.no_macros; - bundler.configureLinkerWithAutoJSX(false); - bundler.options.env.behavior = .disable; - bundler.configureDefines() catch |err| { + transpiler.options.no_macros = transpiler_options.no_macros; + transpiler.configureLinkerWithAutoJSX(false); + transpiler.options.env.behavior = .disable; + transpiler.configureDefines() catch |err| { if ((log.warnings + log.errors) > 0) { return globalThis.throwValue(log.toJS(globalThis, allocator, "Failed to load define")); } @@ -755,42 +755,42 @@ pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) b }; if (transpiler_options.macro_map.count() > 0) { - bundler.options.macro_remap = transpiler_options.macro_map; + transpiler.options.macro_remap = transpiler_options.macro_map; } - bundler.options.dead_code_elimination = transpiler_options.dead_code_elimination; - bundler.options.minify_whitespace = transpiler_options.minify_whitespace; + transpiler.options.dead_code_elimination = transpiler_options.dead_code_elimination; + transpiler.options.minify_whitespace = transpiler_options.minify_whitespace; // Keep defaults for these if (transpiler_options.minify_syntax) - bundler.options.minify_syntax = true; + transpiler.options.minify_syntax = true; if (transpiler_options.minify_identifiers) - bundler.options.minify_identifiers = true; + transpiler.options.minify_identifiers = true; - bundler.options.transform_only = !bundler.options.allow_runtime; + transpiler.options.transform_only = !transpiler.options.allow_runtime; - bundler.options.tree_shaking = transpiler_options.tree_shaking; - bundler.options.trim_unused_imports = transpiler_options.trim_unused_imports; - bundler.options.allow_runtime = transpiler_options.runtime.allow_runtime; - bundler.options.auto_import_jsx = transpiler_options.runtime.auto_import_jsx; - bundler.options.inlining = transpiler_options.runtime.inlining; - bundler.options.hot_module_reloading = transpiler_options.runtime.hot_module_reloading; - bundler.options.react_fast_refresh = false; + transpiler.options.tree_shaking = transpiler_options.tree_shaking; + transpiler.options.trim_unused_imports = transpiler_options.trim_unused_imports; + transpiler.options.allow_runtime = transpiler_options.runtime.allow_runtime; + transpiler.options.auto_import_jsx = transpiler_options.runtime.auto_import_jsx; + transpiler.options.inlining = transpiler_options.runtime.inlining; + transpiler.options.hot_module_reloading = transpiler_options.runtime.hot_module_reloading; + transpiler.options.react_fast_refresh = false; - const transpiler = try allocator.create(Transpiler); - transpiler.* = Transpiler{ + const instance = try allocator.create(JSTranspiler); + instance.* = JSTranspiler{ .transpiler_options = transpiler_options, - .bundler = bundler, + .transpiler = transpiler, .arena = args.arena, .scan_pass_result = ScanPassResult.init(allocator), }; - return transpiler; + return instance; } -pub fn finalize(this: *Transpiler) callconv(.C) void { - this.bundler.log.deinit(); +pub fn finalize(this: *JSTranspiler) void { + this.transpiler.log.deinit(); this.scan_pass_result.named_imports.deinit(this.scan_pass_result.import_records.allocator); this.scan_pass_result.import_records.deinit(); this.scan_pass_result.used_symbols.deinit(); @@ -804,16 +804,16 @@ pub fn finalize(this: *Transpiler) callconv(.C) void { JSC.VirtualMachine.get().allocator.destroy(this); } -fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const u8, loader: ?Loader, macro_js_ctx: Bundler.MacroJSValueType) ?Bundler.ParseResult { +fn getParseResult(this: *JSTranspiler, allocator: std.mem.Allocator, code: []const u8, loader: ?Loader, macro_js_ctx: Transpiler.MacroJSValueType) ?Transpiler.ParseResult { const name = this.transpiler_options.default_loader.stdinName(); const source = logger.Source.initPathString(name, code); const jsx = if (this.transpiler_options.tsconfig != null) - this.transpiler_options.tsconfig.?.mergeJSX(this.bundler.options.jsx) + this.transpiler_options.tsconfig.?.mergeJSX(this.transpiler.options.jsx) else - this.bundler.options.jsx; + this.transpiler.options.jsx; - const parse_options = Bundler.Bundler.ParseOptions{ + const parse_options = Transpiler.Transpiler.ParseOptions{ .allocator = allocator, .macro_remappings = this.transpiler_options.macro_map, .dirname_fd = .zero, @@ -827,10 +827,10 @@ fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const // .allocator = this. }; - return this.bundler.parse(parse_options, null); + return this.transpiler.parse(parse_options, null); } -pub fn scan(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { +pub fn scan(this: *JSTranspiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { JSC.markBinding(@src()); const arguments = callframe.arguments_old(3); var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.slice()); @@ -860,14 +860,14 @@ pub fn scan(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC. } var arena = Mimalloc.Arena.init() catch unreachable; - const prev_allocator = this.bundler.allocator; - this.bundler.setAllocator(arena.allocator()); + const prev_allocator = this.transpiler.allocator; + this.transpiler.setAllocator(arena.allocator()); var log = logger.Log.init(arena.backingAllocator()); defer log.deinit(); - this.bundler.setLog(&log); + this.transpiler.setLog(&log); defer { - this.bundler.setLog(&this.transpiler_options.log); - this.bundler.setAllocator(prev_allocator); + this.transpiler.setLog(&this.transpiler_options.log); + this.transpiler.setAllocator(prev_allocator); arena.deinit(); } @@ -876,16 +876,16 @@ pub fn scan(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC. JSAst.Expr.Data.Store.reset(); } - var parse_result = getParseResult(this, arena.allocator(), code, loader, Bundler.MacroJSValueType.zero) orelse { - if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) { - return globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); + var parse_result = getParseResult(this, arena.allocator(), code, loader, Transpiler.MacroJSValueType.zero) orelse { + if ((this.transpiler.log.warnings + this.transpiler.log.errors) > 0) { + return globalThis.throwValue(this.transpiler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); } return globalThis.throw("Failed to parse", .{}); }; - if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) { - return globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); + if ((this.transpiler.log.warnings + this.transpiler.log.errors) > 0) { + return globalThis.throwValue(this.transpiler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); } const exports_label = JSC.ZigString.static("exports"); @@ -902,7 +902,7 @@ pub fn scan(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC. return JSC.JSValue.createObject2(globalThis, imports_label, exports_label, named_imports_value, named_exports_value); } -pub fn transform(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { +pub fn transform(this: *JSTranspiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { JSC.markBinding(@src()); const arguments = callframe.arguments_old(3); var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.slice()); @@ -946,7 +946,7 @@ pub fn transform(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe: } pub fn transformSync( - this: *Transpiler, + this: *JSTranspiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, ) bun.JSError!JSC.JSValue { @@ -1011,32 +1011,32 @@ pub fn transformSync( JSAst.Expr.Data.Store.reset(); } - const prev_bundler = this.bundler; - this.bundler.setAllocator(arena.allocator()); - this.bundler.macro_context = null; + const prev_bundler = this.transpiler; + this.transpiler.setAllocator(arena.allocator()); + this.transpiler.macro_context = null; var log = logger.Log.init(arena.backingAllocator()); log.level = this.transpiler_options.log.level; - this.bundler.setLog(&log); + this.transpiler.setLog(&log); defer { - this.bundler = prev_bundler; + this.transpiler = prev_bundler; } const parse_result = getParseResult( this, arena.allocator(), code, loader, - if (comptime JSC.is_bindgen) Bundler.MacroJSValueType.zero else js_ctx_value, + if (comptime JSC.is_bindgen) Transpiler.MacroJSValueType.zero else js_ctx_value, ) orelse { - if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) { - return globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); + if ((this.transpiler.log.warnings + this.transpiler.log.errors) > 0) { + return globalThis.throwValue(this.transpiler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); } return globalThis.throw("Failed to parse code", .{}); }; - if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) { - return globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); + if ((this.transpiler.log.warnings + this.transpiler.log.errors) > 0) { + return globalThis.throwValue(this.transpiler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); } var buffer_writer = this.buffer_writer orelse brk: { @@ -1055,7 +1055,7 @@ pub fn transformSync( buffer_writer.reset(); var printer = JSPrinter.BufferPrinter.init(buffer_writer); - _ = this.bundler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| { + _ = this.transpiler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| { return globalThis.throwError(err, "Failed to print code"); }; @@ -1114,7 +1114,7 @@ fn namedImportsToJS( return array; } -pub fn scanImports(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { +pub fn scanImports(this: *JSTranspiler, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { const arguments = callframe.arguments_old(2); var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.slice()); defer args.deinit(); @@ -1146,29 +1146,29 @@ pub fn scanImports(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe } var arena = Mimalloc.Arena.init() catch unreachable; - const prev_allocator = this.bundler.allocator; - this.bundler.setAllocator(arena.allocator()); + const prev_allocator = this.transpiler.allocator; + this.transpiler.setAllocator(arena.allocator()); var log = logger.Log.init(arena.backingAllocator()); defer log.deinit(); - this.bundler.setLog(&log); + this.transpiler.setLog(&log); defer { - this.bundler.setLog(&this.transpiler_options.log); - this.bundler.setAllocator(prev_allocator); + this.transpiler.setLog(&this.transpiler_options.log); + this.transpiler.setAllocator(prev_allocator); arena.deinit(); } const source = logger.Source.initPathString(loader.stdinName(), code); - var bundler = &this.bundler; + var transpiler = &this.transpiler; const jsx = if (this.transpiler_options.tsconfig != null) - this.transpiler_options.tsconfig.?.mergeJSX(this.bundler.options.jsx) + this.transpiler_options.tsconfig.?.mergeJSX(this.transpiler.options.jsx) else - this.bundler.options.jsx; + this.transpiler.options.jsx; var opts = JSParser.Parser.Options.init(jsx, loader); - if (this.bundler.macro_context == null) { - this.bundler.macro_context = JSAst.Macro.MacroContext.init(&this.bundler); + if (this.transpiler.macro_context == null) { + this.transpiler.macro_context = JSAst.Macro.MacroContext.init(&this.transpiler); } - opts.macro_context = &this.bundler.macro_context.?; + opts.macro_context = &this.transpiler.macro_context.?; JSAst.Stmt.Data.Store.reset(); JSAst.Expr.Data.Store.reset(); @@ -1178,11 +1178,11 @@ pub fn scanImports(this: *Transpiler, globalThis: *JSC.JSGlobalObject, callframe JSAst.Expr.Data.Store.reset(); } - bundler.resolver.caches.js.scan( - bundler.allocator, + transpiler.resolver.caches.js.scan( + transpiler.allocator, &this.scan_pass_result, opts, - bundler.options.define, + transpiler.options.define, &log, &source, ) catch |err| { diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 3872f0436d..143b87fb25 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -1717,7 +1717,7 @@ pub const Subprocess = struct { var env_array = std.ArrayListUnmanaged(?[*:0]const u8){}; var jsc_vm = globalThis.bunVM(); - var cwd = jsc_vm.bundler.fs.top_level_dir; + var cwd = jsc_vm.transpiler.fs.top_level_dir; var stdio = [3]Stdio{ .{ .ignore = {} }, @@ -1732,7 +1732,7 @@ pub const Subprocess = struct { var lazy = false; var on_exit_callback = JSValue.zero; var on_disconnect_callback = JSValue.zero; - var PATH = jsc_vm.bundler.env.get("PATH") orelse ""; + var PATH = jsc_vm.transpiler.env.get("PATH") orelse ""; var argv = std.ArrayList(?[*:0]const u8).init(allocator); var cmd_value = JSValue.zero; var detached = false; @@ -1985,7 +1985,7 @@ pub const Subprocess = struct { } if (!override_env and env_array.items.len == 0) { - env_array.items = jsc_vm.bundler.env.map.createNullDelimitedEnvMap(allocator) catch |err| return globalThis.throwError(err, "in Bun.spawn") catch return .zero; + env_array.items = jsc_vm.transpiler.env.map.createNullDelimitedEnvMap(allocator) catch |err| return globalThis.throwError(err, "in Bun.spawn") catch return .zero; env_array.capacity = env_array.items.len; } diff --git a/src/bun.js/api/ffi.zig b/src/bun.js/api/ffi.zig index 0fd9ff1644..1f7a9a8499 100644 --- a/src/bun.js/api/ffi.zig +++ b/src/bun.js/api/ffi.zig @@ -17,12 +17,12 @@ const Fs = @import("../../fs.zig"); const Resolver = @import("../../resolver/resolver.zig"); const ast = @import("../../import_record.zig"); -const MacroEntryPoint = bun.bundler.MacroEntryPoint; +const MacroEntryPoint = bun.transpiler.MacroEntryPoint; const logger = bun.logger; const Api = @import("../../api/schema.zig").Api; const options = @import("../../options.zig"); -const Bundler = bun.Bundler; -const ServerEntryPoint = bun.bundler.ServerEntryPoint; +const Transpiler = bun.Transpiler; +const ServerEntryPoint = bun.transpiler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; @@ -33,7 +33,7 @@ const ZigString = bun.JSC.ZigString; const Runtime = @import("../../runtime.zig"); const ImportRecord = ast.ImportRecord; const DotEnv = @import("../../env_loader.zig"); -const ParseResult = bun.bundler.ParseResult; +const ParseResult = bun.transpiler.ParseResult; const PackageJSON = @import("../../resolver/package_json.zig").PackageJSON; const MacroRemap = @import("../../resolver/package_json.zig").MacroMap; const WebCore = bun.JSC.WebCore; diff --git a/src/bun.js/api/filesystem_router.zig b/src/bun.js/api/filesystem_router.zig index 8738fbce70..ae4d50e2c2 100644 --- a/src/bun.js/api/filesystem_router.zig +++ b/src/bun.js/api/filesystem_router.zig @@ -8,7 +8,7 @@ const string = bun.string; const JSC = bun.JSC; const js = JSC.C; const WebCore = JSC.WebCore; -const Bundler = bun.bundler; +const Transpiler = bun.transpiler; const VirtualMachine = JavaScript.VirtualMachine; const ScriptSrcStream = std.io.FixedBufferStream([]u8); const ZigString = JSC.ZigString; @@ -60,7 +60,7 @@ pub const FileSystemRouter = struct { } var vm = globalThis.bunVM(); - var root_dir_path: ZigString.Slice = ZigString.Slice.fromUTF8NeverFree(vm.bundler.fs.top_level_dir); + var root_dir_path: ZigString.Slice = ZigString.Slice.fromUTF8NeverFree(vm.transpiler.fs.top_level_dir); defer root_dir_path.deinit(); var origin_str: ZigString.Slice = .{}; var asset_prefix_slice: ZigString.Slice = .{}; @@ -129,14 +129,14 @@ pub const FileSystemRouter = struct { asset_prefix_slice = asset_prefix.toSlice(globalThis, allocator).clone(allocator) catch unreachable; } - const orig_log = vm.bundler.resolver.log; + const orig_log = vm.transpiler.resolver.log; var log = Log.Log.init(allocator); - vm.bundler.resolver.log = &log; - defer vm.bundler.resolver.log = orig_log; + vm.transpiler.resolver.log = &log; + defer vm.transpiler.resolver.log = orig_log; const path_to_use = (root_dir_path.cloneWithTrailingSlash(allocator) catch unreachable).slice(); - const root_dir_info = vm.bundler.resolver.readDirInfo(path_to_use) catch { + const root_dir_info = vm.transpiler.resolver.readDirInfo(path_to_use) catch { origin_str.deinit(); arena.deinit(); globalThis.allocator().destroy(arena); @@ -148,13 +148,13 @@ pub const FileSystemRouter = struct { return globalThis.throw("Unable to find directory: {s}", .{root_dir_path.slice()}); }; - var router = Router.init(vm.bundler.fs, allocator, .{ + var router = Router.init(vm.transpiler.fs, allocator, .{ .dir = path_to_use, .extensions = if (extensions.items.len > 0) extensions.items else default_extensions, .asset_prefix_path = asset_prefix_slice.slice(), }) catch unreachable; - router.loadRoutes(&log, root_dir_info, Resolver, &vm.bundler.resolver, router.config.dir) catch { + router.loadRoutes(&log, root_dir_info, Resolver, &vm.transpiler.resolver, router.config.dir) catch { origin_str.deinit(); arena.deinit(); globalThis.allocator().destroy(arena); @@ -201,10 +201,10 @@ pub const FileSystemRouter = struct { var vm = globalThis.bunVM(); var path = inputPath; if (comptime Environment.isWindows) { - path = vm.bundler.resolver.fs.normalizeBuf(&win32_normalized_dir_info_cache_buf, path); + path = vm.transpiler.resolver.fs.normalizeBuf(&win32_normalized_dir_info_cache_buf, path); } - const root_dir_info = vm.bundler.resolver.readDirInfo(path) catch { + const root_dir_info = vm.transpiler.resolver.readDirInfo(path) catch { return; }; @@ -216,7 +216,7 @@ pub const FileSystemRouter = struct { if (entry.base()[0] == '.') { continue :outer; } - if (entry.kind(&vm.bundler.fs.fs, false) == .dir) { + if (entry.kind(&vm.transpiler.fs.fs, false) == .dir) { inline for (Router.banned_dirs) |banned_dir| { if (strings.eqlComptime(entry.base(), comptime banned_dir)) { continue :outer; @@ -224,16 +224,16 @@ pub const FileSystemRouter = struct { } var abs_parts_con = [_]string{ entry.dir, entry.base() }; - const full_path = vm.bundler.fs.abs(&abs_parts_con); + const full_path = vm.transpiler.fs.abs(&abs_parts_con); - _ = vm.bundler.resolver.bustDirCache(strings.withoutTrailingSlashWindowsPath(full_path)); + _ = vm.transpiler.resolver.bustDirCache(strings.withoutTrailingSlashWindowsPath(full_path)); bustDirCacheRecursive(this, globalThis, full_path); } } } } - _ = vm.bundler.resolver.bustDirCache(path); + _ = vm.transpiler.resolver.bustDirCache(path); } pub fn bustDirCache(this: *FileSystemRouter, globalThis: *JSC.JSGlobalObject) void { @@ -249,14 +249,14 @@ pub const FileSystemRouter = struct { var allocator = arena.allocator(); var vm = globalThis.bunVM(); - const orig_log = vm.bundler.resolver.log; + const orig_log = vm.transpiler.resolver.log; var log = Log.Log.init(allocator); - vm.bundler.resolver.log = &log; - defer vm.bundler.resolver.log = orig_log; + vm.transpiler.resolver.log = &log; + defer vm.transpiler.resolver.log = orig_log; bustDirCache(this, globalThis); - const root_dir_info = vm.bundler.resolver.readDirInfo(this.router.config.dir) catch { + const root_dir_info = vm.transpiler.resolver.readDirInfo(this.router.config.dir) catch { return globalThis.throwValue(log.toJS(globalThis, globalThis.allocator(), "reading root directory")); } orelse { arena.deinit(); @@ -264,12 +264,12 @@ pub const FileSystemRouter = struct { return globalThis.throw("Unable to find directory: {s}", .{this.router.config.dir}); }; - var router = Router.init(vm.bundler.fs, allocator, .{ + var router = Router.init(vm.transpiler.fs, allocator, .{ .dir = allocator.dupe(u8, this.router.config.dir) catch unreachable, .extensions = allocator.dupe(string, this.router.config.extensions) catch unreachable, .asset_prefix_path = this.router.config.asset_prefix_path, }) catch unreachable; - router.loadRoutes(&log, root_dir_info, Resolver, &vm.bundler.resolver, router.config.dir) catch { + router.loadRoutes(&log, root_dir_info, Resolver, &vm.transpiler.resolver, router.config.dir) catch { arena.deinit(); globalThis.allocator().destroy(arena); return globalThis.throwValue(log.toJS(globalThis, globalThis.allocator(), "loading routes")); @@ -583,7 +583,7 @@ pub const MatchedRoute = struct { // this is kind of bad. we should consider instead a way to inline the contents of the script. if (client_framework_enabled) { JSC.API.Bun.getPublicPath( - Bundler.ClientEntryPoint.generateEntryPointPath( + Transpiler.ClientEntryPoint.generateEntryPointPath( &entry_point_tempbuf, Fs.PathName.init(file_path), ), @@ -605,7 +605,7 @@ pub const MatchedRoute = struct { var writer = stream.writer(); JSC.API.Bun.getPublicPathWithAssetPrefix( this.route.file_path, - if (this.base_dir) |base_dir| base_dir.slice() else VirtualMachine.get().bundler.fs.top_level_dir, + if (this.base_dir) |base_dir| base_dir.slice() else VirtualMachine.get().transpiler.fs.top_level_dir, if (this.origin) |origin| URL.parse(origin.slice()) else URL{}, if (this.asset_prefix) |prefix| prefix.slice() else "", @TypeOf(&writer), diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 8c968ec319..1335e7b7dc 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -16,12 +16,12 @@ const Resolver = @import("../../resolver/resolver.zig"); const ast = @import("../../import_record.zig"); const Sys = @import("../../sys.zig"); -const MacroEntryPoint = bun.bundler.MacroEntryPoint; +const MacroEntryPoint = bun.transpiler.MacroEntryPoint; const logger = bun.logger; const Api = @import("../../api/schema.zig").Api; const options = @import("../../options.zig"); -const Bundler = bun.Bundler; -const ServerEntryPoint = bun.bundler.ServerEntryPoint; +const Transpiler = bun.Transpiler; +const ServerEntryPoint = bun.transpiler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; @@ -32,7 +32,7 @@ const ZigString = bun.JSC.ZigString; const Runtime = @import("../../runtime.zig"); const ImportRecord = ast.ImportRecord; const DotEnv = @import("../../env_loader.zig"); -const ParseResult = bun.bundler.ParseResult; +const ParseResult = bun.transpiler.ParseResult; const PackageJSON = @import("../../resolver/package_json.zig").PackageJSON; const MacroRemap = @import("../../resolver/package_json.zig").MacroMap; const WebCore = bun.JSC.WebCore; @@ -1154,7 +1154,7 @@ pub const ServerConfig = struct { allow_bake_config: bool, ) bun.JSError!void { const vm = arguments.vm; - const env = vm.bundler.env; + const env = vm.transpiler.env; args.* = .{ .address = .{ @@ -1175,7 +1175,7 @@ pub const ServerConfig = struct { args.development = false; } - if (arguments.vm.bundler.options.production) { + if (arguments.vm.transpiler.options.production) { args.development = false; } @@ -1190,7 +1190,7 @@ pub const ServerConfig = struct { } } - if (arguments.vm.bundler.options.transform_options.port) |port| { + if (arguments.vm.transpiler.options.transform_options.port) |port| { break :brk port; } @@ -1198,7 +1198,7 @@ pub const ServerConfig = struct { }; var port = args.address.tcp.port; - if (arguments.vm.bundler.options.transform_options.origin) |origin| { + if (arguments.vm.transpiler.options.transform_options.origin) |origin| { args.base_uri = origin; } @@ -2218,7 +2218,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp .message = std.fmt.allocPrint(allocator, comptime Output.prettyFmt(fmt, false), args) catch unreachable, .router = null, .reason = .fetch_event_handler, - .cwd = VirtualMachine.get().bundler.fs.top_level_dir, + .cwd = VirtualMachine.get().transpiler.fs.top_level_dir, .problems = Api.Problems{ .code = @as(u16, @truncate(@intFromError(err))), .name = @errorName(err), @@ -6754,7 +6754,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp _ = js_printer.printJSON( *js_printer.BufferPrinter, &writer, - bun.Global.BunInfo.generate(*Bundler, &JSC.VirtualMachine.get().bundler, allocator) catch unreachable, + bun.Global.BunInfo.generate(*Transpiler, &JSC.VirtualMachine.get().transpiler, allocator) catch unreachable, &source, .{}, ) catch unreachable; @@ -6780,7 +6780,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp } var ctx = &JSC.VirtualMachine.get().rareData().editor_context; - ctx.autoDetectEditor(JSC.VirtualMachine.get().bundler.env); + ctx.autoDetectEditor(JSC.VirtualMachine.get().transpiler.env); const line: ?string = req.header("editor-line"); const column: ?string = req.header("editor-column"); diff --git a/src/bun.js/config.zig b/src/bun.js/config.zig index d82c3467d2..c8fbeddbd4 100644 --- a/src/bun.js/config.zig +++ b/src/bun.js/config.zig @@ -16,7 +16,7 @@ const ast = @import("../import_record.zig"); const logger = bun.logger; const Api = @import("../api/schema.zig").Api; const options = @import("../options.zig"); -const Bundler = bun.bundler.ServeBundler; +const Transpiler = bun.transpiler.ServeBundler; const js_printer = bun.js_printer; pub const DefaultBunDefines = struct { diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 8705a7b08f..03e24fe55b 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -556,7 +556,7 @@ pub const GarbageCollectionController = struct { } var gc_timer_interval: i32 = 1000; - if (vm.bundler.env.get("BUN_GC_TIMER_INTERVAL")) |timer| { + if (vm.transpiler.env.get("BUN_GC_TIMER_INTERVAL")) |timer| { if (std.fmt.parseInt(i32, timer, 10)) |parsed| { if (parsed > 0) { gc_timer_interval = parsed; @@ -565,7 +565,7 @@ pub const GarbageCollectionController = struct { } this.gc_timer_interval = gc_timer_interval; - this.disabled = vm.bundler.env.has("BUN_GC_TIMER_DISABLE"); + this.disabled = vm.transpiler.env.has("BUN_GC_TIMER_DISABLE"); if (!this.disabled) this.gc_repeating_timer.set(this, onGCRepeatingTimer, gc_timer_interval, gc_timer_interval); @@ -2266,7 +2266,7 @@ pub const EventLoopHandle = union(enum) { pub inline fn createNullDelimitedEnvMap(this: @This(), alloc: Allocator) ![:null]?[*:0]u8 { return switch (this) { - .js => this.js.virtual_machine.bundler.env.map.createNullDelimitedEnvMap(alloc), + .js => this.js.virtual_machine.transpiler.env.map.createNullDelimitedEnvMap(alloc), .mini => this.mini.env.?.map.createNullDelimitedEnvMap(alloc), }; } @@ -2280,14 +2280,14 @@ pub const EventLoopHandle = union(enum) { pub inline fn topLevelDir(this: EventLoopHandle) []const u8 { return switch (this) { - .js => this.js.virtual_machine.bundler.fs.top_level_dir, + .js => this.js.virtual_machine.transpiler.fs.top_level_dir, .mini => this.mini.top_level_dir, }; } pub inline fn env(this: EventLoopHandle) *bun.DotEnv.Loader { return switch (this) { - .js => this.js.virtual_machine.bundler.env, + .js => this.js.virtual_machine.transpiler.env, .mini => this.mini.env.?, }; } diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index f03cfccf57..9418c2fe39 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -20,14 +20,14 @@ const IdentityContext = @import("../identity_context.zig").IdentityContext; const Fs = @import("../fs.zig"); const Resolver = @import("../resolver/resolver.zig"); const ast = @import("../import_record.zig"); -const MacroEntryPoint = bun.bundler.MacroEntryPoint; -const ParseResult = bun.bundler.ParseResult; +const MacroEntryPoint = bun.transpiler.MacroEntryPoint; +const ParseResult = bun.transpiler.ParseResult; const logger = bun.logger; const Api = @import("../api/schema.zig").Api; const options = @import("../options.zig"); -const Bundler = bun.Bundler; -const PluginRunner = bun.bundler.PluginRunner; -const ServerEntryPoint = bun.bundler.ServerEntryPoint; +const Transpiler = bun.Transpiler; +const PluginRunner = bun.transpiler.PluginRunner; +const ServerEntryPoint = bun.transpiler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; @@ -567,7 +567,7 @@ pub export fn Bun__onDidAppendPlugin(jsc_vm: *VirtualMachine, globalObject: *JSG .global_object = globalObject, .allocator = jsc_vm.allocator, }; - jsc_vm.bundler.linker.plugin_runner = &jsc_vm.plugin_runner.?; + jsc_vm.transpiler.linker.plugin_runner = &jsc_vm.plugin_runner.?; } const WindowsOnly = struct { @@ -772,7 +772,7 @@ pub const VirtualMachine = struct { global: *JSGlobalObject, allocator: std.mem.Allocator, has_loaded_constructors: bool = false, - bundler: Bundler, + transpiler: Transpiler, bun_watcher: ImportWatcher = .{ .none = {} }, console: *ConsoleObject, log: *logger.Log, @@ -942,7 +942,7 @@ pub const VirtualMachine = struct { } pub fn getTLSRejectUnauthorized(this: *const VirtualMachine) bool { - return this.default_tls_reject_unauthorized orelse this.bundler.env.getTLSRejectUnauthorized(); + return this.default_tls_reject_unauthorized orelse this.transpiler.env.getTLSRejectUnauthorized(); } pub fn onSubprocessSpawn(this: *VirtualMachine, process: *bun.spawn.Process) void { @@ -955,7 +955,7 @@ pub const VirtualMachine = struct { pub fn getVerboseFetch(this: *VirtualMachine) bun.http.HTTPVerboseLevel { return this.default_verbose_fetch orelse { - if (this.bundler.env.get("BUN_CONFIG_VERBOSE_FETCH")) |verbose_fetch| { + if (this.transpiler.env.get("BUN_CONFIG_VERBOSE_FETCH")) |verbose_fetch| { if (strings.eqlComptime(verbose_fetch, "true") or strings.eqlComptime(verbose_fetch, "1")) { this.default_verbose_fetch = .headers; return .headers; @@ -1127,7 +1127,7 @@ pub const VirtualMachine = struct { } pub fn loadExtraEnvAndSourceCodePrinter(this: *VirtualMachine) void { - var map = this.bundler.env.map; + var map = this.transpiler.env.map; ensureSourceCodePrinter(this); @@ -1251,7 +1251,7 @@ pub const VirtualMachine = struct { } pub inline fn packageManager(this: *VirtualMachine) *PackageManager { - return this.bundler.getPackageManager(); + return this.transpiler.getPackageManager(); } pub fn garbageCollect(this: *const VirtualMachine, sync: bool) usize { @@ -1272,7 +1272,7 @@ pub const VirtualMachine = struct { pub fn reload(this: *VirtualMachine, _: *HotReloader.HotReloadTask) void { Output.debug("Reloading...", .{}); - const should_clear_terminal = !this.bundler.env.hasSetNoClearTerminalOnReload(!Output.enable_ansi_colors); + const should_clear_terminal = !this.transpiler.env.hasSetNoClearTerminalOnReload(!Output.enable_ansi_colors); if (this.hot_reload == .watch) { Output.flush(); bun.reloadProcess( @@ -1710,7 +1710,7 @@ pub const VirtualMachine = struct { vm.allocator = arena.allocator(); vm.arena = &arena; - vm.bundler.configureDefines() catch @panic("Failed to configure defines"); + vm.transpiler.configureDefines() catch @panic("Failed to configure defines"); vm.is_main_thread = false; vm.eventLoop().ensureWaker(); @@ -1828,8 +1828,8 @@ pub const VirtualMachine = struct { ensureSourceCodePrinter(this); } - this.bundler.options.target = .bun_macro; - this.bundler.resolver.caches.fs.use_alternate_source_cache = true; + this.transpiler.options.target = .bun_macro; + this.transpiler.resolver.caches.fs.use_alternate_source_cache = true; this.macro_mode = true; this.event_loop = &this.macro_event_loop; Analytics.Features.macros += 1; @@ -1837,8 +1837,8 @@ pub const VirtualMachine = struct { } pub fn disableMacroMode(this: *VirtualMachine) void { - this.bundler.options.target = .bun; - this.bundler.resolver.caches.fs.use_alternate_source_cache = false; + this.transpiler.options.target = .bun; + this.transpiler.resolver.caches.fs.use_alternate_source_cache = false; this.macro_mode = false; this.event_loop = &this.regular_event_loop; this.transpiler_store.enabled = true; @@ -1878,7 +1878,7 @@ pub const VirtualMachine = struct { const console = try allocator.create(ConsoleObject); console.* = ConsoleObject.init(Output.errorWriter(), Output.writer()); const log = opts.log.?; - const bundler = try Bundler.init( + const transpiler = try Transpiler.init( allocator, log, opts.args, @@ -1891,10 +1891,10 @@ pub const VirtualMachine = struct { .transpiler_store = RuntimeTranspilerStore.init(), .allocator = allocator, .entry_point = ServerEntryPoint{}, - .bundler = bundler, + .transpiler = transpiler, .console = console, .log = log, - .origin = bundler.options.origin, + .origin = transpiler.options.origin, .saved_source_map_table = SavedSourceMap.HashTable.init(bun.default_allocator), .source_mappings = undefined, .macros = MacroMap.init(allocator), @@ -1920,22 +1920,22 @@ pub const VirtualMachine = struct { vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; - vm.bundler.macro_context = null; - vm.bundler.resolver.store_fd = false; - vm.bundler.resolver.prefer_module_field = false; + vm.transpiler.macro_context = null; + vm.transpiler.resolver.store_fd = false; + vm.transpiler.resolver.prefer_module_field = false; - vm.bundler.resolver.onWakePackageManager = .{ + vm.transpiler.resolver.onWakePackageManager = .{ .context = &vm.modules, .handler = ModuleLoader.AsyncModule.Queue.onWakeHandler, .onDependencyError = JSC.ModuleLoader.AsyncModule.Queue.onDependencyError, }; - vm.bundler.resolver.standalone_module_graph = opts.graph.?; + vm.transpiler.resolver.standalone_module_graph = opts.graph.?; // Avoid reading from tsconfig.json & package.json when we're in standalone mode - vm.bundler.configureLinkerWithAutoJSX(false); + vm.transpiler.configureLinkerWithAutoJSX(false); - vm.bundler.macro_context = js_ast.Macro.MacroContext.init(&vm.bundler); + vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler); if (opts.is_main_thread) { VMHolder.main_thread_vm = vm; } @@ -1992,7 +1992,7 @@ pub const VirtualMachine = struct { VMHolder.vm = try allocator.create(VirtualMachine); const console = try allocator.create(ConsoleObject); console.* = ConsoleObject.init(Output.errorWriter(), Output.writer()); - const bundler = try Bundler.init( + const transpiler = try Transpiler.init( allocator, log, try Config.configureTransformOptionsForBunVM(allocator, opts.args), @@ -2007,10 +2007,10 @@ pub const VirtualMachine = struct { .transpiler_store = RuntimeTranspilerStore.init(), .allocator = allocator, .entry_point = ServerEntryPoint{}, - .bundler = bundler, + .transpiler = transpiler, .console = console, .log = log, - .origin = bundler.options.origin, + .origin = transpiler.options.origin, .saved_source_map_table = SavedSourceMap.HashTable.init(bun.default_allocator), .source_mappings = undefined, .macros = MacroMap.init(allocator), @@ -2035,19 +2035,19 @@ pub const VirtualMachine = struct { vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; - vm.bundler.macro_context = null; - vm.bundler.resolver.store_fd = opts.store_fd; - vm.bundler.resolver.prefer_module_field = false; + vm.transpiler.macro_context = null; + vm.transpiler.resolver.store_fd = opts.store_fd; + vm.transpiler.resolver.prefer_module_field = false; - vm.bundler.resolver.onWakePackageManager = .{ + vm.transpiler.resolver.onWakePackageManager = .{ .context = &vm.modules, .handler = ModuleLoader.AsyncModule.Queue.onWakeHandler, .onDependencyError = JSC.ModuleLoader.AsyncModule.Queue.onDependencyError, }; - vm.bundler.configureLinker(); + vm.transpiler.configureLinker(); - vm.bundler.macro_context = js_ast.Macro.MacroContext.init(&vm.bundler); + vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler); vm.global = ZigGlobalObject.create( vm.console, @@ -2123,10 +2123,10 @@ pub const VirtualMachine = struct { } if (this.isInspectorEnabled() and this.debugger.?.mode != .connect) { - this.bundler.options.minify_identifiers = false; - this.bundler.options.minify_syntax = false; - this.bundler.options.minify_whitespace = false; - this.bundler.options.debugger = true; + this.transpiler.options.minify_identifiers = false; + this.transpiler.options.minify_syntax = false; + this.transpiler.options.minify_whitespace = false; + this.transpiler.options.debugger = true; } } @@ -2147,7 +2147,7 @@ pub const VirtualMachine = struct { VMHolder.vm = try allocator.create(VirtualMachine); const console = try allocator.create(ConsoleObject); console.* = ConsoleObject.init(Output.errorWriter(), Output.writer()); - const bundler = try Bundler.init( + const transpiler = try Transpiler.init( allocator, log, try Config.configureTransformOptionsForBunVM(allocator, opts.args), @@ -2160,10 +2160,10 @@ pub const VirtualMachine = struct { .allocator = allocator, .transpiler_store = RuntimeTranspilerStore.init(), .entry_point = ServerEntryPoint{}, - .bundler = bundler, + .transpiler = transpiler, .console = console, .log = log, - .origin = bundler.options.origin, + .origin = transpiler.options.origin, .saved_source_map_table = SavedSourceMap.HashTable.init(bun.default_allocator), .source_mappings = undefined, .macros = MacroMap.init(allocator), @@ -2190,24 +2190,24 @@ pub const VirtualMachine = struct { vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; vm.hot_reload = worker.parent.hot_reload; - vm.bundler.macro_context = null; - vm.bundler.resolver.store_fd = opts.store_fd; - vm.bundler.resolver.prefer_module_field = false; - vm.bundler.resolver.onWakePackageManager = .{ + vm.transpiler.macro_context = null; + vm.transpiler.resolver.store_fd = opts.store_fd; + vm.transpiler.resolver.prefer_module_field = false; + vm.transpiler.resolver.onWakePackageManager = .{ .context = &vm.modules, .handler = ModuleLoader.AsyncModule.Queue.onWakeHandler, .onDependencyError = JSC.ModuleLoader.AsyncModule.Queue.onDependencyError, }; - vm.bundler.resolver.standalone_module_graph = opts.graph; + vm.transpiler.resolver.standalone_module_graph = opts.graph; if (opts.graph == null) { - vm.bundler.configureLinker(); + vm.transpiler.configureLinker(); } else { - vm.bundler.configureLinkerWithAutoJSX(false); + vm.transpiler.configureLinkerWithAutoJSX(false); } vm.smol = opts.smol; - vm.bundler.macro_context = js_ast.Macro.MacroContext.init(&vm.bundler); + vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler); vm.global = ZigGlobalObject.create( vm.console, @@ -2219,7 +2219,7 @@ pub const VirtualMachine = struct { vm.regular_event_loop.global = vm.global; vm.regular_event_loop.virtual_machine = vm; vm.jsc = vm.global.vm(); - vm.bundler.setAllocator(allocator); + vm.transpiler.setAllocator(allocator); vm.body_value_hive_allocator = BodyValueHiveAllocator.init(bun.typedAllocator(JSC.WebCore.Body.Value)); return vm; @@ -2239,7 +2239,7 @@ pub const VirtualMachine = struct { VMHolder.vm = try allocator.create(VirtualMachine); const console = try allocator.create(ConsoleObject); console.* = ConsoleObject.init(Output.errorWriter(), Output.writer()); - const bundler = try Bundler.init( + const transpiler = try Transpiler.init( allocator, log, try Config.configureTransformOptionsForBunVM(allocator, opts.args), @@ -2252,10 +2252,10 @@ pub const VirtualMachine = struct { .transpiler_store = RuntimeTranspilerStore.init(), .allocator = allocator, .entry_point = ServerEntryPoint{}, - .bundler = bundler, + .transpiler = transpiler, .console = console, .log = log, - .origin = bundler.options.origin, + .origin = transpiler.options.origin, .saved_source_map_table = SavedSourceMap.HashTable.init(bun.default_allocator), .source_mappings = undefined, .macros = MacroMap.init(allocator), @@ -2280,19 +2280,19 @@ pub const VirtualMachine = struct { vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; - vm.bundler.macro_context = null; - vm.bundler.resolver.store_fd = opts.store_fd; - vm.bundler.resolver.prefer_module_field = false; + vm.transpiler.macro_context = null; + vm.transpiler.resolver.store_fd = opts.store_fd; + vm.transpiler.resolver.prefer_module_field = false; - vm.bundler.resolver.onWakePackageManager = .{ + vm.transpiler.resolver.onWakePackageManager = .{ .context = &vm.modules, .handler = ModuleLoader.AsyncModule.Queue.onWakeHandler, .onDependencyError = JSC.ModuleLoader.AsyncModule.Queue.onDependencyError, }; - vm.bundler.configureLinker(); + vm.transpiler.configureLinker(); - vm.bundler.macro_context = js_ast.Macro.MacroContext.init(&vm.bundler); + vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler); vm.regular_event_loop.virtual_machine = vm; vm.smol = opts.smol; @@ -2473,7 +2473,7 @@ pub const VirtualMachine = struct { } break :brk .{ - jsc_vm.bundler.options.loaders.get(ext_for_loader) orelse brk2: { + jsc_vm.transpiler.options.loaders.get(ext_for_loader) orelse brk2: { if (strings.eqlLong(specifier, jsc_vm.main, true)) { break :brk2 options.Loader.js; } @@ -2582,7 +2582,7 @@ pub const VirtualMachine = struct { else source else - jsc_vm.bundler.fs.top_level_dir; + jsc_vm.transpiler.fs.top_level_dir; const result: Resolver.Result = try brk: { // TODO: We only want to retry on not found only when the directories we searched for were cached. @@ -2592,7 +2592,7 @@ pub const VirtualMachine = struct { // This cache-bust is disabled when the filesystem is not being used to resolve. var retry_on_not_found = std.fs.path.isAbsolute(source_to_use); while (true) { - break :brk switch (jsc_vm.bundler.resolver.resolveAndAutoInstall( + break :brk switch (jsc_vm.transpiler.resolver.resolveAndAutoInstall( source_to_use, normalized_specifier, if (is_esm) .stmt else .require, @@ -2620,7 +2620,7 @@ pub const VirtualMachine = struct { }; break :name bun.path.joinAbsStringBufZ( - jsc_vm.bundler.fs.top_level_dir, + jsc_vm.transpiler.fs.top_level_dir, &specifier_cache_resolver_buf, &parts, .auto, @@ -2628,7 +2628,7 @@ pub const VirtualMachine = struct { }; // Only re-query if we previously had something cached. - if (jsc_vm.bundler.resolver.bustDirCache(bun.strings.withoutTrailingSlashWindowsPath(buster_name))) { + if (jsc_vm.transpiler.resolver.bustDirCache(bun.strings.withoutTrailingSlashWindowsPath(buster_name))) { continue; } @@ -2639,7 +2639,7 @@ pub const VirtualMachine = struct { }; if (!jsc_vm.macro_mode) { - jsc_vm.has_any_macro_remappings = jsc_vm.has_any_macro_remappings or jsc_vm.bundler.options.macro_remap.count() > 0; + jsc_vm.has_any_macro_remappings = jsc_vm.has_any_macro_remappings or jsc_vm.transpiler.options.macro_remap.count() > 0; } ret.result = result; ret.query_string = query_string; @@ -2738,7 +2738,7 @@ pub const VirtualMachine = struct { } } - if (JSC.HardcodedModule.Aliases.getWithEql(specifier, bun.String.eqlComptime, jsc_vm.bundler.options.target)) |hardcoded| { + if (JSC.HardcodedModule.Aliases.getWithEql(specifier, bun.String.eqlComptime, jsc_vm.transpiler.options.target)) |hardcoded| { // if (hardcoded.tag == .none) { // resolveMaybeNeedsTrailingSlash( // res, @@ -2761,12 +2761,12 @@ pub const VirtualMachine = struct { var log = logger.Log.init(bun.default_allocator); defer log.deinit(); jsc_vm.log = &log; - jsc_vm.bundler.resolver.log = &log; - jsc_vm.bundler.linker.log = &log; + jsc_vm.transpiler.resolver.log = &log; + jsc_vm.transpiler.linker.log = &log; defer { jsc_vm.log = old_log; - jsc_vm.bundler.linker.log = old_log; - jsc_vm.bundler.resolver.log = old_log; + jsc_vm.transpiler.linker.log = old_log; + jsc_vm.transpiler.resolver.log = old_log; } _resolve(&result, specifier_utf8.slice(), normalizeSource(source_utf8.slice()), is_esm, is_a_file_path) catch |err_| { var err = err_; @@ -2984,8 +2984,8 @@ pub const VirtualMachine = struct { defer this.is_in_preload = false; for (this.preload) |preload| { - var result = switch (this.bundler.resolver.resolveAndAutoInstall( - this.bundler.fs.top_level_dir, + var result = switch (this.transpiler.resolver.resolveAndAutoInstall( + this.transpiler.fs.top_level_dir, normalizeSource(preload), .stmt, if (this.standalone_module_graph == null) .read_only else .disable, @@ -3080,7 +3080,7 @@ pub const VirtualMachine = struct { ); this.eventLoop().ensureWaker(); - if (!this.bundler.options.disable_transpilation) { + if (!this.transpiler.options.disable_transpilation) { if (try this.loadPreloads()) |promise| { JSC.JSValue.fromCell(promise).ensureStillAlive(); JSC.JSValue.fromCell(promise).protect(); @@ -3110,7 +3110,7 @@ pub const VirtualMachine = struct { try this.ensureDebugger(true); - if (!this.bundler.options.disable_transpilation) { + if (!this.transpiler.options.disable_transpilation) { if (try this.loadPreloads()) |promise| { JSC.JSValue.fromCell(promise).ensureStillAlive(); this.pending_internal_promise = promise; @@ -3225,7 +3225,7 @@ pub const VirtualMachine = struct { if (!entry_point_entry.found_existing) { var macro_entry_pointer: *MacroEntryPoint = this.allocator.create(MacroEntryPoint) catch unreachable; entry_point_entry.value_ptr.* = macro_entry_pointer; - try macro_entry_pointer.generate(&this.bundler, Fs.PathName.init(entry_path), function_name, hash, specifier); + try macro_entry_pointer.generate(&this.transpiler, Fs.PathName.init(entry_path), function_name, hash, specifier); } const entry_point = entry_point_entry.value_ptr.*; @@ -3314,7 +3314,7 @@ pub const VirtualMachine = struct { } if (exception_list) |list| { - zig_exception.addToErrorList(list, this.bundler.fs.top_level_dir, &this.origin) catch {}; + zig_exception.addToErrorList(list, this.transpiler.fs.top_level_dir, &this.origin) catch {}; } } } @@ -3433,7 +3433,7 @@ pub const VirtualMachine = struct { if (stack.len > 0) { var vm = VirtualMachine.get(); const origin: ?*const URL = if (vm.is_from_devserver) &vm.origin else null; - const dir = vm.bundler.fs.top_level_dir; + const dir = vm.transpiler.fs.top_level_dir; for (stack) |frame| { const file_slice = frame.source_url.toUTF8(bun.default_allocator); @@ -3559,7 +3559,7 @@ pub const VirtualMachine = struct { // defer this so that it copies correctly defer { if (exception_list) |list| { - exception.addToErrorList(list, this.bundler.fs.top_level_dir, &this.origin) catch unreachable; + exception.addToErrorList(list, this.transpiler.fs.top_level_dir, &this.origin) catch unreachable; } } @@ -4365,12 +4365,12 @@ pub const VirtualMachine = struct { /// To satisfy the interface from NewHotReloader() pub fn getLoaders(vm: *VirtualMachine) *bun.options.Loader.HashTable { - return &vm.bundler.options.loaders; + return &vm.transpiler.options.loaders; } /// To satisfy the interface from NewHotReloader() pub fn bustDirCache(vm: *VirtualMachine, path: []const u8) bool { - return vm.bundler.resolver.bustDirCache(path); + return vm.transpiler.resolver.bustDirCache(path); } comptime { @@ -4532,7 +4532,7 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime .{ .watch = Watcher.init( Reloader, reloader, - this.bundler.fs, + this.transpiler.fs, bun.default_allocator, ) catch |err| { bun.handleErrorReturnTrace(err, @errorReturnTrace()); @@ -4542,7 +4542,7 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime .{ .hot = Watcher.init( Reloader, reloader, - this.bundler.fs, + this.transpiler.fs, bun.default_allocator, ) catch |err| { bun.handleErrorReturnTrace(err, @errorReturnTrace()); @@ -4550,24 +4550,24 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime } }; if (reload_immediately) { - this.bundler.resolver.watcher = Resolver.ResolveWatcher(*Watcher, Watcher.onMaybeWatchDirectory).init(this.bun_watcher.watch); + this.transpiler.resolver.watcher = Resolver.ResolveWatcher(*Watcher, Watcher.onMaybeWatchDirectory).init(this.bun_watcher.watch); } else { - this.bundler.resolver.watcher = Resolver.ResolveWatcher(*Watcher, Watcher.onMaybeWatchDirectory).init(this.bun_watcher.hot); + this.transpiler.resolver.watcher = Resolver.ResolveWatcher(*Watcher, Watcher.onMaybeWatchDirectory).init(this.bun_watcher.hot); } } else { this.bun_watcher = Watcher.init( Reloader, reloader, - this.bundler.fs, + this.transpiler.fs, bun.default_allocator, ) catch |err| { bun.handleErrorReturnTrace(err, @errorReturnTrace()); Output.panic("Failed to enable File Watcher: {s}", .{@errorName(err)}); }; - this.bundler.resolver.watcher = Resolver.ResolveWatcher(*Watcher, Watcher.onMaybeWatchDirectory).init(this.bun_watcher.?); + this.transpiler.resolver.watcher = Resolver.ResolveWatcher(*Watcher, Watcher.onMaybeWatchDirectory).init(this.bun_watcher.?); } - clear_screen = !this.bundler.env.hasSetNoClearTerminalOnReload(!Output.enable_ansi_colors); + clear_screen = !this.transpiler.env.hasSetNoClearTerminalOnReload(!Output.enable_ansi_colors); reloader.getContext().start() catch @panic("Failed to start File Watcher"); } diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 3684ee1bb0..a16a51a4a4 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -19,14 +19,14 @@ const IdentityContext = @import("../identity_context.zig").IdentityContext; const Fs = @import("../fs.zig"); const Resolver = @import("../resolver/resolver.zig"); const ast = @import("../import_record.zig"); -const MacroEntryPoint = bun.bundler.MacroEntryPoint; -const ParseResult = bun.bundler.ParseResult; +const MacroEntryPoint = bun.transpiler.MacroEntryPoint; +const ParseResult = bun.transpiler.ParseResult; const logger = bun.logger; const Api = @import("../api/schema.zig").Api; const options = @import("../options.zig"); -const Bundler = bun.Bundler; -const PluginRunner = bun.bundler.PluginRunner; -const ServerEntryPoint = bun.bundler.ServerEntryPoint; +const Transpiler = bun.Transpiler; +const PluginRunner = bun.transpiler.PluginRunner; +const ServerEntryPoint = bun.transpiler.ServerEntryPoint; const js_printer = bun.js_printer; const js_parser = bun.js_parser; const js_ast = bun.JSAst; @@ -262,7 +262,7 @@ pub const RuntimeTranspilerStore = struct { .referrer = bun.default_allocator.dupe(u8, referrer) catch unreachable, .vm = vm, .log = logger.Log.init(bun.default_allocator), - .loader = vm.bundler.options.loader(owned_path.name.ext), + .loader = vm.transpiler.options.loader(owned_path.name.ext), .promise = JSC.Strong.create(JSC.JSValue.fromCell(promise), globalObject), .poll_ref = .{}, .fetcher = TranspilerJob.Fetcher{ @@ -347,7 +347,7 @@ pub const RuntimeTranspilerStore = struct { if (resolved_source.is_commonjs_module) { const actual_package_json: *PackageJSON = brk2: { // this should already be cached virtually always so it's fine to do this - const dir_info = (vm.bundler.resolver.readDirInfo(this.path.name.dir) catch null) orelse + const dir_info = (vm.transpiler.resolver.readDirInfo(this.path.name.dir) catch null) orelse break :brk .javascript; break :brk2 dir_info.package_json orelse dir_info.enclosing_package_json; @@ -413,13 +413,13 @@ pub const RuntimeTranspilerStore = struct { }; var vm = this.vm; - var bundler: bun.Bundler = undefined; - bundler = vm.bundler; - bundler.setAllocator(allocator); - bundler.setLog(&this.log); - bundler.resolver.opts = bundler.options; - bundler.macro_context = null; - bundler.linker.resolver = &bundler.resolver; + var transpiler: bun.Transpiler = undefined; + transpiler = vm.transpiler; + transpiler.setAllocator(allocator); + transpiler.setLog(&this.log); + transpiler.resolver.opts = transpiler.options; + transpiler.macro_context = null; + transpiler.linker.resolver = &transpiler.resolver; var fd: ?StoredFileDescriptorType = null; var package_json: ?*PackageJSON = null; @@ -442,7 +442,7 @@ pub const RuntimeTranspilerStore = struct { const macro_remappings = if (vm.macro_mode or !vm.has_any_macro_remappings or is_node_override) MacroRemap{} else - bundler.options.macro_remap; + transpiler.options.macro_remap; var fallback_source: logger.Source = undefined; @@ -459,7 +459,7 @@ pub const RuntimeTranspilerStore = struct { vm.main_hash == hash and strings.eqlLong(vm.main, path.text, false); - var parse_options = Bundler.ParseOptions{ + var parse_options = Transpiler.ParseOptions{ .allocator = allocator, .path = path, .loader = loader, @@ -468,12 +468,12 @@ pub const RuntimeTranspilerStore = struct { .file_fd_ptr = &input_file_fd, .file_hash = hash, .macro_remappings = macro_remappings, - .jsx = bundler.options.jsx, - .emit_decorator_metadata = bundler.options.emit_decorator_metadata, + .jsx = transpiler.options.jsx, + .emit_decorator_metadata = transpiler.options.emit_decorator_metadata, .virtual_source = null, .dont_bundle_twice = true, .allow_commonjs = true, - .inject_jest_globals = bundler.options.rewrite_jest_for_tests and is_main, + .inject_jest_globals = transpiler.options.rewrite_jest_for_tests and is_main, .set_breakpoint_on_first_line = vm.debugger != null and vm.debugger.?.set_breakpoint_on_first_line and is_main and @@ -498,7 +498,7 @@ pub const RuntimeTranspilerStore = struct { } } - var parse_result: bun.bundler.ParseResult = bundler.parseMaybeReturnFileOnlyAllowSharedBuffer( + var parse_result: bun.transpiler.ParseResult = transpiler.parseMaybeReturnFileOnlyAllowSharedBuffer( parse_options, null, false, @@ -596,14 +596,14 @@ pub const RuntimeTranspilerStore = struct { for (parse_result.ast.import_records.slice()) |*import_record_| { var import_record: *bun.ImportRecord = import_record_; - if (JSC.HardcodedModule.Aliases.get(import_record.path.text, bundler.options.target)) |replacement| { + if (JSC.HardcodedModule.Aliases.get(import_record.path.text, transpiler.options.target)) |replacement| { import_record.path.text = replacement.path; import_record.tag = replacement.tag; import_record.is_external_without_side_effects = true; continue; } - if (bundler.options.rewrite_jest_for_tests) { + if (transpiler.options.rewrite_jest_for_tests) { if (strings.eqlComptime( import_record.path.text, "@jest/globals", @@ -643,7 +643,7 @@ pub const RuntimeTranspilerStore = struct { { var mapper = vm.sourceMapHandler(&printer); defer source_code_printer.?.* = printer; - _ = bundler.printWithSourceMap( + _ = transpiler.printWithSourceMap( parse_result, @TypeOf(&printer), &printer, @@ -1381,20 +1381,20 @@ pub const ModuleLoader = struct { const specifier = this.specifier; const old_log = jsc_vm.log; - jsc_vm.bundler.linker.log = log; - jsc_vm.bundler.log = log; - jsc_vm.bundler.resolver.log = log; + jsc_vm.transpiler.linker.log = log; + jsc_vm.transpiler.log = log; + jsc_vm.transpiler.resolver.log = log; jsc_vm.packageManager().log = log; defer { - jsc_vm.bundler.linker.log = old_log; - jsc_vm.bundler.log = old_log; - jsc_vm.bundler.resolver.log = old_log; + jsc_vm.transpiler.linker.log = old_log; + jsc_vm.transpiler.log = old_log; + jsc_vm.transpiler.resolver.log = old_log; jsc_vm.packageManager().log = old_log; } // We _must_ link because: // - node_modules bundle won't be properly - try jsc_vm.bundler.linker.link( + try jsc_vm.transpiler.linker.link( path, &parse_result, jsc_vm.origin, @@ -1410,7 +1410,7 @@ pub const ModuleLoader = struct { { var mapper = jsc_vm.sourceMapHandler(&printer); defer VirtualMachine.source_code_printer.?.* = printer; - _ = try jsc_vm.bundler.printWithSourceMap( + _ = try jsc_vm.transpiler.printWithSourceMap( parse_result, @TypeOf(&printer), &printer, @@ -1480,7 +1480,7 @@ pub const ModuleLoader = struct { var jsc_vm = global.bunVM(); const filename = str.toUTF8(jsc_vm.allocator); defer filename.deinit(); - const loader = jsc_vm.bundler.options.loader(Fs.PathName.init(filename.slice()).ext).toAPI(); + const loader = jsc_vm.transpiler.options.loader(Fs.PathName.init(filename.slice()).ext).toAPI(); if (loader == .file) { return Api.Loader.js; } @@ -1508,7 +1508,7 @@ pub const ModuleLoader = struct { switch (loader) { .js, .jsx, .ts, .tsx, .json, .toml, .text => { jsc_vm.transpiled_count += 1; - jsc_vm.bundler.resetStore(); + jsc_vm.transpiler.resetStore(); const hash = JSC.GenericWatcher.getHash(path.text); const is_main = jsc_vm.main.len == path.text.len and jsc_vm.main_hash == hash and @@ -1570,19 +1570,19 @@ pub const ModuleLoader = struct { .sourcemap_allocator = bun.default_allocator, }; - const old = jsc_vm.bundler.log; - jsc_vm.bundler.log = log; - jsc_vm.bundler.linker.log = log; - jsc_vm.bundler.resolver.log = log; - if (jsc_vm.bundler.resolver.package_manager) |pm| { + const old = jsc_vm.transpiler.log; + jsc_vm.transpiler.log = log; + jsc_vm.transpiler.linker.log = log; + jsc_vm.transpiler.resolver.log = log; + if (jsc_vm.transpiler.resolver.package_manager) |pm| { pm.log = log; } defer { - jsc_vm.bundler.log = old; - jsc_vm.bundler.linker.log = old; - jsc_vm.bundler.resolver.log = old; - if (jsc_vm.bundler.resolver.package_manager) |pm| { + jsc_vm.transpiler.log = old; + jsc_vm.transpiler.linker.log = old; + jsc_vm.transpiler.resolver.log = old; + if (jsc_vm.transpiler.resolver.package_manager) |pm| { pm.log = old; } } @@ -1593,7 +1593,7 @@ pub const ModuleLoader = struct { const macro_remappings = if (jsc_vm.macro_mode or !jsc_vm.has_any_macro_remappings or is_node_override) MacroRemap{} else - jsc_vm.bundler.options.macro_remap; + jsc_vm.transpiler.options.macro_remap; var fallback_source: logger.Source = undefined; @@ -1605,7 +1605,7 @@ pub const ModuleLoader = struct { var should_close_input_file_fd = fd == null; var input_file_fd: StoredFileDescriptorType = bun.invalid_fd; - var parse_options = Bundler.ParseOptions{ + var parse_options = Transpiler.ParseOptions{ .allocator = allocator, .path = path, .loader = loader, @@ -1614,12 +1614,12 @@ pub const ModuleLoader = struct { .file_fd_ptr = &input_file_fd, .file_hash = hash, .macro_remappings = macro_remappings, - .jsx = jsc_vm.bundler.options.jsx, - .emit_decorator_metadata = jsc_vm.bundler.options.emit_decorator_metadata, + .jsx = jsc_vm.transpiler.options.jsx, + .emit_decorator_metadata = jsc_vm.transpiler.options.emit_decorator_metadata, .virtual_source = virtual_source, .dont_bundle_twice = true, .allow_commonjs = true, - .inject_jest_globals = jsc_vm.bundler.options.rewrite_jest_for_tests and is_main, + .inject_jest_globals = jsc_vm.transpiler.options.rewrite_jest_for_tests and is_main, .keep_json_and_toml_as_one_statement = true, .allow_bytecode_cache = true, .set_breakpoint_on_first_line = is_main and @@ -1653,7 +1653,7 @@ pub const ModuleLoader = struct { JSC.VM.ReleaseHeapAccess{ .vm = jsc_vm.jsc, .needs_to_release = false }; defer heap_access.acquire(); - break :brk jsc_vm.bundler.parseMaybeReturnFileOnly( + break :brk jsc_vm.transpiler.parseMaybeReturnFileOnly( parse_options, null, return_file_only, @@ -1720,7 +1720,7 @@ pub const ModuleLoader = struct { } } - if (jsc_vm.bundler.log.errors > 0) { + if (jsc_vm.transpiler.log.errors > 0) { give_back_arena = false; return error.ParseError; } @@ -1817,7 +1817,7 @@ pub const ModuleLoader = struct { if (entry.metadata.module_type == .cjs and parse_result.source.path.isFile()) { const actual_package_json: *PackageJSON = package_json orelse brk2: { // this should already be cached virtually always so it's fine to do this - const dir_info = (jsc_vm.bundler.resolver.readDirInfo(parse_result.source.path.name.dir) catch null) orelse + const dir_info = (jsc_vm.transpiler.resolver.readDirInfo(parse_result.source.path.name.dir) catch null) orelse break :brk .javascript; break :brk2 dir_info.package_json orelse dir_info.enclosing_package_json; @@ -1833,11 +1833,11 @@ pub const ModuleLoader = struct { }; } - const start_count = jsc_vm.bundler.linker.import_counter; + const start_count = jsc_vm.transpiler.linker.import_counter; // We _must_ link because: // - node_modules bundle won't be properly - try jsc_vm.bundler.linker.link( + try jsc_vm.transpiler.linker.link( path, &parse_result, jsc_vm.origin, @@ -1853,8 +1853,8 @@ pub const ModuleLoader = struct { if (parse_result.source.contents_is_recycled) { // this shared buffer is about to become owned by the AsyncModule struct - jsc_vm.bundler.resolver.caches.fs.resetSharedBuffer( - jsc_vm.bundler.resolver.caches.fs.sharedBuffer(), + jsc_vm.transpiler.resolver.caches.fs.resetSharedBuffer( + jsc_vm.transpiler.resolver.caches.fs.sharedBuffer(), ); } @@ -1878,8 +1878,8 @@ pub const ModuleLoader = struct { } if (!jsc_vm.macro_mode) - jsc_vm.resolved_count += jsc_vm.bundler.linker.import_counter - start_count; - jsc_vm.bundler.linker.import_counter = 0; + jsc_vm.resolved_count += jsc_vm.transpiler.linker.import_counter - start_count; + jsc_vm.transpiler.linker.import_counter = 0; var printer = source_code_printer.*; printer.ctx.reset(); @@ -1887,7 +1887,7 @@ pub const ModuleLoader = struct { _ = brk: { var mapper = jsc_vm.sourceMapHandler(&printer); - break :brk try jsc_vm.bundler.printWithSourceMap( + break :brk try jsc_vm.transpiler.printWithSourceMap( parse_result, @TypeOf(&printer), &printer, @@ -1917,7 +1917,7 @@ pub const ModuleLoader = struct { if (parse_result.ast.exports_kind == .cjs and parse_result.source.path.isFile()) { const actual_package_json: *PackageJSON = package_json orelse brk2: { // this should already be cached virtually always so it's fine to do this - const dir_info = (jsc_vm.bundler.resolver.readDirInfo(parse_result.source.path.name.dirOrDot()) catch null) orelse + const dir_info = (jsc_vm.transpiler.resolver.readDirInfo(parse_result.source.path.name.dirOrDot()) catch null) orelse break :brk .javascript; break :brk2 dir_info.package_json orelse dir_info.enclosing_package_json; @@ -1966,7 +1966,7 @@ pub const ModuleLoader = struct { // } // } - // var parse_options = Bundler.ParseOptions{ + // var parse_options = Transpiler.ParseOptions{ // .allocator = allocator, // .path = path, // .loader = loader, @@ -1974,10 +1974,10 @@ pub const ModuleLoader = struct { // .file_descriptor = fd, // .file_hash = hash, // .macro_remappings = MacroRemap{}, - // .jsx = jsc_vm.bundler.options.jsx, + // .jsx = jsc_vm.transpiler.options.jsx, // }; - // var parse_result = jsc_vm.bundler.parse( + // var parse_result = jsc_vm.transpiler.parse( // parse_options, // null, // ) orelse { @@ -2193,7 +2193,7 @@ pub const ModuleLoader = struct { ret: *ErrorableResolvedSource, ) bool { JSC.markBinding(@src()); - var log = logger.Log.init(jsc_vm.bundler.allocator); + var log = logger.Log.init(jsc_vm.transpiler.allocator); defer log.deinit(); if (ModuleLoader.fetchBuiltinModule( @@ -2224,7 +2224,7 @@ pub const ModuleLoader = struct { allow_promise: bool, ) ?*anyopaque { JSC.markBinding(@src()); - var log = logger.Log.init(jsc_vm.bundler.allocator); + var log = logger.Log.init(jsc_vm.transpiler.allocator); defer log.deinit(); var _specifier = specifier_ptr.toUTF8(jsc_vm.allocator); @@ -2250,7 +2250,7 @@ pub const ModuleLoader = struct { // Deliberately optional. // The concurrent one only handles javascript-like loaders right now. - var loader: ?options.Loader = jsc_vm.bundler.options.loaders.get(path.name.ext); + var loader: ?options.Loader = jsc_vm.transpiler.options.loaders.get(path.name.ext); if (jsc_vm.module_loader.eval_source) |eval_source| { if (strings.endsWithComptime(specifier, bun.pathLiteral("/[eval]"))) { @@ -2277,7 +2277,7 @@ pub const ModuleLoader = struct { path = current_path; } - loader = jsc_vm.bundler.options.loaders.get(current_path.name.ext) orelse .tsx; + loader = jsc_vm.transpiler.options.loaders.get(current_path.name.ext) orelse .tsx; } else { loader = .tsx; } @@ -2617,7 +2617,7 @@ pub const ModuleLoader = struct { const loader = if (loader_ != ._none) options.Loader.fromAPI(loader_) else - jsc_vm.bundler.options.loaders.get(path.name.ext) orelse brk: { + jsc_vm.transpiler.options.loaders.get(path.name.ext) orelse brk: { if (strings.eqlLong(specifier, jsc_vm.main, true)) { break :brk options.Loader.js; } diff --git a/src/bun.js/node/path_watcher.zig b/src/bun.js/node/path_watcher.zig index 4d1455fdc7..c5045fc542 100644 --- a/src/bun.js/node/path_watcher.zig +++ b/src/bun.js/node/path_watcher.zig @@ -151,7 +151,7 @@ pub const PathWatcherManager = struct { .main_watcher = try Watcher.init( PathWatcherManager, this, - vm.bundler.fs, + vm.transpiler.fs, bun.default_allocator, ), .vm = vm, diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index 4a4b26b274..fda45fe94b 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -2092,7 +2092,7 @@ pub const Process = struct { // When we update the cwd from JS, we have to update the bundler's version as well // However, this might be called many times in a row, so we use a pre-allocated buffer // that way we don't have to worry about garbage collector - const fs = JSC.VirtualMachine.get().bundler.fs; + const fs = JSC.VirtualMachine.get().transpiler.fs; const into_cwd_buf = switch (bun.sys.getcwd(&buf)) { .result => |r| r, .err => |err| { diff --git a/src/bun.js/test/snapshot.zig b/src/bun.js/test/snapshot.zig index 99eb561d40..b9380d4f68 100644 --- a/src/bun.js/test/snapshot.zig +++ b/src/bun.js/test/snapshot.zig @@ -115,7 +115,7 @@ pub const Snapshots = struct { if (this.file_buf.items.len == 0) return; const vm = VirtualMachine.get(); - const opts = js_parser.Parser.Options.init(vm.bundler.options.jsx, .js); + const opts = js_parser.Parser.Options.init(vm.transpiler.options.jsx, .js); var temp_log = logger.Log.init(this.allocator); const test_file = Jest.runner.?.files.get(file.id); @@ -141,7 +141,7 @@ pub const Snapshots = struct { opts, &temp_log, &source, - vm.bundler.options.define, + vm.transpiler.options.define, this.allocator, ); @@ -224,7 +224,7 @@ pub const Snapshots = struct { var success = true; const vm = VirtualMachine.get(); - const opts = js_parser.Parser.Options.init(vm.bundler.options.jsx, .js); + const opts = js_parser.Parser.Options.init(vm.transpiler.options.jsx, .js); for (this.inline_snapshots_to_write.keys(), this.inline_snapshots_to_write.values()) |file_id, *ils_info| { _ = arena_backing.reset(.retain_capacity); @@ -311,7 +311,7 @@ pub const Snapshots = struct { } try lexer.next(); var parser: bun.js_parser.TSXParser = undefined; - try bun.js_parser.TSXParser.init(arena, &log, &source, vm.bundler.options.define, lexer, opts, &parser); + try bun.js_parser.TSXParser.init(arena, &log, &source, vm.transpiler.options.define, lexer, opts, &parser); try parser.lexer.expect(.t_open_paren); const after_open_paren_loc = parser.lexer.loc().start; diff --git a/src/bun.js/web_worker.zig b/src/bun.js/web_worker.zig index b91b917496..6fcb6eed62 100644 --- a/src/bun.js/web_worker.zig +++ b/src/bun.js/web_worker.zig @@ -152,7 +152,7 @@ pub const WebWorker = struct { } } - var resolved_entry_point: bun.resolver.Result = parent.bundler.resolveEntryPoint(str) catch { + var resolved_entry_point: bun.resolver.Result = parent.transpiler.resolveEntryPoint(str) catch { const out = logger.toJS(parent.global, bun.default_allocator, "Error resolving Worker entry point").toBunString(parent.global); error_message.* = out; return null; @@ -186,10 +186,10 @@ pub const WebWorker = struct { log("[{d}] WebWorker.create", .{this_context_id}); var spec_slice = specifier_str.toUTF8(bun.default_allocator); defer spec_slice.deinit(); - const prev_log = parent.bundler.log; + const prev_log = parent.transpiler.log; var temp_log = bun.logger.Log.init(bun.default_allocator); - parent.bundler.setLog(&temp_log); - defer parent.bundler.setLog(prev_log); + parent.transpiler.setLog(&temp_log); + defer parent.transpiler.setLog(prev_log); defer temp_log.deinit(); const preload_modules = if (preload_modules_ptr) |ptr| @@ -226,7 +226,7 @@ pub const WebWorker = struct { .execution_context_id = this_context_id, .mini = mini, .specifier = bun.default_allocator.dupe(u8, path) catch bun.outOfMemory(), - .store_fd = parent.bundler.resolver.store_fd, + .store_fd = parent.transpiler.resolver.store_fd, .name = brk: { if (!name_str.isEmpty()) { break :brk std.fmt.allocPrintZ(bun.default_allocator, "{}", .{name_str}) catch bun.outOfMemory(); @@ -274,14 +274,14 @@ pub const WebWorker = struct { this.arena = try bun.MimallocArena.init(); var vm = try JSC.VirtualMachine.initWorker(this, .{ .allocator = this.arena.?.allocator(), - .args = this.parent.bundler.options.transform_options, + .args = this.parent.transpiler.options.transform_options, .store_fd = this.store_fd, .graph = this.parent.standalone_module_graph, }); vm.allocator = this.arena.?.allocator(); vm.arena = &this.arena.?; - var b = &vm.bundler; + var b = &vm.transpiler; b.configureDefines() catch { this.flushLogs(); @@ -292,12 +292,12 @@ pub const WebWorker = struct { // TODO: we may have to clone other parts of vm state. this will be more // important when implementing vm.deinit() const map = try vm.allocator.create(bun.DotEnv.Map); - map.* = try vm.bundler.env.map.cloneWithAllocator(vm.allocator); + map.* = try vm.transpiler.env.map.cloneWithAllocator(vm.allocator); const loader = try vm.allocator.create(bun.DotEnv.Loader); loader.* = bun.DotEnv.Loader.init(map, vm.allocator); - vm.bundler.env = loader; + vm.transpiler.env = loader; vm.loadExtraEnvAndSourceCodePrinter(); vm.is_main_thread = false; diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 644c853f4c..76e6bd4993 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -1889,10 +1889,10 @@ pub const Fetch = struct { var proxy: ?ZigURL = null; if (fetch_options.proxy) |proxy_opt| { if (!proxy_opt.isEmpty()) { //if is empty just ignore proxy - proxy = fetch_options.proxy orelse jsc_vm.bundler.env.getHttpProxy(fetch_options.url); + proxy = fetch_options.proxy orelse jsc_vm.transpiler.env.getHttpProxy(fetch_options.url); } } else { - proxy = jsc_vm.bundler.env.getHttpProxy(fetch_options.url); + proxy = jsc_vm.transpiler.env.getHttpProxy(fetch_options.url); } if (fetch_tasklet.check_server_identity.has() and fetch_tasklet.reject_unauthorized) { @@ -3008,7 +3008,7 @@ pub const Fetch = struct { var cwd_buf: bun.PathBuffer = undefined; const cwd = if (Environment.isWindows) (bun.getcwd(&cwd_buf) catch |err| { return globalThis.throwError(err, "Failed to resolve file url"); - }) else globalThis.bunVM().bundler.fs.top_level_dir; + }) else globalThis.bunVM().transpiler.fs.top_level_dir; const fullpath = bun.path.joinAbsStringBuf( cwd, diff --git a/src/bun.zig b/src/bun.zig index efac52b91b..9c37bf8854 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -1331,8 +1331,8 @@ pub const PackageManager = install.PackageManager; pub const RunCommand = @import("./cli/run_command.zig").RunCommand; pub const fs = @import("./fs.zig"); -pub const Bundler = bundler.Bundler; -pub const bundler = @import("./bundler.zig"); +pub const Transpiler = transpiler.Transpiler; +pub const transpiler = @import("./transpiler.zig"); pub const which = @import("./which.zig").which; pub const js_parser = @import("./js_parser.zig"); pub const js_printer = @import("./js_printer.zig"); diff --git a/src/bun_js.zig b/src/bun_js.zig index 602b010af6..7545b09e46 100644 --- a/src/bun_js.zig +++ b/src/bun_js.zig @@ -24,7 +24,7 @@ const Api = @import("api/schema.zig").Api; const resolve_path = @import("./resolver/resolve_path.zig"); const configureTransformOptionsForBun = @import("./bun.js/config.zig").configureTransformOptionsForBun; const Command = @import("cli.zig").Command; -const bundler = bun.bundler; +const bundler = bun.transpiler; const DotEnv = @import("env_loader.zig"); const which = @import("which.zig").which; const JSC = bun.JSC; @@ -72,7 +72,7 @@ pub const Run = struct { }; var vm = run.vm; - var b = &vm.bundler; + var b = &vm.transpiler; vm.preload = ctx.preloads; vm.argv = ctx.passthrough; vm.arena = &run.arena; @@ -156,7 +156,7 @@ pub const Run = struct { @setCold(true); // this is a hack: make dummy bundler so we can use its `.runEnvLoader()` function to populate environment variables probably should split out the functionality - var bundle = try bun.Bundler.init( + var bundle = try bun.Transpiler.init( ctx.allocator, ctx.log, try @import("./bun.js/config.zig").configureTransformOptionsForBunVM(ctx.allocator, ctx.args), @@ -208,7 +208,7 @@ pub const Run = struct { }; var vm = run.vm; - var b = &vm.bundler; + var b = &vm.transpiler; vm.preload = ctx.preloads; vm.argv = ctx.passthrough; vm.arena = &run.arena; @@ -264,13 +264,13 @@ pub const Run = struct { JSC.VirtualMachine.is_main_thread_vm = true; // Allow setting a custom timezone - if (vm.bundler.env.get("TZ")) |tz| { + if (vm.transpiler.env.get("TZ")) |tz| { if (tz.len > 0) { _ = vm.global.setTimeZone(&JSC.ZigString.init(tz)); } } - vm.bundler.env.loadTracy(); + vm.transpiler.env.loadTracy(); doPreconnect(ctx.runtime_options.preconnect); @@ -300,8 +300,8 @@ pub const Run = struct { else => {}, } - if (strings.eqlComptime(this.entry_path, ".") and vm.bundler.fs.top_level_dir.len > 0) { - this.entry_path = vm.bundler.fs.top_level_dir; + if (strings.eqlComptime(this.entry_path, ".") and vm.transpiler.fs.top_level_dir.len > 0) { + this.entry_path = vm.transpiler.fs.top_level_dir; } if (vm.loadEntryPoint(this.entry_path)) |promise| { diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index 0bc292fad1..8f47276d6e 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -1,4 +1,4 @@ -// This is Bun's JavaScript/TypeScript bundler +// This is Bun's JavaScript/TypeScript transpiler // // A lot of the implementation is based on the Go implementation of esbuild. Thank you Evan Wallace. // @@ -41,7 +41,7 @@ // // make mimalloc-debug // -const Bundler = bun.Bundler; +const Transpiler = bun.Transpiler; const bun = @import("root").bun; const string = bun.string; const Output = bun.Output; @@ -100,7 +100,6 @@ const Linker = linker.Linker; const Resolver = _resolver.Resolver; const TOML = @import("../toml/toml_parser.zig").TOML; const EntryPoints = @import("./entry_points.zig"); -const ThisBundler = @import("../bundler.zig").Bundler; const Dependency = js_ast.Dependency; const JSAst = js_ast.BundledAst; const Loader = options.Loader; @@ -134,7 +133,7 @@ const debug_deferred = bun.Output.scoped(.BUNDLER_DEFERRED, true); const logPartDependencyTree = Output.scoped(.part_dep_tree, false); fn tracer(comptime src: std.builtin.SourceLocation, comptime name: [:0]const u8) bun.tracy.Ctx { - return bun.tracy.traceNamed(src, "Bundler." ++ name); + return bun.tracy.traceNamed(src, "Transpiler." ++ name); } pub const ThreadPool = struct { @@ -264,7 +263,7 @@ pub const ThreadPool = struct { log: *Logger.Log, estimated_input_lines_of_code: usize = 0, macro_context: js_ast.Macro.MacroContext, - bundler: Bundler = undefined, + transpiler: Transpiler = undefined, }; pub fn init(worker: *Worker, v2: *BundleV2) void { @@ -292,18 +291,18 @@ pub const ThreadPool = struct { }; this.data.log.* = Logger.Log.init(allocator); this.ctx = ctx; - this.data.bundler = ctx.bundler.*; - this.data.bundler.setLog(this.data.log); - this.data.bundler.setAllocator(allocator); - this.data.bundler.linker.resolver = &this.data.bundler.resolver; - this.data.bundler.macro_context = js_ast.Macro.MacroContext.init(&this.data.bundler); - this.data.macro_context = this.data.bundler.macro_context.?; + this.data.transpiler = ctx.transpiler.*; + this.data.transpiler.setLog(this.data.log); + this.data.transpiler.setAllocator(allocator); + this.data.transpiler.linker.resolver = &this.data.transpiler.resolver; + this.data.transpiler.macro_context = js_ast.Macro.MacroContext.init(&this.data.transpiler); + this.data.macro_context = this.data.transpiler.macro_context.?; this.temporary_arena = bun.ArenaAllocator.init(this.allocator); this.stmt_list = LinkerContext.StmtList.init(this.allocator); const CacheSet = @import("../cache.zig"); - this.data.bundler.resolver.caches = CacheSet.Set.init(this.allocator); + this.data.transpiler.resolver.caches = CacheSet.Set.init(this.allocator); debug("Worker.create()", .{}); } @@ -367,12 +366,12 @@ fn fmtEscapedNamespace(slice: []const u8, comptime fmt: []const u8, _: std.fmt.F } pub const BundleV2 = struct { - bundler: *Bundler, + transpiler: *Transpiler, /// When Server Component is enabled, this is used for the client bundles - /// and `bundler` is used for the server bundles. - client_bundler: *Bundler, + /// and `transpiler` is used for the server bundles. + client_bundler: *Transpiler, /// See bake.Framework.ServerComponents.separate_ssr_graph - ssr_bundler: *Bundler, + ssr_bundler: *Transpiler, /// When Bun Bake is used, the resolved framework is passed here framework: ?bake.Framework, graph: Graph, @@ -397,7 +396,7 @@ pub const BundleV2 = struct { drain_defer_task: DeferredBatchTask = .{}, - /// Set true by DevServer. Currently every usage of the bundler (Bun.build + /// Set true by DevServer. Currently every usage of the transpiler (Bun.build /// and `bun build` cli) runs at the top of an event loop. When this is /// true, a callback is executed after all work is complete. asynchronous: bool = false, @@ -405,8 +404,8 @@ pub const BundleV2 = struct { const BakeOptions = struct { framework: bake.Framework, - client_bundler: *Bundler, - ssr_bundler: *Bundler, + client_bundler: *Transpiler, + ssr_bundler: *Transpiler, plugins: ?*JSC.API.JSBundler.Plugin, }; @@ -427,20 +426,20 @@ pub const BundleV2 = struct { // running the plugins. .js => |jsc_event_loop| return jsc_event_loop, // The CLI currently has no JSC event loop; for now, no plugin support - .mini => @panic("No JavaScript event loop for bundler plugins to run on"), + .mini => @panic("No JavaScript event loop for transpiler plugins to run on"), } } - /// Most of the time, accessing .bundler directly is OK. This is only + /// Most of the time, accessing .transpiler directly is OK. This is only /// needed when it is important to distinct between client and server /// /// Note that .log, .allocator, and other things are shared - /// between the three bundler configurations - pub inline fn bundlerForTarget(this: *BundleV2, target: options.Target) *Bundler { - return if (!this.bundler.options.server_components) - this.bundler + /// between the three transpiler configurations + pub inline fn bundlerForTarget(this: *BundleV2, target: options.Target) *Transpiler { + return if (!this.transpiler.options.server_components) + this.transpiler else switch (target) { - else => this.bundler, + else => this.transpiler, .browser => this.client_bundler, .bake_server_components_ssr => this.ssr_bundler, }; @@ -452,7 +451,7 @@ pub const BundleV2 = struct { /// Same semantics as bundlerForTarget for `path_to_source_index_map` pub inline fn pathToSourceIndexMap(this: *BundleV2, target: options.Target) *PathToSourceIndexMap { - return if (!this.bundler.options.server_components) + return if (!this.transpiler.options.server_components) &this.graph.path_to_source_index_map else switch (target) { else => &this.graph.path_to_source_index_map, @@ -583,7 +582,7 @@ pub const BundleV2 = struct { // imported and weird things will happen visitor.visit(Index.runtime, false, false); - switch (this.bundler.options.code_splitting) { + switch (this.transpiler.options.code_splitting) { inline else => |check_dynamic_imports| { for (this.graph.entry_points.items) |entry_point| { visitor.visit(entry_point, false, comptime check_dynamic_imports); @@ -636,19 +635,19 @@ pub const BundleV2 = struct { import_record: bun.JSC.API.JSBundler.Resolve.MiniImportRecord, target: options.Target, ) void { - const bundler = this.bundlerForTarget(target); + const transpiler = this.bundlerForTarget(target); var had_busted_dir_cache: bool = false; - var resolve_result = while (true) break bundler.resolver.resolve( + var resolve_result = while (true) break transpiler.resolver.resolve( Fs.PathName.init(import_record.source_file).dirWithTrailingSlash(), import_record.specifier, import_record.kind, ) catch |err| { // Only perform directory busting when hot-reloading is enabled if (err == error.ModuleNotFound) { - if (this.bundler.options.dev_server) |dev| { + if (this.transpiler.options.dev_server) |dev| { if (!had_busted_dir_cache) { // Only re-query if we previously had something cached. - if (bundler.resolver.bustDirCacheFromSpecifier(import_record.source_file, import_record.specifier)) { + if (transpiler.resolver.bustDirCacheFromSpecifier(import_record.source_file, import_record.specifier)) { had_busted_dir_cache = true; continue; } @@ -751,7 +750,7 @@ pub const BundleV2 = struct { if (path.pretty.ptr == path.text.ptr) { // TODO: outbase - const rel = bun.path.relativePlatform(bundler.fs.top_level_dir, path.text, .loose, false); + const rel = bun.path.relativePlatform(transpiler.fs.top_level_dir, path.text, .loose, false); path.pretty = this.graph.allocator.dupe(u8, rel) catch bun.outOfMemory(); } path.assertPrettyIsValid(); @@ -777,7 +776,7 @@ pub const BundleV2 = struct { } } - break :brk path.loader(&bundler.options.loaders) orelse options.Loader.file; + break :brk path.loader(&transpiler.options.loaders) orelse options.Loader.file; }; const idx = this.enqueueParseTask( &resolve_result, @@ -794,7 +793,7 @@ pub const BundleV2 = struct { // For non-javascript files, make all of these files share indices. // For example, it is silly to bundle index.css depended on by client+server twice. // It makes sense to separate these for JS because the target affects DCE - if (this.bundler.options.server_components and !loader.isJavaScriptLike()) { + if (this.transpiler.options.server_components and !loader.isJavaScriptLike()) { const a, const b = switch (target) { else => .{ &this.graph.client_path_to_source_index_map, &this.graph.ssr_path_to_source_index_map }, .browser => .{ &this.graph.path_to_source_index_map, &this.graph.ssr_path_to_source_index_map }, @@ -833,7 +832,7 @@ pub const BundleV2 = struct { } this.incrementScanCounter(); const source_index = Index.source(this.graph.input_files.len); - const loader = this.bundler.options.loaders.get(path.name.ext) orelse .file; + const loader = this.transpiler.options.loaders.get(path.name.ext) orelse .file; path.* = this.pathWithPrettyInitialized(path.*, target) catch bun.outOfMemory(); path.assertPrettyIsValid(); @@ -860,7 +859,7 @@ pub const BundleV2 = struct { // Handle onLoad plugins as entry points if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling(this.bundler.options.experimental_css)) { + if (loader.shouldCopyForBundling(this.transpiler.options.experimental_css)) { var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; additional_files.push(this.graph.allocator, .{ .source_index = task.source_index.get() }) catch unreachable; this.graph.input_files.items(.side_effects)[source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; @@ -876,7 +875,7 @@ pub const BundleV2 = struct { } pub fn init( - bundler: *ThisBundler, + transpiler: *Transpiler, bake_options: ?BakeOptions, allocator: std.mem.Allocator, event_loop: EventLoop, @@ -884,16 +883,16 @@ pub const BundleV2 = struct { thread_pool: ?*ThreadPoolLib, heap: ?ThreadlocalArena, ) !*BundleV2 { - bundler.env.loadTracy(); + transpiler.env.loadTracy(); const this = try allocator.create(BundleV2); - bundler.options.mark_builtins_as_external = bundler.options.target.isBun() or bundler.options.target == .node; - bundler.resolver.opts.mark_builtins_as_external = bundler.options.target.isBun() or bundler.options.target == .node; + transpiler.options.mark_builtins_as_external = transpiler.options.target.isBun() or transpiler.options.target == .node; + transpiler.resolver.opts.mark_builtins_as_external = transpiler.options.target.isBun() or transpiler.options.target == .node; this.* = .{ - .bundler = bundler, - .client_bundler = bundler, - .ssr_bundler = bundler, + .transpiler = transpiler, + .client_bundler = transpiler, + .ssr_bundler = transpiler, .framework = null, .graph = .{ .pool = undefined, @@ -920,50 +919,50 @@ pub const BundleV2 = struct { this.framework = bo.framework; this.linker.framework = &this.framework.?; this.plugins = bo.plugins; - bun.assert(bundler.options.server_components); + bun.assert(transpiler.options.server_components); bun.assert(this.client_bundler.options.server_components); if (bo.framework.server_components.?.separate_ssr_graph) bun.assert(this.ssr_bundler.options.server_components); } this.linker.graph.allocator = this.graph.heap.allocator(); this.graph.allocator = this.linker.graph.allocator; - this.bundler.allocator = this.graph.allocator; - this.bundler.resolver.allocator = this.graph.allocator; - this.bundler.linker.allocator = this.graph.allocator; - this.bundler.log.msgs.allocator = this.graph.allocator; - this.bundler.log.clone_line_text = true; + this.transpiler.allocator = this.graph.allocator; + this.transpiler.resolver.allocator = this.graph.allocator; + this.transpiler.linker.allocator = this.graph.allocator; + this.transpiler.log.msgs.allocator = this.graph.allocator; + this.transpiler.log.clone_line_text = true; // We don't expose an option to disable this. Bake forbids tree-shaking // since every export must is always exist in case a future module // starts depending on it. - if (this.bundler.options.output_format == .internal_bake_dev) { - this.bundler.options.tree_shaking = false; - this.bundler.resolver.opts.tree_shaking = false; + if (this.transpiler.options.output_format == .internal_bake_dev) { + this.transpiler.options.tree_shaking = false; + this.transpiler.resolver.opts.tree_shaking = false; } else { - this.bundler.options.tree_shaking = true; - this.bundler.resolver.opts.tree_shaking = true; + this.transpiler.options.tree_shaking = true; + this.transpiler.resolver.opts.tree_shaking = true; } - this.linker.resolver = &this.bundler.resolver; - this.linker.graph.code_splitting = bundler.options.code_splitting; + this.linker.resolver = &this.transpiler.resolver; + this.linker.graph.code_splitting = transpiler.options.code_splitting; - this.linker.options.minify_syntax = bundler.options.minify_syntax; - this.linker.options.minify_identifiers = bundler.options.minify_identifiers; - this.linker.options.minify_whitespace = bundler.options.minify_whitespace; - this.linker.options.emit_dce_annotations = bundler.options.emit_dce_annotations; - this.linker.options.ignore_dce_annotations = bundler.options.ignore_dce_annotations; - this.linker.options.banner = bundler.options.banner; - this.linker.options.footer = bundler.options.footer; - this.linker.options.experimental_css = bundler.options.experimental_css; - this.linker.options.css_chunking = bundler.options.css_chunking; - this.linker.options.source_maps = bundler.options.source_map; - this.linker.options.tree_shaking = bundler.options.tree_shaking; - this.linker.options.public_path = bundler.options.public_path; - this.linker.options.target = bundler.options.target; - this.linker.options.output_format = bundler.options.output_format; - this.linker.options.generate_bytecode_cache = bundler.options.bytecode; + this.linker.options.minify_syntax = transpiler.options.minify_syntax; + this.linker.options.minify_identifiers = transpiler.options.minify_identifiers; + this.linker.options.minify_whitespace = transpiler.options.minify_whitespace; + this.linker.options.emit_dce_annotations = transpiler.options.emit_dce_annotations; + this.linker.options.ignore_dce_annotations = transpiler.options.ignore_dce_annotations; + this.linker.options.banner = transpiler.options.banner; + this.linker.options.footer = transpiler.options.footer; + this.linker.options.experimental_css = transpiler.options.experimental_css; + this.linker.options.css_chunking = transpiler.options.css_chunking; + this.linker.options.source_maps = transpiler.options.source_map; + this.linker.options.tree_shaking = transpiler.options.tree_shaking; + this.linker.options.public_path = transpiler.options.public_path; + this.linker.options.target = transpiler.options.target; + this.linker.options.output_format = transpiler.options.output_format; + this.linker.options.generate_bytecode_cache = transpiler.options.bytecode; - this.linker.dev_server = bundler.options.dev_server; + this.linker.dev_server = transpiler.options.dev_server; var pool = try this.graph.allocator.create(ThreadPool); if (cli_watch_flag) { @@ -999,7 +998,7 @@ pub const BundleV2 = struct { pub fn onAfterDecrementScanCounter(this: *BundleV2) void { if (this.asynchronous and this.isDone()) { - this.finishFromBakeDevServer(this.bundler.options.dev_server orelse + this.finishFromBakeDevServer(this.transpiler.options.dev_server orelse @panic("No dev server attached in asynchronous bundle job")) catch bun.outOfMemory(); } @@ -1021,7 +1020,7 @@ pub const BundleV2 = struct { { // Add the runtime - const rt = ParseTask.getRuntimeSource(this.bundler.options.target); + const rt = ParseTask.getRuntimeSource(this.transpiler.options.target); try this.graph.input_files.append(bun.default_allocator, Graph.InputFile{ .source = rt.source, .loader = .js, @@ -1045,7 +1044,7 @@ pub const BundleV2 = struct { // gets its content set after the scan+parse phase, but before linking. // // The dev server does not use these, as it is implement in the HMR runtime. - if (this.bundler.options.dev_server == null) { + if (this.transpiler.options.dev_server == null) { try this.reserveSourceIndexesForBake(); } @@ -1064,14 +1063,14 @@ pub const BundleV2 = struct { switch (variant) { .normal => { for (data) |entry_point| { - const resolved = this.bundler.resolveEntryPoint(entry_point) catch + const resolved = this.transpiler.resolveEntryPoint(entry_point) catch continue; - _ = try this.enqueueEntryItem(null, &batch, resolved, true, this.bundler.options.target); + _ = try this.enqueueEntryItem(null, &batch, resolved, true, this.transpiler.options.target); } }, .dev_server => { for (data.files.set.keys(), data.files.set.values()) |abs_path, flags| { - const resolved = this.bundler.resolveEntryPoint(abs_path) catch + const resolved = this.transpiler.resolveEntryPoint(abs_path) catch continue; if (flags.client) brk: { @@ -1080,19 +1079,19 @@ pub const BundleV2 = struct { try data.css_data.putNoClobber(this.graph.allocator, Index.init(source_index), .{ .imported_on_server = false }); } } - if (flags.server) _ = try this.enqueueEntryItem(null, &batch, resolved, true, this.bundler.options.target); + if (flags.server) _ = try this.enqueueEntryItem(null, &batch, resolved, true, this.transpiler.options.target); if (flags.ssr) _ = try this.enqueueEntryItem(null, &batch, resolved, true, .bake_server_components_ssr); } }, .bake_production => { for (data.files.keys()) |key| { - const resolved = this.bundler.resolveEntryPoint(key.absPath()) catch + const resolved = this.transpiler.resolveEntryPoint(key.absPath()) catch continue; // TODO: wrap client files so the exports arent preserved. _ = try this.enqueueEntryItem(null, &batch, resolved, true, switch (key.side) { .client => .browser, - .server => this.bundler.options.target, + .server => this.transpiler.options.target, }) orelse continue; } }, @@ -1105,8 +1104,8 @@ pub const BundleV2 = struct { fn cloneAST(this: *BundleV2) !void { const trace = tracer(@src(), "cloneAST"); defer trace.end(); - this.linker.allocator = this.bundler.allocator; - this.linker.graph.allocator = this.bundler.allocator; + this.linker.allocator = this.transpiler.allocator; + this.linker.graph.allocator = this.transpiler.allocator; this.linker.graph.ast = try this.graph.ast.clone(this.linker.allocator); var ast = this.linker.graph.ast.slice(); for (ast.items(.module_scope)) |*module_scope| { @@ -1135,8 +1134,8 @@ pub const BundleV2 = struct { const alloc = this.graph.allocator; - var server = try AstBuilder.init(this.graph.allocator, &bake.server_virtual_source, this.bundler.options.hot_module_reloading); - var client = try AstBuilder.init(this.graph.allocator, &bake.client_virtual_source, this.bundler.options.hot_module_reloading); + var server = try AstBuilder.init(this.graph.allocator, &bake.server_virtual_source, this.transpiler.options.hot_module_reloading); + var client = try AstBuilder.init(this.graph.allocator, &bake.client_virtual_source, this.transpiler.options.hot_module_reloading); var server_manifest_props: std.ArrayListUnmanaged(G.Property) = .{}; var client_manifest_props: std.ArrayListUnmanaged(G.Property) = .{}; @@ -1287,7 +1286,7 @@ pub const BundleV2 = struct { // Handle onLoad plugins if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling(this.bundler.options.experimental_css)) { + if (loader.shouldCopyForBundling(this.transpiler.options.experimental_css)) { var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; additional_files.push(this.graph.allocator, .{ .source_index = task.source_index.get() }) catch unreachable; this.graph.input_files.items(.side_effects)[source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; @@ -1326,7 +1325,7 @@ pub const BundleV2 = struct { }, .side_effects = .has_side_effects, .jsx = if (known_target == .bake_server_components_ssr and !this.framework.?.server_components.?.separate_ssr_graph) - this.bundler.options.jsx + this.transpiler.options.jsx else this.bundlerForTarget(known_target).options.jsx, .source_index = source_index, @@ -1343,7 +1342,7 @@ pub const BundleV2 = struct { // Handle onLoad plugins if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling(this.bundler.options.experimental_css)) { + if (loader.shouldCopyForBundling(this.transpiler.options.experimental_css)) { var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; additional_files.push(this.graph.allocator, .{ .source_index = task.source_index.get() }) catch unreachable; this.graph.input_files.items(.side_effects)[source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; @@ -1386,7 +1385,7 @@ pub const BundleV2 = struct { } pub fn generateFromCLI( - bundler: *ThisBundler, + transpiler: *Transpiler, allocator: std.mem.Allocator, event_loop: EventLoop, enable_reloading: bool, @@ -1394,16 +1393,16 @@ pub const BundleV2 = struct { minify_duration: *u64, source_code_size: *u64, ) !std.ArrayList(options.OutputFile) { - var this = try BundleV2.init(bundler, null, allocator, event_loop, enable_reloading, null, null); + var this = try BundleV2.init(transpiler, null, allocator, event_loop, enable_reloading, null, null); this.unique_key = generateUniqueKey(); - if (this.bundler.log.hasErrors()) { + if (this.transpiler.log.hasErrors()) { return error.BuildFailed; } - this.graph.pool.pool.schedule(try this.enqueueEntryPoints(.normal, this.bundler.options.entry_points)); + this.graph.pool.pool.schedule(try this.enqueueEntryPoints(.normal, this.transpiler.options.entry_points)); - if (this.bundler.log.hasErrors()) { + if (this.transpiler.log.hasErrors()) { return error.BuildFailed; } @@ -1412,7 +1411,7 @@ pub const BundleV2 = struct { minify_duration.* = @as(u64, @intCast(@divTrunc(@as(i64, @truncate(std.time.nanoTimestamp())) - @as(i64, @truncate(bun.CLI.start_time)), @as(i64, std.time.ns_per_ms)))); source_code_size.* = this.source_code_length; - if (this.bundler.log.hasErrors()) { + if (this.transpiler.log.hasErrors()) { return error.BuildFailed; } @@ -1439,7 +1438,7 @@ pub const BundleV2 = struct { pub fn generateFromBakeProductionCLI( entry_points: bake.production.EntryPointMap, - server_bundler: *ThisBundler, + server_bundler: *Transpiler, kit_options: BakeOptions, allocator: std.mem.Allocator, event_loop: EventLoop, @@ -1447,19 +1446,19 @@ pub const BundleV2 = struct { var this = try BundleV2.init(server_bundler, kit_options, allocator, event_loop, false, null, null); this.unique_key = generateUniqueKey(); - if (this.bundler.log.hasErrors()) { + if (this.transpiler.log.hasErrors()) { return error.BuildFailed; } this.graph.pool.pool.schedule(try this.enqueueEntryPoints(.bake_production, entry_points)); - if (this.bundler.log.hasErrors()) { + if (this.transpiler.log.hasErrors()) { return error.BuildFailed; } this.waitForParse(); - if (this.bundler.log.hasErrors()) { + if (this.transpiler.log.hasErrors()) { return error.BuildFailed; } @@ -1507,7 +1506,7 @@ pub const BundleV2 = struct { const unique_key_for_additional_files = this.graph.input_files.items(.unique_key_for_additional_file); const content_hashes_for_additional_files = this.graph.input_files.items(.content_hash_for_additional_file); const sources = this.graph.input_files.items(.source); - var additional_output_files = std.ArrayList(options.OutputFile).init(this.bundler.allocator); + var additional_output_files = std.ArrayList(options.OutputFile).init(this.transpiler.allocator); const additional_files: []BabyList(AdditionalFile) = this.graph.input_files.items(.additional_files); const loaders = this.graph.input_files.items(.loader); @@ -1517,13 +1516,13 @@ pub const BundleV2 = struct { const key = unique_key_for_additional_files[index]; if (key.len > 0) { var template = PathTemplate.asset; - if (this.bundler.options.asset_naming.len > 0) - template.data = this.bundler.options.asset_naming; + if (this.transpiler.options.asset_naming.len > 0) + template.data = this.transpiler.options.asset_naming; const source = &sources[index]; var pathname = source.path.name; // TODO: outbase - pathname = Fs.PathName.init(bun.path.relativePlatform(this.bundler.options.root_dir, source.path.text, .loose, false)); + pathname = Fs.PathName.init(bun.path.relativePlatform(this.transpiler.options.root_dir, source.path.text, .loose, false)); template.placeholder.name = pathname.base; template.placeholder.dir = pathname.dir; @@ -1579,7 +1578,7 @@ pub const BundleV2 = struct { .promise = JSC.JSPromise.Strong.init(globalThis), .globalThis = globalThis, .poll_ref = Async.KeepAlive.init(), - .env = globalThis.bunVM().bundler.env, + .env = globalThis.bunVM().transpiler.env, .plugins = plugins, .log = Logger.Log.init(bun.default_allocator), .task = JSBundleCompletionTask.TaskCompletion.init(completion), @@ -1623,18 +1622,18 @@ pub const BundleV2 = struct { result: Result = .{ .pending = {} }, next: ?*JSBundleCompletionTask = null, - bundler: *BundleV2 = undefined, + transpiler: *BundleV2 = undefined, plugins: ?*bun.JSC.API.JSBundler.Plugin = null, ref_count: std.atomic.Value(u32) = std.atomic.Value(u32).init(1), pub fn configureBundler( completion: *JSBundleCompletionTask, - bundler: *Bundler, + transpiler: *Transpiler, allocator: std.mem.Allocator, ) !void { const config = &completion.config; - bundler.* = try bun.Bundler.init( + transpiler.* = try bun.Transpiler.init( allocator, &completion.log, Api.TransformOptions{ @@ -1651,52 +1650,52 @@ pub const BundleV2 = struct { .extension_order = &.{}, .env_files = &.{}, .conditions = config.conditions.map.keys(), - .ignore_dce_annotations = bundler.options.ignore_dce_annotations, + .ignore_dce_annotations = transpiler.options.ignore_dce_annotations, .drop = config.drop.map.keys(), }, completion.env, ); - bundler.options.env.behavior = config.env_behavior; - bundler.options.env.prefix = config.env_prefix.slice(); + transpiler.options.env.behavior = config.env_behavior; + transpiler.options.env.prefix = config.env_prefix.slice(); - bundler.options.entry_points = config.entry_points.keys(); - bundler.options.jsx = config.jsx; - bundler.options.no_macros = config.no_macros; - bundler.options.loaders = try options.loadersFromTransformOptions(allocator, config.loaders, config.target); - bundler.options.entry_naming = config.names.entry_point.data; - bundler.options.chunk_naming = config.names.chunk.data; - bundler.options.asset_naming = config.names.asset.data; + transpiler.options.entry_points = config.entry_points.keys(); + transpiler.options.jsx = config.jsx; + transpiler.options.no_macros = config.no_macros; + transpiler.options.loaders = try options.loadersFromTransformOptions(allocator, config.loaders, config.target); + transpiler.options.entry_naming = config.names.entry_point.data; + transpiler.options.chunk_naming = config.names.chunk.data; + transpiler.options.asset_naming = config.names.asset.data; - bundler.options.public_path = config.public_path.list.items; - bundler.options.output_format = config.format; - bundler.options.bytecode = config.bytecode; + transpiler.options.public_path = config.public_path.list.items; + transpiler.options.output_format = config.format; + transpiler.options.bytecode = config.bytecode; - bundler.options.output_dir = config.outdir.slice(); - bundler.options.root_dir = config.rootdir.slice(); - bundler.options.minify_syntax = config.minify.syntax; - bundler.options.minify_whitespace = config.minify.whitespace; - bundler.options.minify_identifiers = config.minify.identifiers; - bundler.options.inlining = config.minify.syntax; - bundler.options.source_map = config.source_map; - bundler.options.packages = config.packages; - bundler.options.code_splitting = config.code_splitting; - bundler.options.emit_dce_annotations = config.emit_dce_annotations orelse !config.minify.whitespace; - bundler.options.ignore_dce_annotations = config.ignore_dce_annotations; - bundler.options.experimental_css = config.experimental_css; - bundler.options.css_chunking = config.css_chunking; - bundler.options.banner = config.banner.slice(); - bundler.options.footer = config.footer.slice(); + transpiler.options.output_dir = config.outdir.slice(); + transpiler.options.root_dir = config.rootdir.slice(); + transpiler.options.minify_syntax = config.minify.syntax; + transpiler.options.minify_whitespace = config.minify.whitespace; + transpiler.options.minify_identifiers = config.minify.identifiers; + transpiler.options.inlining = config.minify.syntax; + transpiler.options.source_map = config.source_map; + transpiler.options.packages = config.packages; + transpiler.options.code_splitting = config.code_splitting; + transpiler.options.emit_dce_annotations = config.emit_dce_annotations orelse !config.minify.whitespace; + transpiler.options.ignore_dce_annotations = config.ignore_dce_annotations; + transpiler.options.experimental_css = config.experimental_css; + transpiler.options.css_chunking = config.css_chunking; + transpiler.options.banner = config.banner.slice(); + transpiler.options.footer = config.footer.slice(); - bundler.configureLinker(); - try bundler.configureDefines(); + transpiler.configureLinker(); + try transpiler.configureDefines(); if (bun.FeatureFlags.breaking_changes_1_2) { - if (!bundler.options.production) { - try bundler.options.conditions.appendSlice(&.{"development"}); + if (!transpiler.options.production) { + try transpiler.options.conditions.appendSlice(&.{"development"}); } } - bundler.resolver.opts = bundler.options; + transpiler.resolver.opts = transpiler.options; } pub fn completeOnBundleThread(completion: *JSBundleCompletionTask) void { @@ -1868,7 +1867,7 @@ pub const BundleV2 = struct { this.graph.heap.gc(true); } } - const log = this.bundler.log; + const log = this.transpiler.log; // TODO: watcher @@ -1893,7 +1892,7 @@ pub const BundleV2 = struct { this.decrementScanCounter(); }, .success => |code| { - const should_copy_for_bundling = load.parse_task.defer_copy_for_bundling and code.loader.shouldCopyForBundling(this.bundler.options.experimental_css); + const should_copy_for_bundling = load.parse_task.defer_copy_for_bundling and code.loader.shouldCopyForBundling(this.transpiler.options.experimental_css); if (should_copy_for_bundling) { const source_index = load.source_index; var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; @@ -1912,7 +1911,7 @@ pub const BundleV2 = struct { this.graph.pool.pool.schedule(ThreadPoolLib.Batch.from(&parse_task.task)); }, .err => |msg| { - if (this.bundler.options.dev_server) |dev| { + if (this.transpiler.options.dev_server) |dev| { const source = &this.graph.input_files.items(.source)[load.source_index.get()]; // A stack-allocated Log object containing the singular message var msg_mut = msg; @@ -1955,7 +1954,7 @@ pub const BundleV2 = struct { this.graph.heap.gc(true); } } - const log = this.bundler.log; + const log = this.transpiler.log; switch (resolve.value.consume()) { .no_match => { @@ -2010,7 +2009,7 @@ pub const BundleV2 = struct { existing.value_ptr.* = source_index.get(); out_source_index = source_index; this.graph.ast.append(bun.default_allocator, JSAst.empty) catch unreachable; - const loader = path.loader(&this.bundler.options.loaders) orelse options.Loader.file; + const loader = path.loader(&this.transpiler.options.loaders) orelse options.Loader.file; this.graph.input_files.append(bun.default_allocator, .{ .source = .{ @@ -2046,7 +2045,7 @@ pub const BundleV2 = struct { // Handle onLoad plugins if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling(this.bundler.options.experimental_css)) { + if (loader.shouldCopyForBundling(this.transpiler.options.experimental_css)) { var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; additional_files.push(this.graph.allocator, .{ .source_index = task.source_index.get() }) catch unreachable; this.graph.input_files.items(.side_effects)[source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; @@ -2135,7 +2134,7 @@ pub const BundleV2 = struct { ) !std.ArrayList(options.OutputFile) { this.unique_key = generateUniqueKey(); - if (this.bundler.log.errors > 0) { + if (this.transpiler.log.errors > 0) { return error.BuildFailed; } @@ -2148,7 +2147,7 @@ pub const BundleV2 = struct { this.graph.heap.helpCatchMemoryIssues(); - if (this.bundler.log.errors > 0) { + if (this.transpiler.log.errors > 0) { return error.BuildFailed; } @@ -2173,14 +2172,14 @@ pub const BundleV2 = struct { reachable_files, ); - if (this.bundler.log.errors > 0) { + if (this.transpiler.log.errors > 0) { return error.BuildFailed; } return try this.linker.generateChunksInParallel(chunks, false); } - /// Dev Server uses this instead to run a subset of the bundler, and to run it asynchronously. + /// Dev Server uses this instead to run a subset of the transpiler, and to run it asynchronously. pub fn startFromBakeDevServer(this: *BundleV2, bake_entry_points: bake.DevServer.EntryPointList) !BakeBundleStart { this.unique_key = generateUniqueKey(); @@ -2383,7 +2382,7 @@ pub const BundleV2 = struct { pub fn enqueueOnLoadPluginIfNeeded(this: *BundleV2, parse: *ParseTask) bool { if (this.plugins) |plugins| { if (plugins.hasAnyMatches(&parse.path, true)) { - if (parse.is_entry_point and parse.loader != null and parse.loader.?.shouldCopyForBundling(this.bundler.options.experimental_css)) { + if (parse.is_entry_point and parse.loader != null and parse.loader.?.shouldCopyForBundling(this.transpiler.options.experimental_css)) { parse.defer_copy_for_bundling = true; } // This is where onLoad plugins are enqueued @@ -2402,7 +2401,7 @@ pub const BundleV2 = struct { } fn pathWithPrettyInitialized(this: *BundleV2, path: Fs.Path, target: options.Target) !Fs.Path { - return genericPathWithPrettyInitialized(path, target, this.bundler.fs.top_level_dir, this.graph.allocator); + return genericPathWithPrettyInitialized(path, target, this.transpiler.fs.top_level_dir, this.graph.allocator); } fn reserveSourceIndexesForBake(this: *BundleV2) !void { @@ -2484,7 +2483,7 @@ pub const BundleV2 = struct { inline else => |is_server| { const src = if (is_server) bake.server_virtual_source else bake.client_virtual_source; if (strings.eqlComptime(import_record.path.text, src.path.pretty)) { - if (this.bundler.options.dev_server != null) { + if (this.transpiler.options.dev_server != null) { import_record.is_external_without_side_effects = true; import_record.source_index = Index.invalid; } else { @@ -2511,7 +2510,7 @@ pub const BundleV2 = struct { continue; } - if (this.bundler.options.rewrite_jest_for_tests) { + if (this.transpiler.options.rewrite_jest_for_tests) { if (strings.eqlComptime( import_record.path.text, "@jest/globals", @@ -2556,13 +2555,13 @@ pub const BundleV2 = struct { continue; } - const bundler, const renderer: bake.Graph, const target = + const transpiler, const renderer: bake.Graph, const target = if (import_record.tag == .bake_resolve_to_ssr_graph) brk: { // TODO: consider moving this error into js_parser so it is caught more reliably // Then we can assert(this.framework != null) if (this.framework == null) { - this.bundler.log.addErrorFmt( + this.transpiler.log.addErrorFmt( source, import_record.range.loc, this.graph.allocator, @@ -2575,7 +2574,7 @@ pub const BundleV2 = struct { const is_supported = this.framework.?.server_components != null and this.framework.?.server_components.?.separate_ssr_graph; if (!is_supported) { - this.bundler.log.addErrorFmt( + this.transpiler.log.addErrorFmt( source, import_record.range.loc, this.graph.allocator, @@ -2597,17 +2596,17 @@ pub const BundleV2 = struct { }; var had_busted_dir_cache = false; - var resolve_result = inner: while (true) break bundler.resolver.resolveWithFramework( + var resolve_result = inner: while (true) break transpiler.resolver.resolveWithFramework( source_dir, import_record.path.text, import_record.kind, ) catch |err| { // Only perform directory busting when hot-reloading is enabled if (err == error.ModuleNotFound) { - if (this.bundler.options.dev_server) |dev| { + if (this.transpiler.options.dev_server) |dev| { if (!had_busted_dir_cache) { // Only re-query if we previously had something cached. - if (bundler.resolver.bustDirCacheFromSpecifier( + if (transpiler.resolver.bustDirCacheFromSpecifier( source.path.text, import_record.path.text, )) { @@ -2640,7 +2639,7 @@ pub const BundleV2 = struct { if (isPackagePath(import_record.path.text)) { if (ast.target == .browser and options.ExternalModules.isNodeBuiltin(import_record.path.text)) { addError( - this.bundler.log, + this.transpiler.log, source, import_record.range, this.graph.allocator, @@ -2650,7 +2649,7 @@ pub const BundleV2 = struct { ) catch @panic("unexpected log error"); } else { addError( - this.bundler.log, + this.transpiler.log, source, import_record.range, this.graph.allocator, @@ -2661,7 +2660,7 @@ pub const BundleV2 = struct { } } else { addError( - this.bundler.log, + this.transpiler.log, source, import_record.range, this.graph.allocator, @@ -2699,12 +2698,12 @@ pub const BundleV2 = struct { continue; } - if (this.bundler.options.dev_server) |dev_server| { + if (this.transpiler.options.dev_server) |dev_server| { import_record.source_index = Index.invalid; import_record.is_external_without_side_effects = true; if (dev_server.isFileCached(path.text, renderer)) |entry| { - const rel = bun.path.relativePlatform(this.bundler.fs.top_level_dir, path.text, .loose, false); + const rel = bun.path.relativePlatform(this.transpiler.fs.top_level_dir, path.text, .loose, false); import_record.path.text = rel; import_record.path.pretty = rel; import_record.path = this.pathWithPrettyInitialized(path.*, target) catch bun.outOfMemory(); @@ -2718,7 +2717,7 @@ pub const BundleV2 = struct { const hash_key = path.hashKey(); if (this.pathToSourceIndexMap(target).get(hash_key)) |id| { - if (this.bundler.options.dev_server != null) { + if (this.transpiler.options.dev_server != null) { import_record.path = this.graph.input_files.items(.source)[id].path; } else { import_record.source_index = Index.init(id); @@ -2759,8 +2758,8 @@ pub const BundleV2 = struct { } if (resolve_task.loader == null) { - resolve_task.loader = path.loader(&this.bundler.options.loaders); - resolve_task.tree_shaking = this.bundler.options.tree_shaking; + resolve_task.loader = path.loader(&this.transpiler.options.loaders); + resolve_task.tree_shaking = this.transpiler.options.tree_shaking; } resolve_entry.value_ptr.* = resolve_task; @@ -2804,7 +2803,7 @@ pub const BundleV2 = struct { .success => |val| val.source.index.get(), }; const loader: Loader = this.graph.input_files.items(.loader)[source]; - if (!loader.shouldCopyForBundling(this.bundler.options.experimental_css)) { + if (!loader.shouldCopyForBundling(this.transpiler.options.experimental_css)) { this.finalizers.append(bun.default_allocator, parse_result.external) catch bun.outOfMemory(); } else { this.graph.input_files.items(.allocator)[source] = ExternalFreeFunctionAllocator.create(@ptrCast(parse_result.external.function.?), parse_result.external.ctx.?); @@ -2834,7 +2833,7 @@ pub const BundleV2 = struct { } } - // To minimize contention, watchers are appended by the bundler thread. + // To minimize contention, watchers are appended by the transpiler thread. if (this.bun_watcher) |watcher| { if (parse_result.watcher_data.fd != bun.invalid_fd and parse_result.watcher_data.fd != .zero) { const source = switch (parse_result.value) { @@ -2866,7 +2865,7 @@ pub const BundleV2 = struct { } }, .success => |*result| { - result.log.cloneToWithRecycled(this.bundler.log, true) catch unreachable; + result.log.cloneToWithRecycled(this.transpiler.log, true) catch unreachable; // Warning: `input_files` and `ast` arrays may resize in this function call // It is not safe to cache slices from them. @@ -2911,7 +2910,7 @@ pub const BundleV2 = struct { .side_effects = value.side_effects, }; - const loader = new_task.loader orelse new_input_file.source.path.loader(&this.bundler.options.loaders) orelse options.Loader.file; + const loader = new_task.loader orelse new_input_file.source.path.loader(&this.transpiler.options.loaders) orelse options.Loader.file; new_input_file.source.index = Index.source(graph.input_files.len); new_input_file.source.path = new_task.path; @@ -2931,7 +2930,7 @@ pub const BundleV2 = struct { continue; } - if (loader.shouldCopyForBundling(this.bundler.options.experimental_css)) { + if (loader.shouldCopyForBundling(this.transpiler.options.experimental_css)) { var additional_files: *BabyList(AdditionalFile) = &graph.input_files.items(.additional_files)[result.source.index.get()]; additional_files.push(this.graph.allocator, .{ .source_index = new_task.source_index.get() }) catch unreachable; new_input_file.side_effects = _resolver.SideEffects.no_side_effects__pure_data; @@ -2941,8 +2940,8 @@ pub const BundleV2 = struct { // schedule as early as possible graph.pool.pool.schedule(ThreadPoolLib.Batch.from(&new_task.task)); } else { - const loader = value.loader orelse graph.input_files.items(.source)[existing.value_ptr.*].path.loader(&this.bundler.options.loaders) orelse options.Loader.file; - if (loader.shouldCopyForBundling(this.bundler.options.experimental_css)) { + const loader = value.loader orelse graph.input_files.items(.source)[existing.value_ptr.*].path.loader(&this.transpiler.options.loaders) orelse options.Loader.file; + if (loader.shouldCopyForBundling(this.transpiler.options.experimental_css)) { var additional_files: *BabyList(AdditionalFile) = &graph.input_files.items(.additional_files)[result.source.index.get()]; additional_files.push(this.graph.allocator, .{ .source_index = existing.value_ptr.* }) catch unreachable; graph.estimated_file_loader_count += 1; @@ -2958,7 +2957,7 @@ pub const BundleV2 = struct { if (this.resolve_tasks_waiting_for_import_source_index.fetchSwapRemove(result.source.index.get())) |pending_entry| { for (pending_entry.value.slice()) |to_assign| { - if (this.bundler.options.dev_server == null or + if (this.transpiler.options.dev_server == null or input_file_loaders[to_assign.to_source_index.get()] == .css) { import_records.slice()[to_assign.import_record_index].source_index = to_assign.to_source_index; @@ -2975,7 +2974,7 @@ pub const BundleV2 = struct { for (import_records.slice(), 0..) |*record, i| { if (path_to_source_index_map.get(record.path.hashKey())) |source_index| { - if (this.bundler.options.dev_server == null or + if (this.transpiler.options.dev_server == null or input_file_loaders[source_index] == .css) record.source_index.value = source_index; @@ -3027,7 +3026,7 @@ pub const BundleV2 = struct { // Enqueue only one file var server_source = result.source; server_source.path.pretty = server_source.path.text; - server_source.path = this.pathWithPrettyInitialized(server_source.path, this.bundler.options.target) catch bun.outOfMemory(); + server_source.path = this.pathWithPrettyInitialized(server_source.path, this.transpiler.options.target) catch bun.outOfMemory(); const server_index = this.enqueueParseTask2( server_source, this.graph.input_files.items(.loader)[result.source.index.get()], @@ -3058,7 +3057,7 @@ pub const BundleV2 = struct { } if (process_log) { - if (this.bundler.options.dev_server) |dev_server| { + if (this.transpiler.options.dev_server) |dev_server| { dev_server.handleParseTaskFailure( err.err, err.target.bakeGraph(), @@ -3066,19 +3065,19 @@ pub const BundleV2 = struct { &err.log, ) catch bun.outOfMemory(); } else if (err.log.msgs.items.len > 0) { - err.log.cloneToWithRecycled(this.bundler.log, true) catch unreachable; + err.log.cloneToWithRecycled(this.transpiler.log, true) catch unreachable; } else { - this.bundler.log.addErrorFmt( + this.transpiler.log.addErrorFmt( null, Logger.Loc.Empty, - this.bundler.log.msgs.allocator, + this.transpiler.log.msgs.allocator, "{s} while {s}", .{ @errorName(err.err), @tagName(err.step) }, ) catch unreachable; } } - if (Environment.allow_assert and this.bundler.options.dev_server != null) { + if (Environment.allow_assert and this.transpiler.options.dev_server != null) { bun.assert(this.graph.ast.items(.parts)[err.source_index.get()].len == 0); } }, @@ -3087,12 +3086,12 @@ pub const BundleV2 = struct { /// To satisfy the interface from NewHotReloader() pub fn getLoaders(vm: *BundleV2) *bun.options.Loader.HashTable { - return &vm.bundler.options.loaders; + return &vm.transpiler.options.loaders; } /// To satisfy the interface from NewHotReloader() pub fn bustDirCache(vm: *BundleV2, path: []const u8) bool { - return vm.bundler.resolver.bustDirCache(path); + return vm.transpiler.resolver.bustDirCache(path); } }; @@ -3209,14 +3208,14 @@ pub fn BundleThread(CompletionStruct: type) type { ast_memory_allocator.reset(); ast_memory_allocator.push(); - const bundler = try allocator.create(bun.Bundler); + const transpiler = try allocator.create(bun.Transpiler); - try completion.configureBundler(bundler, allocator); + try completion.configureBundler(transpiler, allocator); - bundler.resolver.generation = generation; + transpiler.resolver.generation = generation; const this = try BundleV2.init( - bundler, + transpiler, null, // TODO: Kit allocator, JSC.AnyEventLoop.init(allocator), @@ -3230,7 +3229,7 @@ pub fn BundleThread(CompletionStruct: type) type { BundleV2.JSBundleCompletionTask => completion, else => @compileError("Unknown completion struct: " ++ CompletionStruct), }; - completion.bundler = this; + completion.transpiler = this; defer { if (this.graph.pool.pool.threadpool_context == @as(?*anyopaque, @ptrCast(this.graph.pool))) { @@ -3247,16 +3246,16 @@ pub fn BundleThread(CompletionStruct: type) type { this.linker.source_maps.quoted_contents_wait_group.wait(); var out_log = Logger.Log.init(bun.default_allocator); - this.bundler.log.appendToWithRecycled(&out_log, true) catch bun.outOfMemory(); + this.transpiler.log.appendToWithRecycled(&out_log, true) catch bun.outOfMemory(); completion.log = out_log; } completion.result = .{ .value = .{ - .output_files = try this.runFromJSInNewThread(bundler.options.entry_points), + .output_files = try this.runFromJSInNewThread(transpiler.options.entry_points), } }; var out_log = Logger.Log.init(bun.default_allocator); - this.bundler.log.appendToWithRecycled(&out_log, true) catch bun.outOfMemory(); + this.transpiler.log.appendToWithRecycled(&out_log, true) catch bun.outOfMemory(); completion.log = out_log; completion.completeOnBundleThread(); } @@ -3284,8 +3283,8 @@ pub const DeferredBatchTask = struct { } pub fn getCompletion(this: *DeferredBatchTask) ?*bun.BundleV2.JSBundleCompletionTask { - const bundler: *BundleV2 = @alignCast(@fieldParentPtr("drain_defer_task", this)); - return bundler.completion; + const transpiler: *BundleV2 = @alignCast(@fieldParentPtr("drain_defer_task", this)); + return transpiler.completion; } pub fn schedule(this: *DeferredBatchTask) void { @@ -3308,7 +3307,7 @@ pub const DeferredBatchTask = struct { return; }; - completion.bundler.plugins.?.drainDeferred(completion.result == .err); + completion.transpiler.plugins.?.drainDeferred(completion.result == .err); } }; @@ -3421,7 +3420,7 @@ pub const ParseTask = struct { .module_type = resolve_result.module_type, .emit_decorator_metadata = resolve_result.emit_decorator_metadata, .package_version = if (resolve_result.package_json) |package_json| package_json.version else "", - .known_target = ctx.bundler.options.target, + .known_target = ctx.transpiler.options.target, }; } @@ -3576,25 +3575,25 @@ pub const ParseTask = struct { fn getEmptyCSSAST( log: *Logger.Log, - bundler: *Bundler, + transpiler: *Transpiler, opts: js_parser.Parser.Options, allocator: std.mem.Allocator, source: Logger.Source, ) !JSAst { const root = Expr.init(E.Object, E.Object{}, Logger.Loc{ .start = 0 }); - var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); + var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); ast.css = bun.create(allocator, bun.css.BundlerStyleSheet, bun.css.BundlerStyleSheet.empty(allocator)); return ast; } - fn getEmptyAST(log: *Logger.Log, bundler: *Bundler, opts: js_parser.Parser.Options, allocator: std.mem.Allocator, source: Logger.Source, comptime RootType: type) !JSAst { + fn getEmptyAST(log: *Logger.Log, transpiler: *Transpiler, opts: js_parser.Parser.Options, allocator: std.mem.Allocator, source: Logger.Source, comptime RootType: type) !JSAst { const root = Expr.init(RootType, RootType{}, Logger.Loc.Empty); - return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); + return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); } fn getAST( log: *Logger.Log, - bundler: *Bundler, + transpiler: *Transpiler, opts: js_parser.Parser.Options, allocator: std.mem.Allocator, resolver: *Resolver, @@ -3608,9 +3607,9 @@ pub const ParseTask = struct { const trace = tracer(@src(), "ParseJS"); defer trace.end(); return if (try resolver.caches.js.parse( - bundler.allocator, + transpiler.allocator, opts, - bundler.options.define, + transpiler.options.define, log, &source, )) |res| @@ -3618,7 +3617,7 @@ pub const ParseTask = struct { else switch (opts.module_type == .esm) { inline else => |as_undefined| try getEmptyAST( log, - bundler, + transpiler, opts, allocator, source, @@ -3630,25 +3629,25 @@ pub const ParseTask = struct { const trace = tracer(@src(), "ParseJSON"); defer trace.end(); const root = (try resolver.caches.json.parsePackageJSON(log, source, allocator, false)) orelse Expr.init(E.Object, E.Object{}, Logger.Loc.Empty); - return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); + return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); }, .toml => { const trace = tracer(@src(), "ParseTOML"); defer trace.end(); const root = try TOML.parse(&source, log, allocator, false); - return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); + return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); }, .text => { const root = Expr.init(E.String, E.String{ .data = source.contents, }, Logger.Loc{ .start = 0 }); - var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); - ast.addUrlForCss(allocator, bundler.options.experimental_css, &source, "text/plain", null); + var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); + ast.addUrlForCss(allocator, transpiler.options.experimental_css, &source, "text/plain", null); return ast; }, .sqlite_embedded, .sqlite => { - if (!bundler.options.target.isBun()) { + if (!transpiler.options.target.isBun()) { log.addError( null, Logger.Loc.Empty, @@ -3708,11 +3707,11 @@ pub const ParseTask = struct { .name = "db", }, Logger.Loc{ .start = 0 }); - return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); + return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); }, .napi => { // (dap-eval-cb "source.contents.ptr") - if (bundler.options.target == .browser) { + if (transpiler.options.target == .browser) { log.addError( null, Logger.Loc.Empty, @@ -3739,10 +3738,10 @@ pub const ParseTask = struct { }, Logger.Loc{ .start = 0 }); unique_key_for_additional_file.* = unique_key; - return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); + return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); }, .css => { - if (bundler.options.experimental_css) { + if (transpiler.options.experimental_css) { // const unique_key = std.fmt.allocPrint(allocator, "{any}A{d:0>8}", .{ bun.fmt.hexIntLower(unique_key_prefix), source.index.get() }) catch unreachable; // unique_key_for_additional_file.* = unique_key; var import_records = BabyList(ImportRecord){}; @@ -3750,7 +3749,7 @@ pub const ParseTask = struct { var css_ast = switch (bun.css.BundlerStyleSheet.parseBundler( allocator, source_code, - bun.css.ParserOptions.default(allocator, bundler.log), + bun.css.ParserOptions.default(allocator, transpiler.log), &import_records, )) { .result => |v| v, @@ -3760,7 +3759,7 @@ pub const ParseTask = struct { }, }; if (css_ast.minify(allocator, bun.css.MinifyOptions{ - .targets = bun.css.Targets.forBundlerTarget(bundler.options.target), + .targets = bun.css.Targets.forBundlerTarget(transpiler.options.target), .unused_symbols = .{}, }).asErr()) |e| { try e.addToLogger(log, &source); @@ -3768,7 +3767,7 @@ pub const ParseTask = struct { } const root = Expr.init(E.Object, E.Object{}, Logger.Loc{ .start = 0 }); const css_ast_heap = bun.create(allocator, bun.css.BundlerStyleSheet, css_ast); - var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); + var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); ast.css = css_ast_heap; ast.import_records = import_records; return ast; @@ -3781,16 +3780,16 @@ pub const ParseTask = struct { .data = unique_key, }, Logger.Loc{ .start = 0 }); unique_key_for_additional_file.* = unique_key; - var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); + var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, &source, "")).?); ast.url_for_css = unique_key; - ast.addUrlForCss(allocator, bundler.options.experimental_css, &source, null, unique_key); + ast.addUrlForCss(allocator, transpiler.options.experimental_css, &source, null, unique_key); return ast; } fn getCodeForParseTaskWithoutPlugins( task: *ParseTask, log: *Logger.Log, - bundler: *Bundler, + transpiler: *Transpiler, resolver: *Resolver, allocator: std.mem.Allocator, file_path: *Fs.Path, @@ -3826,7 +3825,7 @@ pub const ParseTask = struct { bun.default_allocator else allocator, - bundler.fs, + transpiler.fs, file_path.text, task.contents_or_fd.fd.dir, false, @@ -3870,7 +3869,7 @@ pub const ParseTask = struct { fn getCodeForParseTask( task: *ParseTask, log: *Logger.Log, - bundler: *Bundler, + transpiler: *Transpiler, resolver: *Resolver, allocator: std.mem.Allocator, file_path: *Fs.Path, @@ -3890,7 +3889,7 @@ pub const ParseTask = struct { }; if (!might_have_on_parse_plugins) { - return getCodeForParseTaskWithoutPlugins(task, log, bundler, resolver, allocator, file_path, loader.*, experimental_css); + return getCodeForParseTaskWithoutPlugins(task, log, transpiler, resolver, allocator, file_path, loader.*, experimental_css); } var should_continue_running: i32 = 1; @@ -3898,7 +3897,7 @@ pub const ParseTask = struct { var ctx = OnBeforeParsePlugin{ .task = task, .log = log, - .bundler = bundler, + .transpiler = transpiler, .resolver = resolver, .allocator = allocator, .file_path = file_path, @@ -3914,7 +3913,7 @@ pub const ParseTask = struct { const OnBeforeParsePlugin = struct { task: *ParseTask, log: *Logger.Log, - bundler: *Bundler, + transpiler: *Transpiler, resolver: *Resolver, allocator: std.mem.Allocator, file_path: *Fs.Path, @@ -4075,7 +4074,7 @@ pub const ParseTask = struct { const entry = getCodeForParseTaskWithoutPlugins( this.task, this.log, - this.bundler, + this.transpiler, this.resolver, this.allocator, this.file_path, @@ -4208,7 +4207,7 @@ pub const ParseTask = struct { } } - return try getCodeForParseTaskWithoutPlugins(this.task, this.log, this.bundler, this.resolver, this.allocator, this.file_path, this.loader.*, this.experimental_css); + return try getCodeForParseTaskWithoutPlugins(this.task, this.log, this.transpiler, this.resolver, this.allocator, this.file_path, this.loader.*, this.experimental_css); } }; @@ -4221,15 +4220,15 @@ pub const ParseTask = struct { const allocator = this.allocator; var data = this.data; - var bundler = &data.bundler; - errdefer bundler.resetStore(); - var resolver: *Resolver = &bundler.resolver; + var transpiler = &data.transpiler; + errdefer transpiler.resetStore(); + var resolver: *Resolver = &transpiler.resolver; var file_path = task.path; step.* = .read_file; - var loader = task.loader orelse file_path.loader(&bundler.options.loaders) orelse options.Loader.file; + var loader = task.loader orelse file_path.loader(&transpiler.options.loaders) orelse options.Loader.file; var contents_came_from_plugin: bool = false; - var entry = try getCodeForParseTask(task, log, bundler, resolver, allocator, &file_path, &loader, this.ctx.bundler.options.experimental_css, &contents_came_from_plugin); + var entry = try getCodeForParseTask(task, log, transpiler, resolver, allocator, &file_path, &loader, this.ctx.transpiler.options.experimental_css, &contents_came_from_plugin); // WARNING: Do not change the variant of `task.contents_or_fd` from // `.fd` to `.contents` (or back) after this point! @@ -4273,7 +4272,7 @@ pub const ParseTask = struct { const is_empty = strings.isAllWhitespace(entry.contents); - const use_directive: UseDirective = if (!is_empty and bundler.options.server_components) + const use_directive: UseDirective = if (!is_empty and transpiler.options.server_components) if (UseDirective.parse(entry.contents)) |use| use else @@ -4288,11 +4287,11 @@ pub const ParseTask = struct { task.known_target != .bake_server_components_ssr and this.ctx.framework.?.server_components.?.separate_ssr_graph) or // set the target to the client when bundling client-side files - (bundler.options.server_components and task.known_target == .browser)) + (transpiler.options.server_components and task.known_target == .browser)) { - bundler = this.ctx.client_bundler; - resolver = &bundler.resolver; - bun.assert(bundler.options.target == .browser); + transpiler = this.ctx.client_bundler; + resolver = &transpiler.resolver; + bun.assert(transpiler.options.target == .browser); } var source = Logger.Source{ @@ -4303,12 +4302,12 @@ pub const ParseTask = struct { }; const target = (if (task.source_index.get() == 1) targetFromHashbang(entry.contents) else null) orelse - if (task.known_target == .bake_server_components_ssr and bundler.options.framework.?.server_components.?.separate_ssr_graph) + if (task.known_target == .bake_server_components_ssr and transpiler.options.framework.?.server_components.?.separate_ssr_graph) .bake_server_components_ssr else - bundler.options.target; + transpiler.options.target; - const output_format = bundler.options.output_format; + const output_format = transpiler.options.output_format; var opts = js_parser.Parser.Options.init(task.jsx, loader); opts.bundle = true; @@ -4321,25 +4320,25 @@ pub const ParseTask = struct { opts.features.unwrap_commonjs_to_esm = output_format == .esm and FeatureFlags.unwrap_commonjs_to_esm; opts.features.use_import_meta_require = target.isBun(); opts.features.top_level_await = output_format == .esm or output_format == .internal_bake_dev; - opts.features.auto_import_jsx = task.jsx.parse and bundler.options.auto_import_jsx; - opts.features.trim_unused_imports = loader.isTypeScript() or (bundler.options.trim_unused_imports orelse false); - opts.features.inlining = bundler.options.minify_syntax; + opts.features.auto_import_jsx = task.jsx.parse and transpiler.options.auto_import_jsx; + opts.features.trim_unused_imports = loader.isTypeScript() or (transpiler.options.trim_unused_imports orelse false); + opts.features.inlining = transpiler.options.minify_syntax; opts.output_format = output_format; - opts.features.minify_syntax = bundler.options.minify_syntax; - opts.features.minify_identifiers = bundler.options.minify_identifiers; - opts.features.emit_decorator_metadata = bundler.options.emit_decorator_metadata; - opts.features.unwrap_commonjs_packages = bundler.options.unwrap_commonjs_packages; + opts.features.minify_syntax = transpiler.options.minify_syntax; + opts.features.minify_identifiers = transpiler.options.minify_identifiers; + opts.features.emit_decorator_metadata = transpiler.options.emit_decorator_metadata; + opts.features.unwrap_commonjs_packages = transpiler.options.unwrap_commonjs_packages; opts.features.hot_module_reloading = output_format == .internal_bake_dev and !source.index.isRuntime(); opts.features.react_fast_refresh = target == .browser and - bundler.options.react_fast_refresh and + transpiler.options.react_fast_refresh and loader.isJSX() and !source.path.isNodeModule(); - opts.features.server_components = if (bundler.options.server_components) switch (target) { + opts.features.server_components = if (transpiler.options.server_components) switch (target) { .browser => .client_side, else => switch (use_directive) { .none => .wrap_anon_server_functions, - .client => if (bundler.options.framework.?.server_components.?.separate_ssr_graph) + .client => if (transpiler.options.framework.?.server_components.?.separate_ssr_graph) .client_side else .wrap_exports_for_client_reference, @@ -4347,37 +4346,37 @@ pub const ParseTask = struct { }, } else .none; - opts.framework = bundler.options.framework; + opts.framework = transpiler.options.framework; - opts.ignore_dce_annotations = bundler.options.ignore_dce_annotations and !source.index.isRuntime(); + opts.ignore_dce_annotations = transpiler.options.ignore_dce_annotations and !source.index.isRuntime(); // For files that are not user-specified entrypoints, set `import.meta.main` to `false`. // Entrypoints will have `import.meta.main` set as "unknown", unless we use `--compile`, // in which we inline `true`. - if (bundler.options.inline_entrypoint_import_meta_main or !task.is_entry_point) { + if (transpiler.options.inline_entrypoint_import_meta_main or !task.is_entry_point) { opts.import_meta_main_value = task.is_entry_point; - } else if (bundler.options.target == .node) { + } else if (transpiler.options.target == .node) { opts.lower_import_meta_main_for_node_js = true; } - opts.tree_shaking = if (source.index.isRuntime()) true else bundler.options.tree_shaking; + opts.tree_shaking = if (source.index.isRuntime()) true else transpiler.options.tree_shaking; opts.module_type = task.module_type; task.jsx.parse = loader.isJSX(); var unique_key_for_additional_file: []const u8 = ""; var ast: JSAst = if (!is_empty) - try getAST(log, bundler, opts, allocator, resolver, source, loader, task.ctx.unique_key, &unique_key_for_additional_file) + try getAST(log, transpiler, opts, allocator, resolver, source, loader, task.ctx.unique_key, &unique_key_for_additional_file) else switch (opts.module_type == .esm) { - inline else => |as_undefined| if (loader == .css and this.ctx.bundler.options.experimental_css) try getEmptyCSSAST( + inline else => |as_undefined| if (loader == .css and this.ctx.transpiler.options.experimental_css) try getEmptyCSSAST( log, - bundler, + transpiler, opts, allocator, source, ) else try getEmptyAST( log, - bundler, + transpiler, opts, allocator, source, @@ -4401,7 +4400,7 @@ pub const ParseTask = struct { .side_effects = task.side_effects, // Hash the files in here so that we do it in parallel. - .content_hash_for_additional_file = if (loader.shouldCopyForBundling(this.ctx.bundler.options.experimental_css)) + .content_hash_for_additional_file = if (loader.shouldCopyForBundling(this.ctx.transpiler.options.experimental_css)) ContentHasher.run(source.contents) else 0, @@ -4422,7 +4421,7 @@ pub const ParseTask = struct { const value: ParseTask.Result.Value = if (run(this, worker, &step, &log)) |ast| value: { // When using HMR, always flag asts with errors as parse failures. // Not done outside of the dev server out of fear of breaking existing code. - if (this.ctx.bundler.options.dev_server != null and ast.log.hasErrors()) { + if (this.ctx.transpiler.options.dev_server != null and ast.log.hasErrors()) { break :value .{ .err = .{ .err = error.SyntaxError, @@ -4554,7 +4553,7 @@ pub const ServerComponentParseTask = struct { log: *Logger.Log, allocator: std.mem.Allocator, ) bun.OOM!ParseTask.Result.Success { - var ab = try AstBuilder.init(allocator, &task.source, task.ctx.bundler.options.hot_module_reloading); + var ab = try AstBuilder.init(allocator, &task.source, task.ctx.transpiler.options.hot_module_reloading); switch (task.data) { .client_reference_proxy => |data| try task.generateClientReferenceProxy(data, &ab), @@ -4564,7 +4563,7 @@ pub const ServerComponentParseTask = struct { return .{ .ast = try ab.toBundledAst(switch (task.data) { // Server-side - .client_reference_proxy => task.ctx.bundler.options.target, + .client_reference_proxy => task.ctx.transpiler.options.target, // Client-side, .client_entry_wrapper => .browser, }), @@ -4604,7 +4603,7 @@ pub const ServerComponentParseTask = struct { // In production, the path here must be the final chunk path, but // that information is not yet available since chunks are not // computed. The unique_key replacement system is used here. - .data = if (task.ctx.bundler.options.dev_server != null) + .data = if (task.ctx.transpiler.options.dev_server != null) data.other_source.path.pretty else try std.fmt.allocPrint(b.allocator, "{}S{d:0>8}", .{ @@ -4944,15 +4943,15 @@ pub const Graph = struct { /// each `.defer()` called in an onLoad plugin. /// /// Returns true if there were more tasks queued. - pub fn drainDeferredTasks(this: *@This(), bundler: *BundleV2) bool { - bundler.thread_lock.assertLocked(); + pub fn drainDeferredTasks(this: *@This(), transpiler: *BundleV2) bool { + transpiler.thread_lock.assertLocked(); if (this.deferred_pending > 0) { this.pending_items += this.deferred_pending; this.deferred_pending = 0; - bundler.drain_defer_task.init(); - bundler.drain_defer_task.schedule(); + transpiler.drain_defer_task.init(); + transpiler.drain_defer_task.schedule(); return true; } @@ -5649,10 +5648,10 @@ pub const LinkerContext = struct { defer trace.end(); this.parse_graph = &bundle.graph; - this.graph.code_splitting = bundle.bundler.options.code_splitting; - this.log = bundle.bundler.log; + this.graph.code_splitting = bundle.transpiler.options.code_splitting; + this.log = bundle.transpiler.log; - this.resolver = &bundle.bundler.resolver; + this.resolver = &bundle.transpiler.resolver; this.cycle_detector = std.ArrayList(ImportTracker).init(this.allocator); this.graph.reachable_files = reachable; @@ -7672,7 +7671,7 @@ pub const LinkerContext = struct { // module may be simultaneously imported and required, and the // importing code should not see "__esModule" while the requiring // code should see "__esModule". This is an extremely complex - // and subtle set of bundler interop issues. See for example + // and subtle set of transpiler interop issues. See for example // https://github.com/evanw/esbuild/issues/1591. if (kind == .require) { record.wrap_with_to_commonjs = true; @@ -8918,8 +8917,8 @@ pub const LinkerContext = struct { } top_level_symbols.clearRetainingCapacity(); - for (sorted_imports_from_other_chunks.items) |stable| { - try minify_renamer.accumulateSymbolUseCount(&top_level_symbols, stable.ref, 1, stable_source_indices); + for (sorted_imports_from_other_chunks.items) |stable_ref| { + try minify_renamer.accumulateSymbolUseCount(&top_level_symbols, stable_ref.ref, 1, stable_source_indices); } top_level_symbols_all.appendSlice(top_level_symbols.items) catch unreachable; try minify_renamer.allocateTopLevelSymbolSlots(top_level_symbols_all); @@ -11474,7 +11473,7 @@ pub const LinkerContext = struct { // hmr-runtime.ts defines `module.importSync` to be // a synchronous import. this is different from // require in that esm <-> cjs is handled - // automatically, instead of with bundler-added + // automatically, instead of with transpiler-added // annotations like '__commonJS'. // // this cannot be done in the parse step because the final @@ -12482,7 +12481,7 @@ pub const LinkerContext = struct { // - Reuse unchanged parts to assemble the full bundle if Cmd+R is used in the browser // - Send only the newly changed code through a socket. // - // When this isnt the initial bundle, concatenation as usual would produce a + // When this isn't the initial bundle, concatenation as usual would produce a // broken module. It is DevServer's job to create and send HMR patches. if (is_dev_server) return; @@ -13248,7 +13247,6 @@ pub const LinkerContext = struct { .buffer = JSC.Buffer{ .buffer = .{ .ptr = @constCast(bytes.ptr), - // TODO: handle > 4 GB files .len = @as(u32, @truncate(bytes.len)), .byte_len = @as(u32, @truncate(bytes.len)), }, @@ -13735,7 +13733,7 @@ pub const LinkerContext = struct { next_source.path.pretty, named_import.alias.?, }, - "Bun's bundler defaults to browser builds instead of node or bun builds. If you want to use node or bun builds, you can set the target to \"node\" or \"bun\" in the bundler options.", + "Bun's bundler defaults to browser builds instead of node or bun builds. If you want to use node or bun builds, you can set the target to \"node\" or \"bun\" in the transpiler options.", .{}, r, ) catch unreachable; @@ -13761,7 +13759,7 @@ pub const LinkerContext = struct { next_source.path.pretty, named_import.alias.?, }, - "Bun's bundler defaults to browser builds instead of node or bun builds. If you want to use node or bun builds, you can set the target to \"node\" or \"bun\" in the bundler options.", + "Bun's bundler defaults to browser builds instead of node or bun builds. If you want to use node or bun builds, you can set the target to \"node\" or \"bun\" in the transpiler options.", .{}, r, ) catch unreachable; @@ -15654,12 +15652,12 @@ pub const CssEntryPointMeta = struct { imported_on_server: bool, }; -/// The lifetime of this structure is tied to the bundler's arena +/// The lifetime of this structure is tied to the transpiler's arena pub const BakeBundleStart = struct { css_entry_points: std.AutoArrayHashMapUnmanaged(Index, CssEntryPointMeta), }; -/// The lifetime of this structure is tied to the bundler's arena +/// The lifetime of this structure is tied to the transpiler's arena pub const BakeBundleOutput = struct { chunks: []Chunk, css_file_list: std.AutoArrayHashMapUnmanaged(Index, CssEntryPointMeta), diff --git a/src/bundler/entry_points.zig b/src/bundler/entry_points.zig index 306116742f..2636cc7960 100644 --- a/src/bundler/entry_points.zig +++ b/src/bundler/entry_points.zig @@ -4,7 +4,7 @@ const bun = @import("root").bun; const string = bun.string; const Fs = @import("../fs.zig"); const js_ast = bun.JSAst; -const Bundler = bun.Bundler; +const Transpiler = bun.Transpiler; const strings = bun.strings; pub const FallbackEntryPoint = struct { @@ -16,8 +16,8 @@ pub const FallbackEntryPoint = struct { pub fn generate( entry: *FallbackEntryPoint, input_path: string, - comptime BundlerType: type, - bundler: *BundlerType, + comptime TranspilerType: type, + transpiler: *TranspilerType, ) !void { // This is *extremely* naive. // The basic idea here is this: @@ -29,7 +29,7 @@ pub const FallbackEntryPoint = struct { // We go through the steps of printing the code -- only to then parse/transpile it because // we want it to go through the linker and the rest of the transpilation process - const disable_css_imports = bundler.options.framework.?.client_css_in_js != .auto_onimportcss; + const disable_css_imports = transpiler.options.framework.?.client_css_in_js != .auto_onimportcss; var code: string = undefined; @@ -48,7 +48,7 @@ pub const FallbackEntryPoint = struct { if (count < entry.code_buffer.len) { code = try std.fmt.bufPrint(&entry.code_buffer, fmt, args); } else { - code = try std.fmt.allocPrint(bundler.allocator, fmt, args); + code = try std.fmt.allocPrint(transpiler.allocator, fmt, args); } } else { const fmt = @@ -64,7 +64,7 @@ pub const FallbackEntryPoint = struct { if (count < entry.code_buffer.len) { code = try std.fmt.bufPrint(&entry.code_buffer, fmt, args); } else { - code = try std.fmt.allocPrint(bundler.allocator, fmt, args); + code = try std.fmt.allocPrint(transpiler.allocator, fmt, args); } } @@ -105,7 +105,7 @@ pub const ClientEntryPoint = struct { return outbuffer[0 .. generated_path.len + original_ext.len]; } - pub fn generate(entry: *ClientEntryPoint, comptime BundlerType: type, bundler: *BundlerType, original_path: Fs.PathName, client: string) !void { + pub fn generate(entry: *ClientEntryPoint, comptime TranspilerType: type, transpiler: *TranspilerType, original_path: Fs.PathName, client: string) !void { // This is *extremely* naive. // The basic idea here is this: @@ -118,7 +118,7 @@ pub const ClientEntryPoint = struct { // we want it to go through the linker and the rest of the transpilation process const dir_to_use: string = original_path.dirWithTrailingSlash(); - const disable_css_imports = bundler.options.framework.?.client_css_in_js != .auto_onimportcss; + const disable_css_imports = transpiler.options.framework.?.client_css_in_js != .auto_onimportcss; var code: string = undefined; @@ -266,7 +266,7 @@ pub const MacroEntryPoint = struct { pub fn generate( entry: *MacroEntryPoint, - _: *Bundler, + _: *Transpiler, import_path: Fs.PathName, function_name: string, macro_id: i32, diff --git a/src/cli.zig b/src/cli.zig index 9c11e4d2e9..d49b37200c 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -32,7 +32,7 @@ const configureTransformOptionsForBun = @import("./bun.js/config.zig").configure const clap = bun.clap; const BunJS = @import("./bun_js.zig"); const Install = @import("./install/install.zig"); -const bundler = bun.bundler; +const transpiler = bun.transpiler; const DotEnv = @import("./env_loader.zig"); const RunCommand_ = @import("./cli/run_command.zig").RunCommand; const CreateCommand_ = @import("./cli/create_command.zig").CreateCommand; diff --git a/src/cli/build_command.zig b/src/cli/build_command.zig index e5588e9373..88c449fc4f 100644 --- a/src/cli/build_command.zig +++ b/src/cli/build_command.zig @@ -25,7 +25,7 @@ const sync = @import("../sync.zig"); const Api = @import("../api/schema.zig").Api; const resolve_path = @import("../resolver/resolve_path.zig"); const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun; -const bundler = bun.bundler; +const transpiler = bun.transpiler; const DotEnv = @import("../env_loader.zig"); @@ -74,13 +74,13 @@ pub const BuildCommand = struct { } } - var this_bundler = try bundler.Bundler.init(allocator, log, ctx.args, null); + var this_transpiler = try transpiler.Transpiler.init(allocator, log, ctx.args, null); - this_bundler.options.source_map = options.SourceMapOption.fromApi(ctx.args.source_map); + this_transpiler.options.source_map = options.SourceMapOption.fromApi(ctx.args.source_map); - this_bundler.options.compile = ctx.bundler_options.compile; + this_transpiler.options.compile = ctx.bundler_options.compile; - if (this_bundler.options.source_map == .external and ctx.bundler_options.outdir.len == 0 and !ctx.bundler_options.compile) { + if (this_transpiler.options.source_map == .external and ctx.bundler_options.outdir.len == 0 and !ctx.bundler_options.compile) { Output.prettyErrorln("error: cannot use an external source map without --outdir", .{}); Global.exit(1); return; @@ -89,37 +89,37 @@ pub const BuildCommand = struct { var outfile = ctx.bundler_options.outfile; const output_to_stdout = !ctx.bundler_options.compile and outfile.len == 0 and ctx.bundler_options.outdir.len == 0; - this_bundler.options.supports_multiple_outputs = !(output_to_stdout or outfile.len > 0); + this_transpiler.options.supports_multiple_outputs = !(output_to_stdout or outfile.len > 0); - this_bundler.options.public_path = ctx.bundler_options.public_path; - this_bundler.options.entry_naming = ctx.bundler_options.entry_naming; - this_bundler.options.chunk_naming = ctx.bundler_options.chunk_naming; - this_bundler.options.asset_naming = ctx.bundler_options.asset_naming; - this_bundler.options.server_components = ctx.bundler_options.server_components; - this_bundler.options.react_fast_refresh = ctx.bundler_options.react_fast_refresh; - this_bundler.options.inline_entrypoint_import_meta_main = ctx.bundler_options.inline_entrypoint_import_meta_main; - this_bundler.options.code_splitting = ctx.bundler_options.code_splitting; - this_bundler.options.minify_syntax = ctx.bundler_options.minify_syntax; - this_bundler.options.minify_whitespace = ctx.bundler_options.minify_whitespace; - this_bundler.options.minify_identifiers = ctx.bundler_options.minify_identifiers; - this_bundler.options.emit_dce_annotations = ctx.bundler_options.emit_dce_annotations; - this_bundler.options.ignore_dce_annotations = ctx.bundler_options.ignore_dce_annotations; + this_transpiler.options.public_path = ctx.bundler_options.public_path; + this_transpiler.options.entry_naming = ctx.bundler_options.entry_naming; + this_transpiler.options.chunk_naming = ctx.bundler_options.chunk_naming; + this_transpiler.options.asset_naming = ctx.bundler_options.asset_naming; + this_transpiler.options.server_components = ctx.bundler_options.server_components; + this_transpiler.options.react_fast_refresh = ctx.bundler_options.react_fast_refresh; + this_transpiler.options.inline_entrypoint_import_meta_main = ctx.bundler_options.inline_entrypoint_import_meta_main; + this_transpiler.options.code_splitting = ctx.bundler_options.code_splitting; + this_transpiler.options.minify_syntax = ctx.bundler_options.minify_syntax; + this_transpiler.options.minify_whitespace = ctx.bundler_options.minify_whitespace; + this_transpiler.options.minify_identifiers = ctx.bundler_options.minify_identifiers; + this_transpiler.options.emit_dce_annotations = ctx.bundler_options.emit_dce_annotations; + this_transpiler.options.ignore_dce_annotations = ctx.bundler_options.ignore_dce_annotations; - this_bundler.options.banner = ctx.bundler_options.banner; - this_bundler.options.footer = ctx.bundler_options.footer; - this_bundler.options.drop = ctx.args.drop; + this_transpiler.options.banner = ctx.bundler_options.banner; + this_transpiler.options.footer = ctx.bundler_options.footer; + this_transpiler.options.drop = ctx.args.drop; - this_bundler.options.experimental_css = ctx.bundler_options.experimental_css; - this_bundler.options.css_chunking = ctx.bundler_options.css_chunking; + this_transpiler.options.experimental_css = ctx.bundler_options.experimental_css; + this_transpiler.options.css_chunking = ctx.bundler_options.css_chunking; - this_bundler.options.output_dir = ctx.bundler_options.outdir; - this_bundler.options.output_format = ctx.bundler_options.output_format; + this_transpiler.options.output_dir = ctx.bundler_options.outdir; + this_transpiler.options.output_format = ctx.bundler_options.output_format; if (ctx.bundler_options.output_format == .internal_bake_dev) { - this_bundler.options.tree_shaking = false; + this_transpiler.options.tree_shaking = false; } - this_bundler.options.bytecode = ctx.bundler_options.bytecode; + this_transpiler.options.bytecode = ctx.bundler_options.bytecode; if (ctx.bundler_options.compile) { if (ctx.bundler_options.code_splitting) { @@ -136,21 +136,21 @@ pub const BuildCommand = struct { const base_public_path = bun.StandaloneModuleGraph.targetBasePublicPath(compile_target.os, "root/"); - this_bundler.options.public_path = base_public_path; + this_transpiler.options.public_path = base_public_path; if (outfile.len == 0) { - outfile = std.fs.path.basename(this_bundler.options.entry_points[0]); + outfile = std.fs.path.basename(this_transpiler.options.entry_points[0]); const ext = std.fs.path.extension(outfile); if (ext.len > 0) { outfile = outfile[0 .. outfile.len - ext.len]; } if (strings.eqlComptime(outfile, "index")) { - outfile = std.fs.path.basename(std.fs.path.dirname(this_bundler.options.entry_points[0]) orelse "index"); + outfile = std.fs.path.basename(std.fs.path.dirname(this_transpiler.options.entry_points[0]) orelse "index"); } if (strings.eqlComptime(outfile, "bun")) { - outfile = std.fs.path.basename(std.fs.path.dirname(this_bundler.options.entry_points[0]) orelse "bun"); + outfile = std.fs.path.basename(std.fs.path.dirname(this_transpiler.options.entry_points[0]) orelse "bun"); } } @@ -169,12 +169,12 @@ pub const BuildCommand = struct { } if (ctx.bundler_options.outdir.len == 0 and !ctx.bundler_options.compile) { - if (this_bundler.options.entry_points.len > 1) { + if (this_transpiler.options.entry_points.len > 1) { Output.prettyErrorln("error: Must use --outdir when specifying more than one entry point.", .{}); Global.exit(1); return; } - if (this_bundler.options.code_splitting) { + if (this_transpiler.options.code_splitting) { Output.prettyErrorln("error: Must use --outdir when code splitting is enabled", .{}); Global.exit(1); return; @@ -188,11 +188,11 @@ pub const BuildCommand = struct { break :brk2 ctx.bundler_options.root_dir; } - if (this_bundler.options.entry_points.len == 1) { - break :brk2 std.fs.path.dirname(this_bundler.options.entry_points[0]) orelse "."; + if (this_transpiler.options.entry_points.len == 1) { + break :brk2 std.fs.path.dirname(this_transpiler.options.entry_points[0]) orelse "."; } - break :brk2 resolve_path.getIfExistsLongestCommonPath(this_bundler.options.entry_points) orelse "."; + break :brk2 resolve_path.getIfExistsLongestCommonPath(this_transpiler.options.entry_points) orelse "."; }; var dir = bun.openDirForPath(&(try std.posix.toPosixPath(path))) catch |err| { @@ -207,47 +207,47 @@ pub const BuildCommand = struct { }; }; - this_bundler.options.root_dir = src_root_dir; - this_bundler.options.code_splitting = ctx.bundler_options.code_splitting; - this_bundler.options.transform_only = ctx.bundler_options.transform_only; + this_transpiler.options.root_dir = src_root_dir; + this_transpiler.options.code_splitting = ctx.bundler_options.code_splitting; + this_transpiler.options.transform_only = ctx.bundler_options.transform_only; - this_bundler.options.env.behavior = ctx.bundler_options.env_behavior; - this_bundler.options.env.prefix = ctx.bundler_options.env_prefix; + this_transpiler.options.env.behavior = ctx.bundler_options.env_behavior; + this_transpiler.options.env.prefix = ctx.bundler_options.env_prefix; - try this_bundler.configureDefines(); - this_bundler.configureLinker(); + try this_transpiler.configureDefines(); + this_transpiler.configureLinker(); if (bun.FeatureFlags.breaking_changes_1_2) { // This is currently done in DevServer by default, but not in Bun.build - if (!this_bundler.options.production) { - try this_bundler.options.conditions.appendSlice(&.{"development"}); + if (!this_transpiler.options.production) { + try this_transpiler.options.conditions.appendSlice(&.{"development"}); } } - this_bundler.resolver.opts = this_bundler.options; - this_bundler.options.jsx.development = !this_bundler.options.production; - this_bundler.resolver.opts.jsx.development = this_bundler.options.jsx.development; + this_transpiler.resolver.opts = this_transpiler.options; + this_transpiler.options.jsx.development = !this_transpiler.options.production; + this_transpiler.resolver.opts.jsx.development = this_transpiler.options.jsx.development; switch (ctx.debug.macros) { .disable => { - this_bundler.options.no_macros = true; + this_transpiler.options.no_macros = true; }, .map => |macros| { - this_bundler.options.macro_remap = macros; + this_transpiler.options.macro_remap = macros; }, .unspecified => {}, } - var client_bundler: bundler.Bundler = undefined; - if (this_bundler.options.server_components) { - client_bundler = try bundler.Bundler.init(allocator, log, ctx.args, null); - client_bundler.options = this_bundler.options; + var client_bundler: transpiler.Transpiler = undefined; + if (this_transpiler.options.server_components) { + client_bundler = try transpiler.Transpiler.init(allocator, log, ctx.args, null); + client_bundler.options = this_transpiler.options; client_bundler.options.target = .browser; client_bundler.options.server_components = true; - client_bundler.options.conditions = try this_bundler.options.conditions.clone(); - try this_bundler.options.conditions.appendSlice(&.{"react-server"}); - this_bundler.options.react_fast_refresh = false; - this_bundler.options.minify_syntax = true; + client_bundler.options.conditions = try this_transpiler.options.conditions.clone(); + try this_transpiler.options.conditions.appendSlice(&.{"react-server"}); + this_transpiler.options.react_fast_refresh = false; + this_transpiler.options.minify_syntax = true; client_bundler.options.minify_syntax = true; client_bundler.options.define = try options.Define.init( allocator, @@ -261,20 +261,20 @@ pub const BuildCommand = struct { else null, null, - this_bundler.options.define.drop_debugger, + this_transpiler.options.define.drop_debugger, ); - try bun.bake.addImportMetaDefines(allocator, this_bundler.options.define, .development, .server); + try bun.bake.addImportMetaDefines(allocator, this_transpiler.options.define, .development, .server); try bun.bake.addImportMetaDefines(allocator, client_bundler.options.define, .development, .client); - this_bundler.resolver.opts = this_bundler.options; + this_transpiler.resolver.opts = this_transpiler.options; client_bundler.resolver.opts = client_bundler.options; } - // var env_loader = this_bundler.env; + // var env_loader = this_transpiler.env; if (ctx.debug.dump_environment_variables) { - this_bundler.dumpEnvironmentVariables(); + this_transpiler.dumpEnvironmentVariables(); return; } @@ -284,12 +284,12 @@ pub const BuildCommand = struct { const output_files: []options.OutputFile = brk: { if (ctx.bundler_options.transform_only) { - this_bundler.options.import_path_format = .relative; - this_bundler.options.allow_runtime = false; - this_bundler.resolver.opts.allow_runtime = false; + this_transpiler.options.import_path_format = .relative; + this_transpiler.options.allow_runtime = false; + this_transpiler.resolver.opts.allow_runtime = false; // TODO: refactor this .transform function - const result = try this_bundler.transform( + const result = try this_transpiler.transform( ctx.allocator, ctx.log, ctx.args, @@ -309,7 +309,7 @@ pub const BuildCommand = struct { } break :brk (BundleV2.generateFromCLI( - &this_bundler, + &this_transpiler, allocator, bun.JSC.AnyEventLoop.init(ctx.allocator), ctx.debug.hot_reload == .watch, @@ -335,7 +335,7 @@ pub const BuildCommand = struct { dump: { defer Output.flush(); var writer = Output.writer(); - var output_dir = this_bundler.options.output_dir; + var output_dir = this_transpiler.options.output_dir; const will_be_one_file = // --outdir is not supported with --compile @@ -391,7 +391,7 @@ pub const BuildCommand = struct { printSummary( bundled_end, minify_duration, - this_bundler.options.minify_identifiers or this_bundler.options.minify_whitespace or this_bundler.options.minify_syntax, + this_transpiler.options.minify_identifiers or this_transpiler.options.minify_whitespace or this_transpiler.options.minify_syntax, input_code_length, reachable_file_count, output_files, @@ -414,10 +414,10 @@ pub const BuildCommand = struct { allocator, output_files, root_dir, - this_bundler.options.public_path, + this_transpiler.options.public_path, outfile, - this_bundler.env, - this_bundler.options.output_format, + this_transpiler.env, + this_transpiler.options.output_format, ctx.bundler_options.windows_hide_console, ctx.bundler_options.windows_icon, ); @@ -478,7 +478,7 @@ pub const BuildCommand = struct { Output.printElapsedStdoutTrim( @as(f64, @floatFromInt((@divTrunc(@as(i64, @truncate(std.time.nanoTimestamp() - bun.CLI.start_time)), @as(i64, std.time.ns_per_ms))))), ); - if (this_bundler.options.transform_only) { + if (this_transpiler.options.transform_only) { Output.prettyln(" transpile", .{}); } else { Output.prettyln(" bundle {d} modules", .{ diff --git a/src/cli/bunx_command.zig b/src/cli/bunx_command.zig index 1afa6fd6ff..5eb50b4d20 100644 --- a/src/cli/bunx_command.zig +++ b/src/cli/bunx_command.zig @@ -63,13 +63,13 @@ pub const BunxCommand = struct { /// 1 day const nanoseconds_cache_valid = seconds_cache_valid * 1000000000; - fn getBinNameFromSubpath(bundler: *bun.Bundler, dir_fd: bun.FileDescriptor, subpath_z: [:0]const u8) ![]const u8 { + fn getBinNameFromSubpath(transpiler: *bun.Transpiler, dir_fd: bun.FileDescriptor, subpath_z: [:0]const u8) ![]const u8 { const target_package_json_fd = try bun.sys.openat(dir_fd, subpath_z, bun.O.RDONLY, 0).unwrap(); const target_package_json = bun.sys.File{ .handle = target_package_json_fd }; defer target_package_json.close(); - const package_json_read = target_package_json.readToEnd(bundler.allocator); + const package_json_read = target_package_json.readToEnd(transpiler.allocator); // TODO: make this better if (package_json_read.err) |err| { @@ -82,7 +82,7 @@ pub const BunxCommand = struct { bun.JSAst.Expr.Data.Store.create(); bun.JSAst.Stmt.Data.Store.create(); - const expr = try bun.JSON.parsePackageJSONUTF8(&source, bundler.log, bundler.allocator); + const expr = try bun.JSON.parsePackageJSONUTF8(&source, transpiler.log, transpiler.allocator); // choose the first package that fits if (expr.get("bin")) |bin_expr| { @@ -90,7 +90,7 @@ pub const BunxCommand = struct { .e_object => |object| { for (object.properties.slice()) |prop| { if (prop.key) |key| { - if (key.asString(bundler.allocator)) |bin_name| { + if (key.asString(transpiler.allocator)) |bin_name| { if (bin_name.len == 0) continue; return bin_name; } @@ -99,7 +99,7 @@ pub const BunxCommand = struct { }, .e_string => { if (expr.get("name")) |name_expr| { - if (name_expr.asString(bundler.allocator)) |name| { + if (name_expr.asString(transpiler.allocator)) |name| { return name; } } @@ -110,7 +110,7 @@ pub const BunxCommand = struct { if (expr.asProperty("directories")) |dirs| { if (dirs.expr.asProperty("bin")) |bin_prop| { - if (bin_prop.expr.asString(bundler.allocator)) |dir_name| { + if (bin_prop.expr.asString(transpiler.allocator)) |dir_name| { const bin_dir = try bun.sys.openatA(dir_fd, dir_name, bun.O.RDONLY | bun.O.DIRECTORY, 0).unwrap(); defer _ = bun.sys.close(bin_dir); const dir = std.fs.Dir{ .fd = bin_dir.cast() }; @@ -124,7 +124,7 @@ pub const BunxCommand = struct { if (current.kind == .file) { if (current.name.len == 0) continue; - return try bundler.allocator.dupe(u8, current.name.slice()); + return try transpiler.allocator.dupe(u8, current.name.slice()); } } } @@ -134,13 +134,13 @@ pub const BunxCommand = struct { return error.NoBinFound; } - fn getBinNameFromProjectDirectory(bundler: *bun.Bundler, dir_fd: bun.FileDescriptor, package_name: []const u8) ![]const u8 { + fn getBinNameFromProjectDirectory(transpiler: *bun.Transpiler, dir_fd: bun.FileDescriptor, package_name: []const u8) ![]const u8 { var subpath: bun.PathBuffer = undefined; const subpath_z = std.fmt.bufPrintZ(&subpath, bun.pathLiteral("node_modules/{s}/package.json"), .{package_name}) catch unreachable; - return try getBinNameFromSubpath(bundler, dir_fd, subpath_z); + return try getBinNameFromSubpath(transpiler, dir_fd, subpath_z); } - fn getBinNameFromTempDirectory(bundler: *bun.Bundler, tempdir_name: []const u8, package_name: []const u8, with_stale_check: bool) ![]const u8 { + fn getBinNameFromTempDirectory(transpiler: *bun.Transpiler, tempdir_name: []const u8, package_name: []const u8, with_stale_check: bool) ![]const u8 { var subpath: bun.PathBuffer = undefined; if (with_stale_check) { const subpath_z = std.fmt.bufPrintZ( @@ -186,19 +186,19 @@ pub const BunxCommand = struct { .{ tempdir_name, package_name }, ) catch unreachable; - return try getBinNameFromSubpath(bundler, bun.FD.cwd(), subpath_z); + return try getBinNameFromSubpath(transpiler, bun.FD.cwd(), subpath_z); } /// Check the enclosing package.json for a matching "bin" /// If not found, check bunx cache dir - fn getBinName(bundler: *bun.Bundler, toplevel_fd: bun.FileDescriptor, tempdir_name: []const u8, package_name: []const u8) error{ NoBinFound, NeedToInstall }![]const u8 { + fn getBinName(transpiler: *bun.Transpiler, toplevel_fd: bun.FileDescriptor, tempdir_name: []const u8, package_name: []const u8) error{ NoBinFound, NeedToInstall }![]const u8 { toplevel_fd.assertValid(); - return getBinNameFromProjectDirectory(bundler, toplevel_fd, package_name) catch |err| { + return getBinNameFromProjectDirectory(transpiler, toplevel_fd, package_name) catch |err| { if (err == error.NoBinFound) { return error.NoBinFound; } - return getBinNameFromTempDirectory(bundler, tempdir_name, package_name, true) catch |err2| { + return getBinNameFromTempDirectory(transpiler, tempdir_name, package_name, true) catch |err2| { if (err2 == error.NoBinFound) { return error.NoBinFound; } @@ -304,12 +304,12 @@ pub const BunxCommand = struct { // fast path: they're actually using this interchangeably with `bun run` // so we use Bun.which to check - var this_bundler: bun.Bundler = undefined; + var this_transpiler: bun.Transpiler = undefined; var ORIGINAL_PATH: string = ""; const root_dir_info = try Run.configureEnvForRun( ctx, - &this_bundler, + &this_transpiler, null, true, true, @@ -318,28 +318,28 @@ pub const BunxCommand = struct { try Run.configurePathForRun( ctx, root_dir_info, - &this_bundler, + &this_transpiler, &ORIGINAL_PATH, root_dir_info.abs_path, ctx.debug.run_in_bun, ); - this_bundler.env.map.put("npm_command", "exec") catch unreachable; - this_bundler.env.map.put("npm_lifecycle_event", "bunx") catch unreachable; - this_bundler.env.map.put("npm_lifecycle_script", package_name) catch unreachable; + this_transpiler.env.map.put("npm_command", "exec") catch unreachable; + this_transpiler.env.map.put("npm_lifecycle_event", "bunx") catch unreachable; + this_transpiler.env.map.put("npm_lifecycle_script", package_name) catch unreachable; if (strings.eqlComptime(package_name, "bun-repl")) { - this_bundler.env.map.remove("BUN_INSPECT_CONNECT_TO"); - this_bundler.env.map.remove("BUN_INSPECT_NOTIFY"); - this_bundler.env.map.remove("BUN_INSPECT"); + this_transpiler.env.map.remove("BUN_INSPECT_CONNECT_TO"); + this_transpiler.env.map.remove("BUN_INSPECT_NOTIFY"); + this_transpiler.env.map.remove("BUN_INSPECT"); } - const ignore_cwd = this_bundler.env.get("BUN_WHICH_IGNORE_CWD") orelse ""; + const ignore_cwd = this_transpiler.env.get("BUN_WHICH_IGNORE_CWD") orelse ""; if (ignore_cwd.len > 0) { - _ = this_bundler.env.map.map.swapRemove("BUN_WHICH_IGNORE_CWD"); + _ = this_transpiler.env.map.map.swapRemove("BUN_WHICH_IGNORE_CWD"); } - var PATH = this_bundler.env.get("PATH").?; + var PATH = this_transpiler.env.get("PATH").?; const display_version = if (update_request.version.literal.isEmpty()) "latest" else @@ -454,7 +454,7 @@ pub const BunxCommand = struct { ), }; - try this_bundler.env.map.put("PATH", PATH); + try this_transpiler.env.map.put("PATH", PATH); const bunx_cache_dir = PATH[0 .. temp_dir.len + "/bunx--".len + package_fmt.len + @@ -481,7 +481,7 @@ pub const BunxCommand = struct { destination_ = bun.which( &path_buf, PATH_FOR_BIN_DIRS, - if (ignore_cwd.len > 0) "" else this_bundler.fs.top_level_dir, + if (ignore_cwd.len > 0) "" else this_transpiler.fs.top_level_dir, initial_bin_name, ); } @@ -492,7 +492,7 @@ pub const BunxCommand = struct { if (destination_ orelse bun.which( &path_buf, bunx_cache_dir, - if (ignore_cwd.len > 0) "" else this_bundler.fs.top_level_dir, + if (ignore_cwd.len > 0) "" else this_transpiler.fs.top_level_dir, absolute_in_cache_dir, )) |destination| { const out = bun.asByteSlice(destination); @@ -539,10 +539,10 @@ pub const BunxCommand = struct { try Run.runBinary( ctx, - try this_bundler.fs.dirname_store.append(@TypeOf(out), out), + try this_transpiler.fs.dirname_store.append(@TypeOf(out), out), destination, - this_bundler.fs.top_level_dir, - this_bundler.env, + this_transpiler.fs.top_level_dir, + this_transpiler.env, passthrough, null, ); @@ -553,7 +553,7 @@ pub const BunxCommand = struct { // 2. The "bin" is possibly not the same as the package name, so we load the package.json to figure out what "bin" to use const root_dir_fd = root_dir_info.getFileDescriptor(); bun.assert(root_dir_fd != .zero); - if (getBinName(&this_bundler, root_dir_fd, bunx_cache_dir, initial_bin_name)) |package_name_for_bin| { + if (getBinName(&this_transpiler, root_dir_fd, bunx_cache_dir, initial_bin_name)) |package_name_for_bin| { // if we check the bin name and its actually the same, we don't need to check $PATH here again if (!strings.eqlLong(package_name_for_bin, initial_bin_name, true)) { absolute_in_cache_dir = std.fmt.bufPrint(&absolute_in_cache_dir_buf, bun.pathLiteral("{s}/node_modules/.bin/{s}{s}"), .{ bunx_cache_dir, package_name_for_bin, bun.exe_suffix }) catch unreachable; @@ -563,7 +563,7 @@ pub const BunxCommand = struct { destination_ = bun.which( &path_buf, bunx_cache_dir, - if (ignore_cwd.len > 0) "" else this_bundler.fs.top_level_dir, + if (ignore_cwd.len > 0) "" else this_transpiler.fs.top_level_dir, package_name_for_bin, ); } @@ -571,16 +571,16 @@ pub const BunxCommand = struct { if (destination_ orelse bun.which( &path_buf, bunx_cache_dir, - if (ignore_cwd.len > 0) "" else this_bundler.fs.top_level_dir, + if (ignore_cwd.len > 0) "" else this_transpiler.fs.top_level_dir, absolute_in_cache_dir, )) |destination| { const out = bun.asByteSlice(destination); try Run.runBinary( ctx, - try this_bundler.fs.dirname_store.append(@TypeOf(out), out), + try this_transpiler.fs.dirname_store.append(@TypeOf(out), out), destination, - this_bundler.fs.top_level_dir, - this_bundler.env, + this_transpiler.fs.top_level_dir, + this_transpiler.env, passthrough, null, ); @@ -636,12 +636,12 @@ pub const BunxCommand = struct { const argv_to_use = args.slice(); debug("installing package: {s}", .{bun.fmt.fmtSlice(argv_to_use, " ")}); - this_bundler.env.map.put("BUN_INTERNAL_BUNX_INSTALL", "true") catch bun.outOfMemory(); + this_transpiler.env.map.put("BUN_INTERNAL_BUNX_INSTALL", "true") catch bun.outOfMemory(); const spawn_result = switch ((bun.spawnSync(&.{ .argv = argv_to_use, - .envp = try this_bundler.env.map.createNullDelimitedEnvMap(bun.default_allocator), + .envp = try this_transpiler.env.map.createNullDelimitedEnvMap(bun.default_allocator), .cwd = bunx_cache_dir, .stderr = .inherit, @@ -649,7 +649,7 @@ pub const BunxCommand = struct { .stdin = .inherit, .windows = if (Environment.isWindows) .{ - .loop = bun.JSC.EventLoopHandle.init(bun.JSC.MiniEventLoop.initGlobal(this_bundler.env)), + .loop = bun.JSC.EventLoopHandle.init(bun.JSC.MiniEventLoop.initGlobal(this_transpiler.env)), } else {}, }) catch |err| { Output.prettyErrorln("error: bunx failed to install {s} due to error {s}", .{ install_param, @errorName(err) }); @@ -691,16 +691,16 @@ pub const BunxCommand = struct { if (bun.which( &path_buf, bunx_cache_dir, - if (ignore_cwd.len > 0) "" else this_bundler.fs.top_level_dir, + if (ignore_cwd.len > 0) "" else this_transpiler.fs.top_level_dir, absolute_in_cache_dir, )) |destination| { const out = bun.asByteSlice(destination); try Run.runBinary( ctx, - try this_bundler.fs.dirname_store.append(@TypeOf(out), out), + try this_transpiler.fs.dirname_store.append(@TypeOf(out), out), destination, - this_bundler.fs.top_level_dir, - this_bundler.env, + this_transpiler.fs.top_level_dir, + this_transpiler.env, passthrough, null, ); @@ -709,23 +709,23 @@ pub const BunxCommand = struct { } // 2. The "bin" is possibly not the same as the package name, so we load the package.json to figure out what "bin" to use - if (getBinNameFromTempDirectory(&this_bundler, bunx_cache_dir, result_package_name, false)) |package_name_for_bin| { + if (getBinNameFromTempDirectory(&this_transpiler, bunx_cache_dir, result_package_name, false)) |package_name_for_bin| { if (!strings.eqlLong(package_name_for_bin, initial_bin_name, true)) { absolute_in_cache_dir = std.fmt.bufPrint(&absolute_in_cache_dir_buf, "{s}/node_modules/.bin/{s}{s}", .{ bunx_cache_dir, package_name_for_bin, bun.exe_suffix }) catch unreachable; if (bun.which( &path_buf, bunx_cache_dir, - if (ignore_cwd.len > 0) "" else this_bundler.fs.top_level_dir, + if (ignore_cwd.len > 0) "" else this_transpiler.fs.top_level_dir, absolute_in_cache_dir, )) |destination| { const out = bun.asByteSlice(destination); try Run.runBinary( ctx, - try this_bundler.fs.dirname_store.append(@TypeOf(out), out), + try this_transpiler.fs.dirname_store.append(@TypeOf(out), out), destination, - this_bundler.fs.top_level_dir, - this_bundler.env, + this_transpiler.fs.top_level_dir, + this_transpiler.env, passthrough, null, ); diff --git a/src/cli/create_command.zig b/src/cli/create_command.zig index 0c81ee3730..9e20a74530 100644 --- a/src/cli/create_command.zig +++ b/src/cli/create_command.zig @@ -25,7 +25,6 @@ const Api = @import("../api/schema.zig").Api; const resolve_path = @import("../resolver/resolve_path.zig"); const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun; const Command = @import("../cli.zig").Command; -const bundler = bun.bundler; const fs = @import("../fs.zig"); const URL = @import("../url.zig").URL; diff --git a/src/cli/exec_command.zig b/src/cli/exec_command.zig index 5ea2fd36cc..0711d7b1e3 100644 --- a/src/cli/exec_command.zig +++ b/src/cli/exec_command.zig @@ -16,7 +16,7 @@ pub const ExecCommand = struct { pub fn exec(ctx: Command.Context) !void { const script = ctx.positionals[1]; // this is a hack: make dummy bundler so we can use its `.runEnvLoader()` function to populate environment variables probably should split out the functionality - var bundle = try bun.Bundler.init( + var bundle = try bun.Transpiler.init( ctx.allocator, ctx.log, try @import("../bun.js/config.zig").configureTransformOptionsForBunVM(ctx.allocator, ctx.args), diff --git a/src/cli/filter_run.zig b/src/cli/filter_run.zig index aad627d3d2..cede921e3f 100644 --- a/src/cli/filter_run.zig +++ b/src/cli/filter_run.zig @@ -11,7 +11,7 @@ const SemverString = @import("../install/semver.zig").String; const CLI = bun.CLI; const Command = CLI.Command; -const bundler = bun.bundler; +const transpiler = bun.transpiler; const FilterArg = @import("filter_arg.zig"); @@ -459,8 +459,8 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn { var root_buf: bun.PathBuffer = undefined; const resolve_root = try FilterArg.getCandidatePackagePatterns(ctx.allocator, ctx.log, &patterns, fsinstance.top_level_dir, &root_buf); - var this_bundler: bundler.Bundler = undefined; - _ = try RunCommand.configureEnvForRun(ctx, &this_bundler, null, true, false); + var this_transpiler: transpiler.Transpiler = undefined; + _ = try RunCommand.configureEnvForRun(ctx, &this_transpiler, null, true, false); var package_json_iter = try FilterArg.PackageFilterIterator.init(ctx.allocator, patterns.items, resolve_root); defer package_json_iter.deinit(); @@ -472,7 +472,7 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn { const dirpath = std.fs.path.dirname(package_json_path) orelse Global.crash(); const path = bun.strings.withoutTrailingSlash(dirpath); - const pkgjson = bun.PackageJSON.parse(&this_bundler.resolver, dirpath, .zero, null, .include_scripts, .main, .no_hash) orelse { + const pkgjson = bun.PackageJSON.parse(&this_transpiler.resolver, dirpath, .zero, null, .include_scripts, .main, .no_hash) orelse { Output.warn("Failed to read package.json\n", .{}); continue; }; @@ -482,7 +482,7 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn { if (!filter_instance.matches(path, pkgjson.name)) continue; - const PATH = try RunCommand.configurePathForRunWithPackageJsonDir(ctx, dirpath, &this_bundler, null, dirpath, ctx.debug.run_in_bun); + const PATH = try RunCommand.configurePathForRunWithPackageJsonDir(ctx, dirpath, &this_transpiler, null, dirpath, ctx.debug.run_in_bun); for (&[3][]const u8{ pre_script_name, script_name, post_script_name }) |name| { const original_content = pkgscripts.get(name) orelse continue; @@ -522,9 +522,9 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn { Global.exit(1); } - const event_loop = bun.JSC.MiniEventLoop.initGlobal(this_bundler.env); + const event_loop = bun.JSC.MiniEventLoop.initGlobal(this_transpiler.env); const shell_bin: [:0]const u8 = if (Environment.isPosix) - RunCommand.findShell(this_bundler.env.get("PATH") orelse "", fsinstance.top_level_dir) orelse return error.MissingShell + RunCommand.findShell(this_transpiler.env.get("PATH") orelse "", fsinstance.top_level_dir) orelse return error.MissingShell else bun.selfExePath() catch return error.MissingShell; @@ -533,7 +533,7 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn { .event_loop = event_loop, .pretty_output = if (Environment.isWindows) windowsIsTerminal() else Output.enable_ansi_colors_stdout, .shell_bin = shell_bin, - .env = this_bundler.env, + .env = this_transpiler.env, }; // initialize the handles diff --git a/src/cli/install_completions_command.zig b/src/cli/install_completions_command.zig index 575c79f354..ba1053397d 100644 --- a/src/cli/install_completions_command.zig +++ b/src/cli/install_completions_command.zig @@ -24,7 +24,6 @@ const Api = @import("../api/schema.zig").Api; const resolve_path = @import("../resolver/resolve_path.zig"); const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun; const Command = @import("../cli.zig").Command; -const bundler = bun.bundler; const fs = @import("../fs.zig"); const URL = @import("../url.zig").URL; diff --git a/src/cli/pack_command.zig b/src/cli/pack_command.zig index 1aae3deb27..763ecead80 100644 --- a/src/cli/pack_command.zig +++ b/src/cli/pack_command.zig @@ -1140,11 +1140,11 @@ pub const PackCommand = struct { const edited_package_json = try editRootPackageJSON(ctx.allocator, ctx.lockfile, json); - var this_bundler: bun.bundler.Bundler = undefined; + var this_transpiler: bun.transpiler.Transpiler = undefined; _ = RunCommand.configureEnvForRun( ctx.command_ctx, - &this_bundler, + &this_transpiler, manager.env, manager.options.log_level != .silent, false, @@ -1177,7 +1177,7 @@ pub const PackCommand = struct { prepublish_only, "prepublishOnly", abs_workspace_path, - this_bundler.env, + this_transpiler.env, &.{}, manager.options.log_level == .silent, ctx.command_ctx.debug.use_system_shell, @@ -1202,7 +1202,7 @@ pub const PackCommand = struct { prepack_script_str, "prepack", abs_workspace_path, - this_bundler.env, + this_transpiler.env, &.{}, manager.options.log_level == .silent, ctx.command_ctx.debug.use_system_shell, @@ -1226,7 +1226,7 @@ pub const PackCommand = struct { prepare_script_str, "prepare", abs_workspace_path, - this_bundler.env, + this_transpiler.env, &.{}, manager.options.log_level == .silent, ctx.command_ctx.debug.use_system_shell, @@ -1393,7 +1393,7 @@ pub const PackCommand = struct { .uses_workspaces = false, .publish_script = publish_script, .postpublish_script = postpublish_script, - .script_env = this_bundler.env, + .script_env = this_transpiler.env, .normalized_pkg_info = "", }; } @@ -1719,7 +1719,7 @@ pub const PackCommand = struct { .uses_workspaces = false, .publish_script = publish_script, .postpublish_script = postpublish_script, - .script_env = this_bundler.env, + .script_env = this_transpiler.env, .normalized_pkg_info = normalized_pkg_info, }; } diff --git a/src/cli/run_command.zig b/src/cli/run_command.zig index 78c0c3601d..ab39f134e8 100644 --- a/src/cli/run_command.zig +++ b/src/cli/run_command.zig @@ -33,7 +33,7 @@ const sync = @import("../sync.zig"); const Api = @import("../api/schema.zig").Api; const resolve_path = @import("../resolver/resolve_path.zig"); const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun; -const bundler = bun.bundler; +const transpiler = bun.transpiler; const DotEnv = @import("../env_loader.zig"); const which = @import("../which.zig").which; @@ -615,13 +615,13 @@ pub const RunCommand = struct { pub fn ls(ctx: Command.Context) !void { const args = ctx.args; - var this_bundler = try bundler.Bundler.init(ctx.allocator, ctx.log, args, null); - this_bundler.options.env.behavior = Api.DotEnvBehavior.load_all; - this_bundler.options.env.prefix = ""; + var this_transpiler = try transpiler.Transpiler.init(ctx.allocator, ctx.log, args, null); + this_transpiler.options.env.behavior = Api.DotEnvBehavior.load_all; + this_transpiler.options.env.prefix = ""; - this_bundler.resolver.care_about_bin_folder = true; - this_bundler.resolver.care_about_scripts = true; - this_bundler.configureLinker(); + this_transpiler.resolver.care_about_bin_folder = true; + this_transpiler.resolver.care_about_scripts = true; + this_transpiler.configureLinker(); } pub const bun_node_dir = switch (Environment.os) { @@ -792,30 +792,30 @@ pub const RunCommand = struct { const DirInfo = @import("../resolver/dir_info.zig"); pub fn configureEnvForRun( ctx: Command.Context, - this_bundler: *bundler.Bundler, + this_transpiler: *transpiler.Transpiler, env: ?*DotEnv.Loader, log_errors: bool, store_root_fd: bool, ) !*DirInfo { const args = ctx.args; - this_bundler.* = try bundler.Bundler.init(ctx.allocator, ctx.log, args, env); - this_bundler.options.env.behavior = Api.DotEnvBehavior.load_all; - this_bundler.env.quiet = true; - this_bundler.options.env.prefix = ""; + this_transpiler.* = try transpiler.Transpiler.init(ctx.allocator, ctx.log, args, env); + this_transpiler.options.env.behavior = Api.DotEnvBehavior.load_all; + this_transpiler.env.quiet = true; + this_transpiler.options.env.prefix = ""; - this_bundler.resolver.care_about_bin_folder = true; - this_bundler.resolver.care_about_scripts = true; - this_bundler.resolver.store_fd = store_root_fd; + this_transpiler.resolver.care_about_bin_folder = true; + this_transpiler.resolver.care_about_scripts = true; + this_transpiler.resolver.store_fd = store_root_fd; - this_bundler.resolver.opts.load_tsconfig_json = false; - this_bundler.options.load_tsconfig_json = false; + this_transpiler.resolver.opts.load_tsconfig_json = false; + this_transpiler.options.load_tsconfig_json = false; - this_bundler.configureLinker(); + this_transpiler.configureLinker(); - const root_dir_info = this_bundler.resolver.readDirInfo(this_bundler.fs.top_level_dir) catch |err| { + const root_dir_info = this_transpiler.resolver.readDirInfo(this_transpiler.fs.top_level_dir) catch |err| { if (!log_errors) return error.CouldntReadCurrentDirectory; ctx.log.print(Output.errorWriter()) catch {}; - Output.prettyErrorln("error: {s} loading directory {}", .{ @errorName(err), bun.fmt.QuotedFormatter{ .text = this_bundler.fs.top_level_dir } }); + Output.prettyErrorln("error: {s} loading directory {}", .{ @errorName(err), bun.fmt.QuotedFormatter{ .text = this_transpiler.fs.top_level_dir } }); Output.flush(); return err; } orelse { @@ -825,26 +825,26 @@ pub const RunCommand = struct { return error.CouldntReadCurrentDirectory; }; - this_bundler.resolver.store_fd = false; + this_transpiler.resolver.store_fd = false; if (env == null) { - this_bundler.env.loadProcess(); + this_transpiler.env.loadProcess(); - if (this_bundler.env.get("NODE_ENV")) |node_env| { + if (this_transpiler.env.get("NODE_ENV")) |node_env| { if (strings.eqlComptime(node_env, "production")) { - this_bundler.options.production = true; + this_transpiler.options.production = true; } } - this_bundler.runEnvLoader(true) catch {}; + this_transpiler.runEnvLoader(true) catch {}; } - this_bundler.env.map.putDefault("npm_config_local_prefix", this_bundler.fs.top_level_dir) catch unreachable; + this_transpiler.env.map.putDefault("npm_config_local_prefix", this_transpiler.fs.top_level_dir) catch unreachable; // we have no way of knowing what version they're expecting without running the node executable // running the node executable is too slow // so we will just hardcode it to LTS - this_bundler.env.map.putDefault( + this_transpiler.env.map.putDefault( "npm_config_user_agent", // the use of npm/? is copying yarn // e.g. @@ -852,33 +852,33 @@ pub const RunCommand = struct { "bun/" ++ Global.package_json_version ++ " npm/? node/v" ++ Environment.reported_nodejs_version ++ " " ++ Global.os_name ++ " " ++ Global.arch_name, ) catch unreachable; - if (this_bundler.env.get("npm_execpath") == null) { + if (this_transpiler.env.get("npm_execpath") == null) { // we don't care if this fails if (bun.selfExePath()) |self_exe_path| { - this_bundler.env.map.putDefault("npm_execpath", self_exe_path) catch unreachable; + this_transpiler.env.map.putDefault("npm_execpath", self_exe_path) catch unreachable; } else |_| {} } if (root_dir_info.enclosing_package_json) |package_json| { if (package_json.name.len > 0) { - if (this_bundler.env.map.get(NpmArgs.package_name) == null) { - this_bundler.env.map.put(NpmArgs.package_name, package_json.name) catch unreachable; + if (this_transpiler.env.map.get(NpmArgs.package_name) == null) { + this_transpiler.env.map.put(NpmArgs.package_name, package_json.name) catch unreachable; } } - this_bundler.env.map.putDefault("npm_package_json", package_json.source.path.text) catch unreachable; + this_transpiler.env.map.putDefault("npm_package_json", package_json.source.path.text) catch unreachable; if (package_json.version.len > 0) { - if (this_bundler.env.map.get(NpmArgs.package_version) == null) { - this_bundler.env.map.put(NpmArgs.package_version, package_json.version) catch unreachable; + if (this_transpiler.env.map.get(NpmArgs.package_version) == null) { + this_transpiler.env.map.put(NpmArgs.package_version, package_json.version) catch unreachable; } } if (package_json.config) |config| { - try this_bundler.env.map.ensureUnusedCapacity(config.count()); + try this_transpiler.env.map.ensureUnusedCapacity(config.count()); for (config.keys(), config.values()) |k, v| { const key = try bun.strings.concat(bun.default_allocator, &.{ "npm_package_config_", k }); - this_bundler.env.map.putAssumeCapacity(key, v); + this_transpiler.env.map.putAssumeCapacity(key, v); } } } @@ -889,20 +889,20 @@ pub const RunCommand = struct { pub fn configurePathForRunWithPackageJsonDir( ctx: Command.Context, package_json_dir: string, - this_bundler: *bundler.Bundler, + this_transpiler: *transpiler.Transpiler, ORIGINAL_PATH: ?*string, cwd: string, force_using_bun: bool, ) ![]u8 { - const PATH = this_bundler.env.get("PATH") orelse ""; + const PATH = this_transpiler.env.get("PATH") orelse ""; if (ORIGINAL_PATH) |original_path| { original_path.* = PATH; } const bun_node_exe = try bunNodeFileUtf8(ctx.allocator); const bun_node_dir_win = bun.Dirname.dirname(u8, bun_node_exe) orelse return error.FailedToGetTempPath; - const found_node = this_bundler.env.loadNodeJSConfig( - this_bundler.fs, + const found_node = this_transpiler.env.loadNodeJSConfig( + this_transpiler.fs, if (force_using_bun) bun_node_exe else "", ) catch false; @@ -934,9 +934,9 @@ pub const RunCommand = struct { if (needs_to_force_bun) { createFakeTemporaryNodeExecutable(&new_path, &optional_bun_self_path) catch bun.outOfMemory(); if (!force_using_bun) { - this_bundler.env.map.put("NODE", bun_node_exe) catch bun.outOfMemory(); - this_bundler.env.map.put("npm_node_execpath", bun_node_exe) catch bun.outOfMemory(); - this_bundler.env.map.put("npm_execpath", optional_bun_self_path) catch bun.outOfMemory(); + this_transpiler.env.map.put("NODE", bun_node_exe) catch bun.outOfMemory(); + this_transpiler.env.map.put("npm_node_execpath", bun_node_exe) catch bun.outOfMemory(); + this_transpiler.env.map.put("npm_execpath", optional_bun_self_path) catch bun.outOfMemory(); } needs_to_force_bun = false; @@ -969,7 +969,7 @@ pub const RunCommand = struct { pub fn configurePathForRun( ctx: Command.Context, root_dir_info: *DirInfo, - this_bundler: *bundler.Bundler, + this_transpiler: *transpiler.Transpiler, ORIGINAL_PATH: ?*string, cwd: string, force_using_bun: bool, @@ -984,8 +984,8 @@ pub const RunCommand = struct { } } - const new_path = try configurePathForRunWithPackageJsonDir(ctx, package_json_dir, this_bundler, ORIGINAL_PATH, cwd, force_using_bun); - this_bundler.env.map.put("PATH", new_path) catch bun.outOfMemory(); + const new_path = try configurePathForRunWithPackageJsonDir(ctx, package_json_dir, this_transpiler, ORIGINAL_PATH, cwd, force_using_bun); + this_transpiler.env.map.put("PATH", new_path) catch bun.outOfMemory(); } pub fn completions(ctx: Command.Context, default_completions: ?[]const string, reject_list: []const string, comptime filter: Filter) !ShellCompletions { @@ -998,35 +998,35 @@ pub const RunCommand = struct { const args = ctx.args; - var this_bundler = bundler.Bundler.init(ctx.allocator, ctx.log, args, null) catch return shell_out; - this_bundler.options.env.behavior = Api.DotEnvBehavior.load_all; - this_bundler.options.env.prefix = ""; - this_bundler.env.quiet = true; + var this_transpiler = transpiler.Transpiler.init(ctx.allocator, ctx.log, args, null) catch return shell_out; + this_transpiler.options.env.behavior = Api.DotEnvBehavior.load_all; + this_transpiler.options.env.prefix = ""; + this_transpiler.env.quiet = true; - this_bundler.resolver.care_about_bin_folder = true; - this_bundler.resolver.care_about_scripts = true; - this_bundler.resolver.store_fd = true; + this_transpiler.resolver.care_about_bin_folder = true; + this_transpiler.resolver.care_about_scripts = true; + this_transpiler.resolver.store_fd = true; defer { - this_bundler.resolver.care_about_bin_folder = false; - this_bundler.resolver.care_about_scripts = false; + this_transpiler.resolver.care_about_bin_folder = false; + this_transpiler.resolver.care_about_scripts = false; } - this_bundler.configureLinker(); + this_transpiler.configureLinker(); - const root_dir_info = (this_bundler.resolver.readDirInfo(this_bundler.fs.top_level_dir) catch null) orelse return shell_out; + const root_dir_info = (this_transpiler.resolver.readDirInfo(this_transpiler.fs.top_level_dir) catch null) orelse return shell_out; { - this_bundler.env.loadProcess(); + this_transpiler.env.loadProcess(); - if (this_bundler.env.get("NODE_ENV")) |node_env| { + if (this_transpiler.env.get("NODE_ENV")) |node_env| { if (strings.eqlComptime(node_env, "production")) { - this_bundler.options.production = true; + this_transpiler.options.production = true; } } } const ResultList = bun.StringArrayHashMap(void); - if (this_bundler.env.get("SHELL")) |shell| { + if (this_transpiler.env.get("SHELL")) |shell| { shell_out.shell = ShellCompletions.Shell.fromEnv(@TypeOf(shell), shell); } @@ -1043,15 +1043,15 @@ pub const RunCommand = struct { } if (filter == Filter.bin or filter == Filter.all or filter == Filter.all_plus_bun_js) { - for (this_bundler.resolver.binDirs()) |bin_path| { - if (this_bundler.resolver.readDirInfo(bin_path) catch null) |bin_dir| { + for (this_transpiler.resolver.binDirs()) |bin_path| { + if (this_transpiler.resolver.readDirInfo(bin_path) catch null) |bin_dir| { if (bin_dir.getEntriesConst()) |entries| { var iter = entries.data.iterator(); var has_copied = false; var dir_slice: string = ""; while (iter.next()) |entry| { const value = entry.value_ptr.*; - if (value.kind(&this_bundler.fs.fs, true) == .file) { + if (value.kind(&this_transpiler.fs.fs, true) == .file) { if (!has_copied) { bun.copy(u8, &path_buf, value.dir); dir_slice = path_buf[0..value.dir.len]; @@ -1070,7 +1070,7 @@ pub const RunCommand = struct { } if (!(bun.sys.isExecutableFilePath(slice))) continue; // we need to dupe because the string pay point to a pointer that only exists in the current scope - _ = try results.getOrPut(this_bundler.fs.filename_store.append(@TypeOf(base), base) catch continue); + _ = try results.getOrPut(this_transpiler.fs.filename_store.append(@TypeOf(base), base) catch continue); } } } @@ -1079,21 +1079,21 @@ pub const RunCommand = struct { } if (filter == Filter.all_plus_bun_js or filter == Filter.bun_js) { - if (this_bundler.resolver.readDirInfo(this_bundler.fs.top_level_dir) catch null) |dir_info| { + if (this_transpiler.resolver.readDirInfo(this_transpiler.fs.top_level_dir) catch null) |dir_info| { if (dir_info.getEntriesConst()) |entries| { var iter = entries.data.iterator(); while (iter.next()) |entry| { const value = entry.value_ptr.*; const name = value.base(); - if (name[0] != '.' and this_bundler.options.loader(std.fs.path.extension(name)).canBeRunByBun() and + if (name[0] != '.' and this_transpiler.options.loader(std.fs.path.extension(name)).canBeRunByBun() and !strings.contains(name, ".config") and !strings.contains(name, ".d.ts") and !strings.contains(name, ".d.mts") and !strings.contains(name, ".d.cts") and - value.kind(&this_bundler.fs.fs, true) == .file) + value.kind(&this_transpiler.fs.fs, true) == .file) { - _ = try results.getOrPut(this_bundler.fs.filename_store.append(@TypeOf(name), name) catch continue); + _ = try results.getOrPut(this_transpiler.fs.filename_store.append(@TypeOf(name), name) catch continue); } } } @@ -1109,7 +1109,7 @@ pub const RunCommand = struct { } var max_description_len: usize = 20; - if (this_bundler.env.get("MAX_DESCRIPTION_LEN")) |max| { + if (this_transpiler.env.get("MAX_DESCRIPTION_LEN")) |max| { if (std.fmt.parseInt(usize, max, 10) catch null) |max_len| { max_description_len = max_len; } @@ -1390,10 +1390,10 @@ pub const RunCommand = struct { Global.configureAllocator(.{ .long_running = false }); var ORIGINAL_PATH: string = ""; - var this_bundler: bundler.Bundler = undefined; - const root_dir_info = try configureEnvForRun(ctx, &this_bundler, null, log_errors, false); - try configurePathForRun(ctx, root_dir_info, &this_bundler, &ORIGINAL_PATH, root_dir_info.abs_path, force_using_bun); - this_bundler.env.map.put("npm_command", "run-script") catch unreachable; + var this_transpiler: transpiler.Transpiler = undefined; + const root_dir_info = try configureEnvForRun(ctx, &this_transpiler, null, log_errors, false); + try configurePathForRun(ctx, root_dir_info, &this_transpiler, &ORIGINAL_PATH, root_dir_info.abs_path, force_using_bun); + this_transpiler.env.map.put("npm_command", "run-script") catch unreachable; if (script_name_to_search.len == 0) { // naked "bun run" @@ -1422,8 +1422,8 @@ pub const RunCommand = struct { ctx.allocator, prescript, temp_script_buffer[1..], - this_bundler.fs.top_level_dir, - this_bundler.env, + this_transpiler.fs.top_level_dir, + this_transpiler.env, &.{}, ctx.debug.silent, ctx.debug.use_system_shell, @@ -1436,8 +1436,8 @@ pub const RunCommand = struct { ctx.allocator, script_content, script_name_to_search, - this_bundler.fs.top_level_dir, - this_bundler.env, + this_transpiler.fs.top_level_dir, + this_transpiler.env, passthrough, ctx.debug.silent, ctx.debug.use_system_shell, @@ -1452,8 +1452,8 @@ pub const RunCommand = struct { ctx.allocator, postscript, temp_script_buffer, - this_bundler.fs.top_level_dir, - this_bundler.env, + this_transpiler.fs.top_level_dir, + this_transpiler.env, &.{}, ctx.debug.silent, ctx.debug.use_system_shell, @@ -1536,10 +1536,10 @@ pub const RunCommand = struct { const l = root.len + cwd_len + prefix.len + script_name_to_search.len + ext.len; const path_to_use = BunXFastPath.direct_launch_buffer[0..l :0]; - BunXFastPath.tryLaunch(ctx, path_to_use, this_bundler.env, ctx.passthrough); + BunXFastPath.tryLaunch(ctx, path_to_use, this_transpiler.env, ctx.passthrough); } - const PATH = this_bundler.env.get("PATH") orelse ""; + const PATH = this_transpiler.env.get("PATH") orelse ""; var path_for_which = PATH; if (comptime bin_dirs_only) { if (ORIGINAL_PATH.len < PATH.len) { @@ -1550,14 +1550,14 @@ pub const RunCommand = struct { } if (path_for_which.len > 0) { - if (which(&path_buf, path_for_which, this_bundler.fs.top_level_dir, script_name_to_search)) |destination| { + if (which(&path_buf, path_for_which, this_transpiler.fs.top_level_dir, script_name_to_search)) |destination| { const out = bun.asByteSlice(destination); return try runBinaryWithoutBunxPath( ctx, - try this_bundler.fs.dirname_store.append(@TypeOf(out), out), + try this_transpiler.fs.dirname_store.append(@TypeOf(out), out), destination, - this_bundler.fs.top_level_dir, - this_bundler.env, + this_transpiler.fs.top_level_dir, + this_transpiler.env, passthrough, script_name_to_search, ); diff --git a/src/cli/test_command.zig b/src/cli/test_command.zig index a1229b5edc..050a83880c 100644 --- a/src/cli/test_command.zig +++ b/src/cli/test_command.zig @@ -764,7 +764,7 @@ pub const CommandLineReporter = struct { @compileError("No reporters enabled"); } - const relative_dir = vm.bundler.fs.top_level_dir; + const relative_dir = vm.transpiler.fs.top_level_dir; // --- Text --- const max_filepath_length: usize = if (reporters.text) brk: { @@ -1051,7 +1051,7 @@ const Scanner = struct { } const ext = std.fs.path.extension(slice); - const loader_by_ext = JSC.VirtualMachine.get().bundler.options.loader(ext); + const loader_by_ext = JSC.VirtualMachine.get().transpiler.options.loader(ext); // allow file loader just incase they use a custom loader with a non-standard extension if (!(loader_by_ext.isJavaScriptLike() or loader_by_ext == .file)) { @@ -1266,8 +1266,8 @@ pub const TestCommand = struct { ); vm.argv = ctx.passthrough; vm.preload = ctx.preloads; - vm.bundler.options.rewrite_jest_for_tests = true; - vm.bundler.options.env.behavior = .load_all_without_inlining; + vm.transpiler.options.rewrite_jest_for_tests = true; + vm.transpiler.options.env.behavior = .load_all_without_inlining; const node_env_entry = try env_loader.map.getOrPutWithoutValue("NODE_ENV"); if (!node_env_entry.found_existing) { @@ -1278,18 +1278,18 @@ pub const TestCommand = struct { }; } - try vm.bundler.configureDefines(); + try vm.transpiler.configureDefines(); vm.loadExtraEnvAndSourceCodePrinter(); vm.is_main_thread = true; JSC.VirtualMachine.is_main_thread_vm = true; if (ctx.test_options.coverage.enabled) { - vm.bundler.options.code_coverage = true; - vm.bundler.options.minify_syntax = false; - vm.bundler.options.minify_identifiers = false; - vm.bundler.options.minify_whitespace = false; - vm.bundler.options.dead_code_elimination = false; + vm.transpiler.options.code_coverage = true; + vm.transpiler.options.minify_syntax = false; + vm.transpiler.options.minify_identifiers = false; + vm.transpiler.options.minify_whitespace = false; + vm.transpiler.options.dead_code_elimination = false; vm.global.vm().setControlFlowProfiler(true); } @@ -1299,7 +1299,7 @@ pub const TestCommand = struct { // We use the string "Etc/UTC" instead of "UTC" so there is no normalization difference. "Etc/UTC"; - if (vm.bundler.env.get("TZ")) |tz| { + if (vm.transpiler.env.get("TZ")) |tz| { TZ_NAME = tz; } @@ -1352,8 +1352,8 @@ pub const TestCommand = struct { var scanner = Scanner{ .dirs_to_scan = Scanner.Fifo.init(ctx.allocator), - .options = &vm.bundler.options, - .fs = vm.bundler.fs, + .options = &vm.transpiler.options, + .fs = vm.transpiler.fs, .filter_names = filter_names_normalized, .results = &results, }; @@ -1380,7 +1380,7 @@ pub const TestCommand = struct { else => {}, } - // vm.bundler.fs.fs.readDirectory(_dir: string, _handle: ?std.fs.Dir) + // vm.transpiler.fs.fs.readDirectory(_dir: string, _handle: ?std.fs.Dir) runAllTests(reporter, vm, test_files, ctx.allocator); } @@ -1659,7 +1659,7 @@ pub const TestCommand = struct { defer reporter.jest.only = prev_only; const file_start = reporter.jest.files.len; - const resolution = try vm.bundler.resolveEntryPoint(file_name); + const resolution = try vm.transpiler.resolveEntryPoint(file_name); vm.clearEntryPoint(); const file_path = resolution.path_pair.primary.text; diff --git a/src/cli/upgrade_command.zig b/src/cli/upgrade_command.zig index d55776ad24..f86c6dd0fa 100644 --- a/src/cli/upgrade_command.zig +++ b/src/cli/upgrade_command.zig @@ -25,7 +25,6 @@ const Api = @import("../api/schema.zig").Api; const resolve_path = @import("../resolver/resolve_path.zig"); const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun; const Command = @import("../cli.zig").Command; -const bundler = bun.bundler; const fs = @import("../fs.zig"); const URL = @import("../url.zig").URL; diff --git a/src/css/targets.zig b/src/css/targets.zig index 29b63d02ed..c5fe76f214 100644 --- a/src/css/targets.zig +++ b/src/css/targets.zig @@ -31,7 +31,7 @@ pub const Targets = struct { }; } - pub fn forBundlerTarget(target: bun.bundler.options.Target) Targets { + pub fn forBundlerTarget(target: bun.transpiler.options.Target) Targets { return switch (target) { .node, .bun => runtimeDefault(), .browser, .bun_macro, .bake_server_components_ssr => browserDefault(), diff --git a/src/ini.zig b/src/ini.zig index 017670fbd3..77fe57fe03 100644 --- a/src/ini.zig +++ b/src/ini.zig @@ -528,7 +528,7 @@ pub const IniTestingAPIs = struct { defer arena.deinit(); const envjs = callframe.argument(1); - const env = if (envjs.isEmptyOrUndefinedOrNull()) globalThis.bunVM().bundler.env else brk: { + const env = if (envjs.isEmptyOrUndefinedOrNull()) globalThis.bunVM().transpiler.env else brk: { var envmap = bun.DotEnv.Map.HashTable.init(allocator); var object_iter = JSC.JSPropertyIterator(.{ .skip_empty_name = false, @@ -611,7 +611,7 @@ pub const IniTestingAPIs = struct { const utf8str = bunstr.toUTF8(bun.default_allocator); defer utf8str.deinit(); - var parser = Parser.init(bun.default_allocator, "", utf8str.slice(), globalThis.bunVM().bundler.env); + var parser = Parser.init(bun.default_allocator, "", utf8str.slice(), globalThis.bunVM().transpiler.env); defer parser.deinit(); try parser.parse(parser.arena.allocator()); diff --git a/src/install/install.zig b/src/install/install.zig index 521594194f..5ba0da5b3a 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -37,7 +37,7 @@ const Path = bun.path; const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun; const Command = @import("../cli.zig").Command; const BunArguments = @import("../cli.zig").Arguments; -const bundler = bun.bundler; +const transpiler = bun.transpiler; const DotEnv = @import("../env_loader.zig"); const which = @import("../which.zig").which; @@ -2942,7 +2942,7 @@ pub const PackageManager = struct { pub const ScriptRunEnvironment = struct { root_dir_info: *DirInfo, - bundler: bundler.Bundler, + transpiler: bun.Transpiler, }; const TimePasser = struct { @@ -3009,9 +3009,9 @@ pub const PackageManager = struct { return false; } - pub fn configureEnvForScripts(this: *PackageManager, ctx: Command.Context, log_level: Options.LogLevel) !*bundler.Bundler { + pub fn configureEnvForScripts(this: *PackageManager, ctx: Command.Context, log_level: Options.LogLevel) !*transpiler.Transpiler { if (this.env_configure) |*env_configure| { - return &env_configure.bundler; + return &env_configure.transpiler; } // We need to figure out the PATH and other environment variables @@ -3020,13 +3020,13 @@ pub const PackageManager = struct { // so we really only want to do it when strictly necessary this.env_configure = .{ .root_dir_info = undefined, - .bundler = undefined, + .transpiler = undefined, }; - const this_bundler: *bundler.Bundler = &this.env_configure.?.bundler; + const this_transpiler: *transpiler.Transpiler = &this.env_configure.?.transpiler; const root_dir_info = try RunCommand.configureEnvForRun( ctx, - this_bundler, + this_transpiler, this.env, log_level != .silent, false, @@ -3041,12 +3041,12 @@ pub const PackageManager = struct { }; } - this.env.loadCCachePath(this_bundler.fs); + this.env.loadCCachePath(this_transpiler.fs); { var node_path: bun.PathBuffer = undefined; - if (this.env.getNodePath(this_bundler.fs, &node_path)) |node_pathZ| { - _ = try this.env.loadNodeJSConfig(this_bundler.fs, bun.default_allocator.dupe(u8, node_pathZ) catch bun.outOfMemory()); + if (this.env.getNodePath(this_transpiler.fs, &node_path)) |node_pathZ| { + _ = try this.env.loadNodeJSConfig(this_transpiler.fs, bun.default_allocator.dupe(u8, node_pathZ) catch bun.outOfMemory()); } else brk: { const current_path = this.env.get("PATH") orelse ""; var PATH = try std.ArrayList(u8).initCapacity(bun.default_allocator, current_path.len); @@ -3054,13 +3054,13 @@ pub const PackageManager = struct { var bun_path: string = ""; RunCommand.createFakeTemporaryNodeExecutable(&PATH, &bun_path) catch break :brk; try this.env.map.put("PATH", PATH.items); - _ = try this.env.loadNodeJSConfig(this_bundler.fs, bun.default_allocator.dupe(u8, bun_path) catch bun.outOfMemory()); + _ = try this.env.loadNodeJSConfig(this_transpiler.fs, bun.default_allocator.dupe(u8, bun_path) catch bun.outOfMemory()); } } this.env_configure.?.root_dir_info = root_dir_info; - return this_bundler; + return this_transpiler; } pub fn httpProxy(this: *PackageManager, url: URL) ?URL { @@ -15170,11 +15170,11 @@ pub const PackageManager = struct { try this.ensureTempNodeGypScript(); const cwd = list.cwd; - const this_bundler = try this.configureEnvForScripts(ctx, log_level); - const original_path = this_bundler.env.get("PATH") orelse ""; + const this_transpiler = try this.configureEnvForScripts(ctx, log_level); + const original_path = this_transpiler.env.get("PATH") orelse ""; var PATH = try std.ArrayList(u8).initCapacity(bun.default_allocator, original_path.len + 1 + "node_modules/.bin".len + cwd.len + 1); - var current_dir: ?*DirInfo = this_bundler.resolver.readDirInfo(cwd) catch null; + var current_dir: ?*DirInfo = this_transpiler.resolver.readDirInfo(cwd) catch null; bun.assert(current_dir != null); while (current_dir) |dir| { if (PATH.items.len > 0 and PATH.items[PATH.items.len - 1] != std.fs.path.delimiter) { @@ -15196,10 +15196,10 @@ pub const PackageManager = struct { try PATH.appendSlice(original_path); } - this_bundler.env.map.put("PATH", PATH.items) catch unreachable; + this_transpiler.env.map.put("PATH", PATH.items) catch unreachable; - const envp = try this_bundler.env.map.createNullDelimitedEnvMap(this.allocator); - try this_bundler.env.map.put("PATH", original_path); + const envp = try this_transpiler.env.map.createNullDelimitedEnvMap(this.allocator); + try this_transpiler.env.map.put("PATH", original_path); PATH.deinit(); try LifecycleScriptSubprocess.spawnPackageScripts(this, list, envp, optional, log_level, foreground); @@ -15250,12 +15250,12 @@ pub const bun_install_js_bindings = struct { var lockfile: Lockfile = undefined; lockfile.initEmpty(allocator); - if (globalObject.bunVM().bundler.resolver.env_loader == null) { - globalObject.bunVM().bundler.resolver.env_loader = globalObject.bunVM().bundler.env; + if (globalObject.bunVM().transpiler.resolver.env_loader == null) { + globalObject.bunVM().transpiler.resolver.env_loader = globalObject.bunVM().transpiler.env; } // as long as we aren't migration from `package-lock.json`, leaving this undefined is okay - const manager = globalObject.bunVM().bundler.resolver.getPackageManager(); + const manager = globalObject.bunVM().transpiler.resolver.getPackageManager(); const load_result: Lockfile.LoadResult = lockfile.loadFromDir(bun.toFD(dir), manager, allocator, &log, true); diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 9f64fe8207..57c8ddd676 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -33,7 +33,6 @@ const Path = @import("../resolver/resolve_path.zig"); const configureTransformOptionsForBun = @import("../bun.js/config.zig").configureTransformOptionsForBun; const Command = @import("../cli.zig").Command; const BunArguments = @import("../cli.zig").Arguments; -const bundler = bun.bundler; const DotEnv = @import("../env_loader.zig"); const which = @import("../which.zig").which; diff --git a/src/js_ast.zig b/src/js_ast.zig index ce24d226f5..cb62b226f1 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -7902,8 +7902,8 @@ pub const Macro = struct { const DotEnv = @import("./env_loader.zig"); const js = @import("./bun.js/javascript_core_c_api.zig"); const Zig = @import("./bun.js/bindings/exports.zig"); - const Bundler = bun.Bundler; - const MacroEntryPoint = bun.bundler.MacroEntryPoint; + const Transpiler = bun.Transpiler; + const MacroEntryPoint = bun.transpiler.MacroEntryPoint; const MacroRemap = @import("./resolver/package_json.zig").MacroMap; pub const MacroRemapEntry = @import("./resolver/package_json.zig").MacroImportReplacementMap; @@ -7928,12 +7928,12 @@ pub const Macro = struct { return this.remap.get(path); } - pub fn init(bundler: *Bundler) MacroContext { + pub fn init(transpiler: *Transpiler) MacroContext { return MacroContext{ .macros = MacroMap.init(default_allocator), - .resolver = &bundler.resolver, - .env = bundler.env, - .remap = bundler.options.macro_remap, + .resolver = &transpiler.resolver, + .env = transpiler.env, + .remap = transpiler.options.macro_remap, }; } @@ -8096,7 +8096,7 @@ pub const Macro = struct { _vm.enableMacroMode(); _vm.eventLoop().ensureWaker(); - try _vm.bundler.configureDefines(); + try _vm.transpiler.configureDefines(); break :brk _vm; }; diff --git a/src/json_parser.zig b/src/json_parser.zig index c3fbf960e3..47267b62ee 100644 --- a/src/json_parser.zig +++ b/src/json_parser.zig @@ -1015,8 +1015,8 @@ const js_printer = bun.js_printer; const renamer = @import("renamer.zig"); const SymbolList = [][]Symbol; -const Bundler = bun.Bundler; -const ParseResult = bun.bundler.ParseResult; +const Transpiler = bun.Transpiler; +const ParseResult = bun.transpiler.ParseResult; fn expectPrintedJSON(_contents: string, expected: string) !void { Expr.Data.Store.create(default_allocator); Stmt.Data.Store.create(default_allocator); diff --git a/src/linker.zig b/src/linker.zig index f0136706d5..dcaecf25e8 100644 --- a/src/linker.zig +++ b/src/linker.zig @@ -32,15 +32,15 @@ const ImportKind = _import_record.ImportKind; const allocators = @import("./allocators.zig"); const MimeType = @import("./http/mime_type.zig"); const resolve_path = @import("./resolver/resolve_path.zig"); -const _bundler = bun.bundler; -const Bundler = _bundler.Bundler; -const ResolveQueue = _bundler.ResolveQueue; +const _transpiler = bun.transpiler; +const Transpiler = _transpiler.Transpiler; +const ResolveQueue = _transpiler.ResolveQueue; const ResolverType = Resolver.Resolver; const ESModule = @import("./resolver/package_json.zig").ESModule; const Runtime = @import("./runtime.zig").Runtime; const URL = @import("url.zig").URL; const JSC = bun.JSC; -const PluginRunner = bun.bundler.PluginRunner; +const PluginRunner = bun.transpiler.PluginRunner; pub const CSSResolveError = error{ResolveMessage}; pub const OnImportCallback = *const fn (resolve_result: *const Resolver.Result, import_record: *ImportRecord, origin: URL) void; @@ -54,7 +54,7 @@ pub const Linker = struct { log: *logger.Log, resolve_queue: *ResolveQueue, resolver: *ResolverType, - resolve_results: *_bundler.ResolveResults, + resolve_results: *_transpiler.ResolveResults, any_needs_runtime: bool = false, runtime_import_record: ?ImportRecord = null, hashed_filenames: HashedFileNameMap, @@ -80,7 +80,7 @@ pub const Linker = struct { resolve_queue: *ResolveQueue, options: *Options.BundleOptions, resolver: *ResolverType, - resolve_results: *_bundler.ResolveResults, + resolve_results: *_transpiler.ResolveResults, fs: *Fs.FileSystem, ) ThisLinker { relative_paths_list = ImportPathsList.init(allocator); @@ -116,7 +116,7 @@ pub const Linker = struct { file_path: Fs.Path, fd: ?FileDescriptorType, ) !string { - if (Bundler.isCacheEnabled) { + if (Transpiler.isCacheEnabled) { const hashed = bun.hash(file_path.text); const hashed_result = try this.hashed_filenames.getOrPut(hashed); if (hashed_result.found_existing) { @@ -127,7 +127,7 @@ pub const Linker = struct { const modkey = try this.getModKey(file_path, fd); const hash_name = modkey.hashName(file_path.text); - if (Bundler.isCacheEnabled) { + if (Transpiler.isCacheEnabled) { const hashed = bun.hash(file_path.text); try this.hashed_filenames.put(hashed, try this.allocator.dupe(u8, hash_name)); } @@ -183,7 +183,7 @@ pub const Linker = struct { pub fn link( linker: *ThisLinker, file_path: Fs.Path, - result: *_bundler.ParseResult, + result: *_transpiler.ParseResult, origin: URL, comptime import_path_format: Options.BundleOptions.ImportPathFormat, comptime ignore_runtime: bool, @@ -603,7 +603,7 @@ pub const Linker = struct { fn whenModuleNotFound( linker: *ThisLinker, import_record: *ImportRecord, - result: *_bundler.ParseResult, + result: *_transpiler.ParseResult, comptime is_bun: bool, ) !bool { if (import_record.handles_import_errors) { diff --git a/src/resolver/resolve_path.zig b/src/resolver/resolve_path.zig index eaed43a969..f073394c1f 100644 --- a/src/resolver/resolve_path.zig +++ b/src/resolver/resolve_path.zig @@ -2048,7 +2048,7 @@ export fn ResolvePath__joinAbsStringBufCurrentPlatformBunString( defer str.deinit(); const out_slice = joinAbsStringBuf( - globalObject.bunVM().bundler.fs.top_level_dir, + globalObject.bunVM().transpiler.fs.top_level_dir, &join_buf, &.{str.slice()}, comptime Platform.auto.resolve(), diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index bf87b29dad..557bd39e31 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -3307,7 +3307,7 @@ pub const Resolver = struct { const in_str = argument.toBunString(globalThis); defer in_str.deref(); - const r = &globalThis.bunVM().bundler.resolver; + const r = &globalThis.bunVM().transpiler.resolver; return nodeModulePathsJSValue(r, in_str, globalThis); } @@ -3315,7 +3315,7 @@ pub const Resolver = struct { bun.JSC.markBinding(@src()); const in_str = bun.String.createUTF8("."); - const r = &globalThis.bunVM().bundler.resolver; + const r = &globalThis.bunVM().transpiler.resolver; return nodeModulePathsJSValue(r, in_str, globalThis); } diff --git a/src/shell/interpreter.zig b/src/shell/interpreter.zig index 7fb55877d0..76b94c04d0 100644 --- a/src/shell/interpreter.zig +++ b/src/shell/interpreter.zig @@ -1303,7 +1303,7 @@ pub const Interpreter = struct { var env_loader: *bun.DotEnv.Loader = env_loader: { if (event_loop == .js) { - break :env_loader event_loop.js.virtual_machine.bundler.env; + break :env_loader event_loop.js.virtual_machine.transpiler.env; } break :env_loader event_loop.env(); diff --git a/src/shell/shell.zig b/src/shell/shell.zig index a475cdd763..cd63bf4201 100644 --- a/src/shell/shell.zig +++ b/src/shell/shell.zig @@ -227,7 +227,7 @@ pub const GlobalJS = struct { } pub inline fn createNullDelimitedEnvMap(this: @This(), alloc: Allocator) ![:null]?[*:0]u8 { - return this.globalThis.bunVM().bundler.env.map.createNullDelimitedEnvMap(alloc); + return this.globalThis.bunVM().transpiler.env.map.createNullDelimitedEnvMap(alloc); } pub inline fn getAllocator(this: @This()) Allocator { @@ -239,11 +239,11 @@ pub const GlobalJS = struct { } pub inline fn topLevelDir(this: @This()) []const u8 { - return this.globalThis.bunVM().bundler.fs.top_level_dir; + return this.globalThis.bunVM().transpiler.fs.top_level_dir; } pub inline fn env(this: @This()) *bun.DotEnv.Loader { - return this.globalThis.bunVM().bundler.env; + return this.globalThis.bunVM().transpiler.env; } pub inline fn platformEventLoop(this: @This()) *JSC.PlatformEventLoop { diff --git a/src/shell/subproc.zig b/src/shell/subproc.zig index 1eed3bdf53..672abdcf22 100644 --- a/src/shell/subproc.zig +++ b/src/shell/subproc.zig @@ -704,7 +704,7 @@ pub const ShellSubprocess = struct { } pub fn fillEnvFromProcess(this: *SpawnArgs, globalThis: *JSGlobalObject) void { - var env_iter = EnvMapIter.init(globalThis.bunVM().bundler.env.map, this.arena.allocator()); + var env_iter = EnvMapIter.init(globalThis.bunVM().transpiler.env.map, this.arena.allocator()); return this.fillEnv(globalThis, &env_iter, false); } @@ -782,7 +782,7 @@ pub const ShellSubprocess = struct { const is_sync = config.is_sync; if (!spawn_args.override_env and spawn_args.env_array.items.len == 0) { - // spawn_args.env_array.items = jsc_vm.bundler.env.map.createNullDelimitedEnvMap(allocator) catch bun.outOfMemory(); + // spawn_args.env_array.items = jsc_vm.transpiler.env.map.createNullDelimitedEnvMap(allocator) catch bun.outOfMemory(); spawn_args.env_array.items = event_loop.createNullDelimitedEnvMap(allocator) catch bun.outOfMemory(); spawn_args.env_array.capacity = spawn_args.env_array.items.len; } diff --git a/src/bundler.zig b/src/transpiler.zig similarity index 79% rename from src/bundler.zig rename to src/transpiler.zig index ed9c903a87..fb2e8bacf5 100644 --- a/src/bundler.zig +++ b/src/transpiler.zig @@ -340,13 +340,13 @@ pub const PluginRunner = struct { } }; -/// This structure was the JavaScript bundler before bundle_v2 was written. It now +/// This structure was the JavaScript transpiler before bundle_v2 was written. It now /// acts mostly as a configuration object, but it also contains stateful logic around /// logging errors (.log) and module resolution (.resolve_queue) /// /// This object is not exclusive to bundle_v2/Bun.build, one of these is stored /// on every VM so that the options can be used for transpilation. -pub const Bundler = struct { +pub const Transpiler = struct { options: options.BundleOptions, log: *logger.Log, allocator: std.mem.Allocator, @@ -369,7 +369,7 @@ pub const Bundler = struct { pub const isCacheEnabled = cache_files; - pub fn clone(this: *Bundler, allocator: std.mem.Allocator, to: *Bundler) !void { + pub fn clone(this: *Transpiler, allocator: std.mem.Allocator, to: *Transpiler) !void { to.* = this.*; to.setAllocator(allocator); to.log = try allocator.create(logger.Log); @@ -379,33 +379,33 @@ pub const Bundler = struct { to.linker.resolver = &to.resolver; } - pub inline fn getPackageManager(this: *Bundler) *PackageManager { + pub inline fn getPackageManager(this: *Transpiler) *PackageManager { return this.resolver.getPackageManager(); } - pub fn setLog(this: *Bundler, log: *logger.Log) void { + pub fn setLog(this: *Transpiler, log: *logger.Log) void { this.log = log; this.linker.log = log; this.resolver.log = log; } - pub fn setAllocator(this: *Bundler, allocator: std.mem.Allocator) void { + pub fn setAllocator(this: *Transpiler, allocator: std.mem.Allocator) void { this.allocator = allocator; this.linker.allocator = allocator; this.resolver.allocator = allocator; } - fn _resolveEntryPoint(bundler: *Bundler, entry_point: string) !_resolver.Result { - return bundler.resolver.resolveWithFramework(bundler.fs.top_level_dir, entry_point, .entry_point) catch |err| { + fn _resolveEntryPoint(transpiler: *Transpiler, entry_point: string) !_resolver.Result { + return transpiler.resolver.resolveWithFramework(transpiler.fs.top_level_dir, entry_point, .entry_point) catch |err| { // Relative entry points that were not resolved to a node_modules package are // interpreted as relative to the current working directory. if (!std.fs.path.isAbsolute(entry_point) and !(strings.hasPrefix(entry_point, "./") or strings.hasPrefix(entry_point, ".\\"))) { brk: { - return bundler.resolver.resolve( - bundler.fs.top_level_dir, - try strings.append(bundler.allocator, "./", entry_point), + return transpiler.resolver.resolve( + transpiler.fs.top_level_dir, + try strings.append(transpiler.allocator, "./", entry_point), .entry_point, ) catch { // return the original error @@ -417,8 +417,8 @@ pub const Bundler = struct { }; } - pub fn resolveEntryPoint(bundler: *Bundler, entry_point: string) !_resolver.Result { - return _resolveEntryPoint(bundler, entry_point) catch |err| { + pub fn resolveEntryPoint(transpiler: *Transpiler, entry_point: string) !_resolver.Result { + return _resolveEntryPoint(transpiler, entry_point) catch |err| { var cache_bust_buf: bun.PathBuffer = undefined; // Bust directory cache and try again @@ -436,7 +436,7 @@ pub const Bundler = struct { }; break :name bun.path.joinAbsStringBufZ( - bundler.fs.top_level_dir, + transpiler.fs.top_level_dir, &cache_bust_buf, &parts, .auto, @@ -444,15 +444,15 @@ pub const Bundler = struct { }; // Only re-query if we previously had something cached. - if (bundler.resolver.bustDirCache(bun.strings.withoutTrailingSlashWindowsPath(buster_name))) { - if (_resolveEntryPoint(bundler, entry_point)) |result| + if (transpiler.resolver.bustDirCache(bun.strings.withoutTrailingSlashWindowsPath(buster_name))) { + if (_resolveEntryPoint(transpiler, entry_point)) |result| return result else |_| { // ignore this error, we will print the original error } } - bundler.log.addErrorFmt(null, logger.Loc.Empty, bundler.allocator, "{s} resolving \"{s}\" (entry point)", .{ @errorName(err), entry_point }) catch bun.outOfMemory(); + transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} resolving \"{s}\" (entry point)", .{ @errorName(err), entry_point }) catch bun.outOfMemory(); return err; }; } @@ -462,7 +462,7 @@ pub const Bundler = struct { log: *logger.Log, opts: Api.TransformOptions, env_loader_: ?*DotEnv.Loader, - ) !Bundler { + ) !Transpiler { js_ast.Expr.Data.Store.create(); js_ast.Stmt.Data.Store.create(); @@ -496,7 +496,7 @@ pub const Bundler = struct { // }); const resolve_results = try allocator.create(ResolveResults); resolve_results.* = ResolveResults.init(allocator); - return Bundler{ + return Transpiler{ .options = bundle_options, .fs = fs, .allocator = allocator, @@ -513,36 +513,36 @@ pub const Bundler = struct { }; } - pub fn configureLinkerWithAutoJSX(bundler: *Bundler, auto_jsx: bool) void { - bundler.linker = Linker.init( - bundler.allocator, - bundler.log, - &bundler.resolve_queue, - &bundler.options, - &bundler.resolver, - bundler.resolve_results, - bundler.fs, + pub fn configureLinkerWithAutoJSX(transpiler: *Transpiler, auto_jsx: bool) void { + transpiler.linker = Linker.init( + transpiler.allocator, + transpiler.log, + &transpiler.resolve_queue, + &transpiler.options, + &transpiler.resolver, + transpiler.resolve_results, + transpiler.fs, ); if (auto_jsx) { // Most of the time, this will already be cached - if (bundler.resolver.readDirInfo(bundler.fs.top_level_dir) catch null) |root_dir| { + if (transpiler.resolver.readDirInfo(transpiler.fs.top_level_dir) catch null) |root_dir| { if (root_dir.tsconfig_json) |tsconfig| { // If we don't explicitly pass JSX, try to get it from the root tsconfig - if (bundler.options.transform_options.jsx == null) { - bundler.options.jsx = tsconfig.jsx; + if (transpiler.options.transform_options.jsx == null) { + transpiler.options.jsx = tsconfig.jsx; } - bundler.options.emit_decorator_metadata = tsconfig.emit_decorator_metadata; + transpiler.options.emit_decorator_metadata = tsconfig.emit_decorator_metadata; } } } } - pub fn configureLinker(bundler: *Bundler) void { - bundler.configureLinkerWithAutoJSX(true); + pub fn configureLinker(transpiler: *Transpiler) void { + transpiler.configureLinkerWithAutoJSX(true); } - pub fn runEnvLoader(this: *Bundler, skip_default_env: bool) !void { + pub fn runEnvLoader(this: *Transpiler, skip_default_env: bool) !void { switch (this.options.env.behavior) { .prefix, .load_all, .load_all_without_inlining => { // Step 1. Load the project root. @@ -585,7 +585,7 @@ pub const Bundler = struct { } // This must be run after a framework is configured, if a framework is enabled - pub fn configureDefines(this: *Bundler) !void { + pub fn configureDefines(this: *Transpiler) !void { if (this.options.defines_loaded) { return; } @@ -614,18 +614,18 @@ pub const Bundler = struct { } } - pub fn resetStore(_: *const Bundler) void { + pub fn resetStore(_: *const Transpiler) void { js_ast.Expr.Data.Store.reset(); js_ast.Stmt.Data.Store.reset(); } - pub noinline fn dumpEnvironmentVariables(bundler: *const Bundler) void { + pub noinline fn dumpEnvironmentVariables(transpiler: *const Transpiler) void { @setCold(true); const opts = std.json.StringifyOptions{ .whitespace = .indent_2, }; Output.flush(); - std.json.stringify(bundler.env.map.*, opts, Output.writer()) catch unreachable; + std.json.stringify(transpiler.env.map.*, opts, Output.writer()) catch unreachable; Output.flush(); } @@ -636,7 +636,7 @@ pub const Bundler = struct { }; pub fn buildWithResolveResult( - bundler: *Bundler, + transpiler: *Transpiler, resolve_result: _resolver.Result, allocator: std.mem.Allocator, loader: options.Loader, @@ -659,7 +659,7 @@ pub const Bundler = struct { }; } - errdefer bundler.resetStore(); + errdefer transpiler.resetStore(); var file_path = (resolve_result.pathConst() orelse { return BuildResolveResultPair{ @@ -668,68 +668,68 @@ pub const Bundler = struct { }; }).*; - if (strings.indexOf(file_path.text, bundler.fs.top_level_dir)) |i| { - file_path.pretty = file_path.text[i + bundler.fs.top_level_dir.len ..]; + if (strings.indexOf(file_path.text, transpiler.fs.top_level_dir)) |i| { + file_path.pretty = file_path.text[i + transpiler.fs.top_level_dir.len ..]; } else if (!file_path.is_symlink) { - file_path.pretty = allocator.dupe(u8, bundler.fs.relativeTo(file_path.text)) catch unreachable; + file_path.pretty = allocator.dupe(u8, transpiler.fs.relativeTo(file_path.text)) catch unreachable; } - const old_bundler_allocator = bundler.allocator; - bundler.allocator = allocator; - defer bundler.allocator = old_bundler_allocator; - const old_linker_allocator = bundler.linker.allocator; - defer bundler.linker.allocator = old_linker_allocator; - bundler.linker.allocator = allocator; + const old_bundler_allocator = transpiler.allocator; + transpiler.allocator = allocator; + defer transpiler.allocator = old_bundler_allocator; + const old_linker_allocator = transpiler.linker.allocator; + defer transpiler.linker.allocator = old_linker_allocator; + transpiler.linker.allocator = allocator; switch (loader) { .css => { const CSSBundlerHMR = Css.NewBundler( Writer, - @TypeOf(&bundler.linker), - @TypeOf(&bundler.resolver.caches.fs), + @TypeOf(&transpiler.linker), + @TypeOf(&transpiler.resolver.caches.fs), WatcherType, - @TypeOf(bundler.fs), + @TypeOf(transpiler.fs), true, import_path_format, ); const CSSBundler = Css.NewBundler( Writer, - @TypeOf(&bundler.linker), - @TypeOf(&bundler.resolver.caches.fs), + @TypeOf(&transpiler.linker), + @TypeOf(&transpiler.resolver.caches.fs), WatcherType, - @TypeOf(bundler.fs), + @TypeOf(transpiler.fs), false, import_path_format, ); const written = brk: { - if (bundler.options.hot_module_reloading) { + if (transpiler.options.hot_module_reloading) { break :brk (try CSSBundlerHMR.bundle( file_path.text, - bundler.fs, + transpiler.fs, writer, watcher, - &bundler.resolver.caches.fs, + &transpiler.resolver.caches.fs, filepath_hash, file_descriptor, allocator, - bundler.log, - &bundler.linker, + transpiler.log, + &transpiler.linker, origin, )).written; } else { break :brk (try CSSBundler.bundle( file_path.text, - bundler.fs, + transpiler.fs, writer, watcher, - &bundler.resolver.caches.fs, + &transpiler.resolver.caches.fs, filepath_hash, file_descriptor, allocator, - bundler.log, - &bundler.linker, + transpiler.log, + &transpiler.linker, origin, )).written; } @@ -741,7 +741,7 @@ pub const Bundler = struct { }; }, else => { - var result = bundler.parse( + var result = transpiler.parse( ParseOptions{ .allocator = allocator, .path = file_path, @@ -749,13 +749,13 @@ pub const Bundler = struct { .dirname_fd = resolve_result.dirname_fd, .file_descriptor = file_descriptor, .file_hash = filepath_hash, - .macro_remappings = bundler.options.macro_remap, + .macro_remappings = transpiler.options.macro_remap, .emit_decorator_metadata = resolve_result.emit_decorator_metadata, .jsx = resolve_result.jsx, }, client_entry_point, ) orelse { - bundler.resetStore(); + transpiler.resetStore(); return BuildResolveResultPair{ .written = 0, .input_fd = null, @@ -766,14 +766,14 @@ pub const Bundler = struct { return BuildResolveResultPair{ .written = 0, .input_fd = result.input_fd, .empty = true }; } - if (bundler.options.target.isBun()) { - if (!bundler.options.transform_only) { - try bundler.linker.link(file_path, &result, origin, import_path_format, false, true); + if (transpiler.options.target.isBun()) { + if (!transpiler.options.transform_only) { + try transpiler.linker.link(file_path, &result, origin, import_path_format, false, true); } return BuildResolveResultPair{ .written = switch (result.ast.exports_kind) { - .esm => try bundler.printWithSourceMapMaybe( + .esm => try transpiler.printWithSourceMapMaybe( result.ast, &result.source, Writer, @@ -783,7 +783,7 @@ pub const Bundler = struct { source_map_handler, null, ), - .cjs => try bundler.printWithSourceMapMaybe( + .cjs => try transpiler.printWithSourceMapMaybe( result.ast, &result.source, Writer, @@ -799,13 +799,13 @@ pub const Bundler = struct { }; } - if (!bundler.options.transform_only) { - try bundler.linker.link(file_path, &result, origin, import_path_format, false, false); + if (!transpiler.options.transform_only) { + try transpiler.linker.link(file_path, &result, origin, import_path_format, false, false); } return BuildResolveResultPair{ .written = switch (result.ast.exports_kind) { - .none, .esm => try bundler.printWithSourceMapMaybe( + .none, .esm => try transpiler.printWithSourceMapMaybe( result.ast, &result.source, Writer, @@ -815,7 +815,7 @@ pub const Bundler = struct { source_map_handler, null, ), - .cjs => try bundler.printWithSourceMapMaybe( + .cjs => try transpiler.printWithSourceMapMaybe( result.ast, &result.source, Writer, @@ -834,7 +834,7 @@ pub const Bundler = struct { } pub fn buildWithResolveResultEager( - bundler: *Bundler, + transpiler: *Transpiler, resolve_result: _resolver.Result, comptime import_path_format: options.BundleOptions.ImportPathFormat, comptime Outstream: type, @@ -848,13 +848,13 @@ pub const Bundler = struct { var file_path = (resolve_result.pathConst() orelse return null).*; // Step 1. Parse & scan - const loader = bundler.options.loader(file_path.name.ext); + const loader = transpiler.options.loader(file_path.name.ext); if (client_entry_point_) |client_entry_point| { file_path = client_entry_point.source.path; } - file_path.pretty = Linker.relative_paths_list.append(string, bundler.fs.relativeTo(file_path.text)) catch unreachable; + file_path.pretty = Linker.relative_paths_list.append(string, transpiler.fs.relativeTo(file_path.text)) catch unreachable; var output_file = options.OutputFile{ .src_path = file_path, @@ -867,15 +867,15 @@ pub const Bundler = struct { switch (loader) { .jsx, .tsx, .js, .ts, .json, .toml, .text => { - var result = bundler.parse( + var result = transpiler.parse( ParseOptions{ - .allocator = bundler.allocator, + .allocator = transpiler.allocator, .path = file_path, .loader = loader, .dirname_fd = resolve_result.dirname_fd, .file_descriptor = null, .file_hash = null, - .macro_remappings = bundler.options.macro_remap, + .macro_remappings = transpiler.options.macro_remap, .jsx = resolve_result.jsx, .emit_decorator_metadata = resolve_result.emit_decorator_metadata, }, @@ -883,38 +883,38 @@ pub const Bundler = struct { ) orelse { return null; }; - if (!bundler.options.transform_only) { - if (!bundler.options.target.isBun()) - try bundler.linker.link( + if (!transpiler.options.transform_only) { + if (!transpiler.options.target.isBun()) + try transpiler.linker.link( file_path, &result, - bundler.options.origin, + transpiler.options.origin, import_path_format, false, false, ) else - try bundler.linker.link( + try transpiler.linker.link( file_path, &result, - bundler.options.origin, + transpiler.options.origin, import_path_format, false, true, ); } - const buffer_writer = try js_printer.BufferWriter.init(bundler.allocator); + const buffer_writer = try js_printer.BufferWriter.init(transpiler.allocator); var writer = js_printer.BufferPrinter.init(buffer_writer); - output_file.size = switch (bundler.options.target) { - .browser, .node => try bundler.print( + output_file.size = switch (transpiler.options.target) { + .browser, .node => try transpiler.print( result, *js_printer.BufferPrinter, &writer, .esm, ), - .bun, .bun_macro, .bake_server_components_ssr => try bundler.print( + .bun, .bun_macro, .bake_server_components_ssr => try transpiler.print( result, *js_printer.BufferPrinter, &writer, @@ -923,7 +923,7 @@ pub const Bundler = struct { }; output_file.value = .{ .buffer = .{ - .allocator = bundler.allocator, + .allocator = transpiler.allocator, .bytes = writer.ctx.written, }, }; @@ -932,34 +932,34 @@ pub const Bundler = struct { Output.panic("TODO: dataurl, base64", .{}); // TODO }, .css => { - if (bundler.options.experimental_css) { - const alloc = bundler.allocator; + if (transpiler.options.experimental_css) { + const alloc = transpiler.allocator; - const entry = bundler.resolver.caches.fs.readFileWithAllocator( - bundler.allocator, - bundler.fs, + const entry = transpiler.resolver.caches.fs.readFileWithAllocator( + transpiler.allocator, + transpiler.fs, file_path.text, resolve_result.dirname_fd, false, null, ) catch |err| { - bundler.log.addErrorFmt(null, logger.Loc.Empty, bundler.allocator, "{s} reading \"{s}\"", .{ @errorName(err), file_path.pretty }) catch {}; + transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} reading \"{s}\"", .{ @errorName(err), file_path.pretty }) catch {}; return null; }; - var sheet = switch (bun.css.StyleSheet(bun.css.DefaultAtRule).parse(alloc, entry.contents, bun.css.ParserOptions.default(alloc, bundler.log), null)) { + var sheet = switch (bun.css.StyleSheet(bun.css.DefaultAtRule).parse(alloc, entry.contents, bun.css.ParserOptions.default(alloc, transpiler.log), null)) { .result => |v| v, .err => |e| { - bundler.log.addErrorFmt(null, logger.Loc.Empty, bundler.allocator, "{} parsing", .{e}) catch unreachable; + transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{} parsing", .{e}) catch unreachable; return null; }, }; if (sheet.minify(alloc, bun.css.MinifyOptions.default()).asErr()) |e| { - bundler.log.addErrorFmt(null, logger.Loc.Empty, bundler.allocator, "{} while minifying", .{e.kind}) catch bun.outOfMemory(); + transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{} while minifying", .{e.kind}) catch bun.outOfMemory(); return null; } const result = sheet.toCss(alloc, bun.css.PrinterOptions{ - .targets = bun.css.Targets.forBundlerTarget(bundler.options.target), - .minify = bundler.options.minify_whitespace, + .targets = bun.css.Targets.forBundlerTarget(transpiler.options.target), + .minify = transpiler.options.minify_whitespace, }, null) catch |e| { bun.handleErrorReturnTrace(e, @errorReturnTrace()); return null; @@ -982,12 +982,12 @@ pub const Bundler = struct { const CSSBuildContext = struct { origin: URL, }; - const build_ctx = CSSBuildContext{ .origin = bundler.options.origin }; + const build_ctx = CSSBuildContext{ .origin = transpiler.options.origin }; const BufferedWriter = std.io.CountingWriter(std.io.BufferedWriter(8192, bun.sys.File.Writer)); const CSSWriter = Css.NewWriter( BufferedWriter.Writer, - @TypeOf(&bundler.linker), + @TypeOf(&transpiler.linker), import_path_format, CSSBuildContext, ); @@ -995,8 +995,8 @@ pub const Bundler = struct { .child_stream = .{ .unbuffered_writer = file.writer() }, .bytes_written = 0, }; - const entry = bundler.resolver.caches.fs.readFile( - bundler.fs, + const entry = transpiler.resolver.caches.fs.readFile( + transpiler.fs, file_path.text, resolve_result.dirname_fd, !cache_files, @@ -1004,19 +1004,19 @@ pub const Bundler = struct { ) catch return null; const _file = Fs.PathContentsPair{ .path = file_path, .contents = entry.contents }; - var source = try logger.Source.initFile(_file, bundler.allocator); + var source = try logger.Source.initFile(_file, transpiler.allocator); source.contents_is_recycled = !cache_files; var css_writer = CSSWriter.init( &source, buffered_writer.writer(), - &bundler.linker, - bundler.log, + &transpiler.linker, + transpiler.log, ); css_writer.buildCtx = build_ctx; - try css_writer.run(bundler.log, bundler.allocator); + try css_writer.run(transpiler.log, transpiler.allocator); try css_writer.ctx.context.child_stream.flush(); output_file.size = css_writer.ctx.context.bytes_written; var file_op = options.OutputFile.FileOperation.fromFile(file.handle, file_path.pretty); @@ -1028,7 +1028,7 @@ pub const Bundler = struct { if (Outstream == std.fs.Dir) { file_op.dir = bun.toFD(outstream.fd); - if (bundler.fs.fs.needToCloseFiles()) { + if (transpiler.fs.fs.needToCloseFiles()) { file.close(); file_op.fd = .zero; } @@ -1039,11 +1039,11 @@ pub const Bundler = struct { }, .bunsh, .sqlite_embedded, .sqlite, .wasm, .file, .napi => { - const hashed_name = try bundler.linker.getHashedFilename(file_path, null); - var pathname = try bundler.allocator.alloc(u8, hashed_name.len + file_path.name.ext.len); + const hashed_name = try transpiler.linker.getHashedFilename(file_path, null); + var pathname = try transpiler.allocator.alloc(u8, hashed_name.len + file_path.name.ext.len); bun.copy(u8, pathname, hashed_name); bun.copy(u8, pathname[hashed_name.len..], file_path.name.ext); - const dir = if (bundler.options.output_dir_handle) |output_handle| bun.toFD(output_handle.fd) else .zero; + const dir = if (transpiler.options.output_dir_handle) |output_handle| bun.toFD(output_handle.fd) else .zero; output_file.value = .{ .copy = options.OutputFile.FileOperation{ @@ -1059,7 +1059,7 @@ pub const Bundler = struct { } pub fn printWithSourceMapMaybe( - bundler: *Bundler, + transpiler: *Transpiler, ast: js_ast.Ast, source: *const logger.Source, comptime Writer: type, @@ -1085,14 +1085,14 @@ pub const Bundler = struct { .{ .runtime_imports = ast.runtime_imports, .require_ref = ast.require_ref, - .css_import_behavior = bundler.options.cssImportBehavior(), + .css_import_behavior = transpiler.options.cssImportBehavior(), .source_map_handler = source_map_context, - .minify_whitespace = bundler.options.minify_whitespace, - .minify_syntax = bundler.options.minify_syntax, - .minify_identifiers = bundler.options.minify_identifiers, - .transform_only = bundler.options.transform_only, + .minify_whitespace = transpiler.options.minify_whitespace, + .minify_syntax = transpiler.options.minify_syntax, + .minify_identifiers = transpiler.options.minify_identifiers, + .transform_only = transpiler.options.transform_only, .runtime_transpiler_cache = runtime_transpiler_cache, - .print_dce_annotations = bundler.options.emit_dce_annotations, + .print_dce_annotations = transpiler.options.emit_dce_annotations, }, enable_source_map, ), @@ -1108,18 +1108,18 @@ pub const Bundler = struct { .runtime_imports = ast.runtime_imports, .require_ref = ast.require_ref, .source_map_handler = source_map_context, - .css_import_behavior = bundler.options.cssImportBehavior(), - .minify_whitespace = bundler.options.minify_whitespace, - .minify_syntax = bundler.options.minify_syntax, - .minify_identifiers = bundler.options.minify_identifiers, - .transform_only = bundler.options.transform_only, + .css_import_behavior = transpiler.options.cssImportBehavior(), + .minify_whitespace = transpiler.options.minify_whitespace, + .minify_syntax = transpiler.options.minify_syntax, + .minify_identifiers = transpiler.options.minify_identifiers, + .transform_only = transpiler.options.transform_only, .import_meta_ref = ast.import_meta_ref, .runtime_transpiler_cache = runtime_transpiler_cache, - .print_dce_annotations = bundler.options.emit_dce_annotations, + .print_dce_annotations = transpiler.options.emit_dce_annotations, }, enable_source_map, ), - .esm_ascii => switch (bundler.options.target.isBun()) { + .esm_ascii => switch (transpiler.options.target.isBun()) { inline else => |is_bun| try js_printer.printAst( Writer, writer, @@ -1130,16 +1130,16 @@ pub const Bundler = struct { .{ .runtime_imports = ast.runtime_imports, .require_ref = ast.require_ref, - .css_import_behavior = bundler.options.cssImportBehavior(), + .css_import_behavior = transpiler.options.cssImportBehavior(), .source_map_handler = source_map_context, - .minify_whitespace = bundler.options.minify_whitespace, - .minify_syntax = bundler.options.minify_syntax, - .minify_identifiers = bundler.options.minify_identifiers, - .transform_only = bundler.options.transform_only, - .module_type = if (is_bun and bundler.options.transform_only) + .minify_whitespace = transpiler.options.minify_whitespace, + .minify_syntax = transpiler.options.minify_syntax, + .minify_identifiers = transpiler.options.minify_identifiers, + .transform_only = transpiler.options.transform_only, + .module_type = if (is_bun and transpiler.options.transform_only) // this is for when using `bun build --no-bundle` // it should copy what was passed for the cli - bundler.options.output_format + transpiler.options.output_format else if (ast.exports_kind == .cjs) .cjs else @@ -1147,8 +1147,8 @@ pub const Bundler = struct { .inline_require_and_import_errors = false, .import_meta_ref = ast.import_meta_ref, .runtime_transpiler_cache = runtime_transpiler_cache, - .target = bundler.options.target, - .print_dce_annotations = bundler.options.emit_dce_annotations, + .target = transpiler.options.target, + .print_dce_annotations = transpiler.options.emit_dce_annotations, }, enable_source_map, ), @@ -1158,13 +1158,13 @@ pub const Bundler = struct { } pub fn print( - bundler: *Bundler, + transpiler: *Transpiler, result: ParseResult, comptime Writer: type, writer: Writer, comptime format: js_printer.Format, ) !usize { - return bundler.printWithSourceMapMaybe( + return transpiler.printWithSourceMapMaybe( result.ast, &result.source, Writer, @@ -1177,7 +1177,7 @@ pub const Bundler = struct { } pub fn printWithSourceMap( - bundler: *Bundler, + transpiler: *Transpiler, result: ParseResult, comptime Writer: type, writer: Writer, @@ -1185,7 +1185,7 @@ pub const Bundler = struct { handler: js_printer.SourceMapHandler, ) !usize { if (bun.getRuntimeFeatureFlag("BUN_FEATURE_FLAG_DISABLE_SOURCE_MAPS")) { - return bundler.printWithSourceMapMaybe( + return transpiler.printWithSourceMapMaybe( result.ast, &result.source, Writer, @@ -1196,7 +1196,7 @@ pub const Bundler = struct { result.runtime_transpiler_cache, ); } - return bundler.printWithSourceMapMaybe( + return transpiler.printWithSourceMapMaybe( result.ast, &result.source, Writer, @@ -1239,21 +1239,21 @@ pub const Bundler = struct { }; pub fn parse( - bundler: *Bundler, + transpiler: *Transpiler, this_parse: ParseOptions, client_entry_point_: anytype, ) ?ParseResult { - return parseMaybeReturnFileOnly(bundler, this_parse, client_entry_point_, false); + return parseMaybeReturnFileOnly(transpiler, this_parse, client_entry_point_, false); } pub fn parseMaybeReturnFileOnly( - bundler: *Bundler, + transpiler: *Transpiler, this_parse: ParseOptions, client_entry_point_: anytype, comptime return_file_only: bool, ) ?ParseResult { return parseMaybeReturnFileOnlyAllowSharedBuffer( - bundler, + transpiler, this_parse, client_entry_point_, return_file_only, @@ -1262,7 +1262,7 @@ pub const Bundler = struct { } pub fn parseMaybeReturnFileOnlyAllowSharedBuffer( - bundler: *Bundler, + transpiler: *Transpiler, this_parse: ParseOptions, client_entry_point_: anytype, comptime return_file_only: bool, @@ -1298,32 +1298,32 @@ pub const Bundler = struct { if (strings.startsWith(path.text, "data:")) { const data_url = DataURL.parseWithoutCheck(path.text) catch |err| { - bundler.log.addErrorFmt(null, logger.Loc.Empty, bundler.allocator, "{s} parsing data url \"{s}\"", .{ @errorName(err), path.text }) catch {}; + transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} parsing data url \"{s}\"", .{ @errorName(err), path.text }) catch {}; return null; }; const body = data_url.decodeData(this_parse.allocator) catch |err| { - bundler.log.addErrorFmt(null, logger.Loc.Empty, bundler.allocator, "{s} decoding data \"{s}\"", .{ @errorName(err), path.text }) catch {}; + transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} decoding data \"{s}\"", .{ @errorName(err), path.text }) catch {}; return null; }; break :brk logger.Source.initPathString(path.text, body); } - const entry = bundler.resolver.caches.fs.readFileWithAllocator( + const entry = transpiler.resolver.caches.fs.readFileWithAllocator( if (use_shared_buffer) bun.fs_allocator else this_parse.allocator, - bundler.fs, + transpiler.fs, path.text, dirname_fd, use_shared_buffer, file_descriptor, ) catch |err| { - bundler.log.addErrorFmt(null, logger.Loc.Empty, bundler.allocator, "{s} reading \"{s}\"", .{ @errorName(err), path.text }) catch {}; + transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} reading \"{s}\"", .{ @errorName(err), path.text }) catch {}; return null; }; input_fd = entry.fd; if (this_parse.file_fd_ptr) |file_fd_ptr| { file_fd_ptr.* = entry.fd; } - break :brk logger.Source.initRecycledFile(.{ .path = path, .contents = entry.contents }, bundler.allocator) catch return null; + break :brk logger.Source.initRecycledFile(.{ .path = path, .contents = entry.contents }, transpiler.allocator) catch return null; }; if (comptime return_file_only) { @@ -1351,7 +1351,7 @@ pub const Bundler = struct { }; } - const target = bundler.options.target; + const target = transpiler.options.target; var jsx = this_parse.jsx; jsx.parse = loader.isJSX(); @@ -1359,43 +1359,43 @@ pub const Bundler = struct { var opts = js_parser.Parser.Options.init(jsx, loader); opts.features.emit_decorator_metadata = this_parse.emit_decorator_metadata; - opts.features.allow_runtime = bundler.options.allow_runtime; + opts.features.allow_runtime = transpiler.options.allow_runtime; opts.features.set_breakpoint_on_first_line = this_parse.set_breakpoint_on_first_line; - opts.features.trim_unused_imports = bundler.options.trim_unused_imports orelse loader.isTypeScript(); + opts.features.trim_unused_imports = transpiler.options.trim_unused_imports orelse loader.isTypeScript(); opts.features.use_import_meta_require = target.isBun(); - opts.features.no_macros = bundler.options.no_macros; + opts.features.no_macros = transpiler.options.no_macros; opts.features.runtime_transpiler_cache = this_parse.runtime_transpiler_cache; - opts.transform_only = bundler.options.transform_only; + opts.transform_only = transpiler.options.transform_only; - opts.ignore_dce_annotations = bundler.options.ignore_dce_annotations; + opts.ignore_dce_annotations = transpiler.options.ignore_dce_annotations; // @bun annotation opts.features.dont_bundle_twice = this_parse.dont_bundle_twice; opts.features.commonjs_at_runtime = this_parse.allow_commonjs; - opts.tree_shaking = bundler.options.tree_shaking; - opts.features.inlining = bundler.options.inlining; + opts.tree_shaking = transpiler.options.tree_shaking; + opts.features.inlining = transpiler.options.inlining; opts.filepath_hash_for_hmr = file_hash orelse 0; - opts.features.auto_import_jsx = bundler.options.auto_import_jsx; + opts.features.auto_import_jsx = transpiler.options.auto_import_jsx; opts.warn_about_unbundled_modules = !target.isBun(); opts.features.inject_jest_globals = this_parse.inject_jest_globals; - opts.features.minify_syntax = bundler.options.minify_syntax; - opts.features.minify_identifiers = bundler.options.minify_identifiers; - opts.features.dead_code_elimination = bundler.options.dead_code_elimination; + opts.features.minify_syntax = transpiler.options.minify_syntax; + opts.features.minify_identifiers = transpiler.options.minify_identifiers; + opts.features.dead_code_elimination = transpiler.options.dead_code_elimination; opts.features.remove_cjs_module_wrapper = this_parse.remove_cjs_module_wrapper; - if (bundler.macro_context == null) { - bundler.macro_context = js_ast.Macro.MacroContext.init(bundler); + if (transpiler.macro_context == null) { + transpiler.macro_context = js_ast.Macro.MacroContext.init(transpiler); } // we'll just always enable top-level await // this is incorrect for Node.js files which are CommonJS modules opts.features.top_level_await = true; - opts.macro_context = &bundler.macro_context.?; + opts.macro_context = &transpiler.macro_context.?; if (comptime !JSC.is_bindgen) { if (target != .bun_macro) { opts.macro_context.javascript_object = this_parse.macro_js_ctx; @@ -1405,11 +1405,11 @@ pub const Bundler = struct { opts.features.is_macro_runtime = target == .bun_macro; opts.features.replace_exports = this_parse.replace_exports; - return switch ((bundler.resolver.caches.js.parse( + return switch ((transpiler.resolver.caches.js.parse( allocator, opts, - bundler.options.define, - bundler.log, + transpiler.options.define, + transpiler.log, &source, ) catch null) orelse return null) { .ast => |value| ParseResult{ @@ -1458,11 +1458,11 @@ pub const Bundler = struct { // We allow importing tsconfig.*.json or jsconfig.*.json with comments // These files implicitly become JSONC files, which aligns with the behavior of text editors. if (source.path.isJSONCFile()) - JSON.parseTSConfig(&source, bundler.log, allocator, false) catch return null + JSON.parseTSConfig(&source, transpiler.log, allocator, false) catch return null else - JSON.parse(&source, bundler.log, allocator, false) catch return null + JSON.parse(&source, transpiler.log, allocator, false) catch return null else if (kind == .toml) - TOML.parse(&source, bundler.log, allocator, false) catch return null + TOML.parse(&source, transpiler.log, allocator, false) catch return null else @compileError("unreachable"); @@ -1612,12 +1612,12 @@ pub const Bundler = struct { }; }, .wasm => { - if (bundler.options.target.isBun()) { + if (transpiler.options.target.isBun()) { if (!source.isWebAssembly()) { - bundler.log.addErrorFmt( + transpiler.log.addErrorFmt( null, logger.Loc.Empty, - bundler.allocator, + transpiler.allocator, "Invalid wasm file \"{s}\" (missing magic header)", .{path.text}, ) catch {}; @@ -1644,18 +1644,16 @@ pub const Bundler = struct { threadlocal var tmp_buildfile_buf2: bun.PathBuffer = undefined; threadlocal var tmp_buildfile_buf3: bun.PathBuffer = undefined; - // We try to be mostly stateless when serving - // This means we need a slightly different resolver setup pub fn buildFile( - bundler: *Bundler, + transpiler: *Transpiler, log: *logger.Log, path_to_use_: string, comptime client_entry_point_enabled: bool, ) !ServeResult { - const old_log = bundler.log; + const old_log = transpiler.log; - bundler.setLog(log); - defer bundler.setLog(old_log); + transpiler.setLog(log); + defer transpiler.setLog(old_log); var path_to_use = path_to_use_; @@ -1664,11 +1662,6 @@ pub const Bundler = struct { js_ast.Stmt.Data.Store.reset(); } - // If the extension is .js, omit it. - // if (absolute_path.len > ".js".len and strings.eqlComptime(absolute_path[absolute_path.len - ".js".len ..], ".js")) { - // absolute_path = absolute_path[0 .. absolute_path.len - ".js".len]; - // } - // All non-absolute paths are ./paths if (path_to_use[0] != '/' and path_to_use[0] != '.') { tmp_buildfile_buf3[0..2].* = "./".*; @@ -1676,10 +1669,10 @@ pub const Bundler = struct { path_to_use = tmp_buildfile_buf3[0 .. 2 + path_to_use.len]; } - const resolved = if (comptime !client_entry_point_enabled) (try bundler.resolver.resolve(bundler.fs.top_level_dir, path_to_use, .stmt)) else brk: { + const resolved = if (comptime !client_entry_point_enabled) (try transpiler.resolver.resolve(transpiler.fs.top_level_dir, path_to_use, .stmt)) else brk: { const absolute_pathname = Fs.PathName.init(path_to_use); - const loader_for_ext = bundler.options.loader(absolute_pathname.ext); + const loader_for_ext = transpiler.options.loader(absolute_pathname.ext); // The expected pathname looks like: // /pages/index.entry.tsx @@ -1702,17 +1695,17 @@ pub const Bundler = struct { if (comptime Environment.allow_assert) bun.assert(len > 0); const decoded_entry_point_path = tmp_buildfile_buf2[0..len]; - break :brk try bundler.resolver.resolve(bundler.fs.top_level_dir, decoded_entry_point_path, .entry_point); + break :brk try transpiler.resolver.resolve(transpiler.fs.top_level_dir, decoded_entry_point_path, .entry_point); } } - break :brk (try bundler.resolver.resolve(bundler.fs.top_level_dir, path_to_use, .stmt)); + break :brk (try transpiler.resolver.resolve(transpiler.fs.top_level_dir, path_to_use, .stmt)); }; const path = (resolved.pathConst() orelse return error.ModuleNotFound); - const loader = bundler.options.loader(path.name.ext); - const mime_type_ext = bundler.options.out_extensions.get(path.name.ext) orelse path.name.ext; + const loader = transpiler.options.loader(path.name.ext); + const mime_type_ext = transpiler.options.out_extensions.get(path.name.ext) orelse path.name.ext; switch (loader) { .js, .jsx, .ts, .tsx, .css => { @@ -1745,14 +1738,14 @@ pub const Bundler = struct { } } - pub fn normalizeEntryPointPath(bundler: *Bundler, _entry: string) string { + pub fn normalizeEntryPointPath(transpiler: *Transpiler, _entry: string) string { var paths = [_]string{_entry}; - var entry = bundler.fs.abs(&paths); + var entry = transpiler.fs.abs(&paths); std.fs.accessAbsolute(entry, .{}) catch return _entry; - entry = bundler.fs.relativeTo(entry); + entry = transpiler.fs.relativeTo(entry); if (!strings.startsWith(entry, "./")) { // Entry point paths without a leading "./" are interpreted as package @@ -1767,7 +1760,7 @@ pub const Bundler = struct { // a leading "./" because the path may not be a file system path. For // example, it may be a URL. So only insert a leading "./" when the path // is an exact match for an existing file. - var __entry = bundler.allocator.alloc(u8, "./".len + entry.len) catch unreachable; + var __entry = transpiler.allocator.alloc(u8, "./".len + entry.len) catch unreachable; __entry[0] = '.'; __entry[1] = '/'; bun.copy(u8, __entry[2..__entry.len], entry); @@ -1777,18 +1770,18 @@ pub const Bundler = struct { return entry; } - fn enqueueEntryPoints(bundler: *Bundler, entry_points: []_resolver.Result, comptime normalize_entry_point: bool) usize { + fn enqueueEntryPoints(transpiler: *Transpiler, entry_points: []_resolver.Result, comptime normalize_entry_point: bool) usize { var entry_point_i: usize = 0; - for (bundler.options.entry_points) |_entry| { - const entry: string = if (comptime normalize_entry_point) bundler.normalizeEntryPointPath(_entry) else _entry; + for (transpiler.options.entry_points) |_entry| { + const entry: string = if (comptime normalize_entry_point) transpiler.normalizeEntryPointPath(_entry) else _entry; defer { js_ast.Expr.Data.Store.reset(); js_ast.Stmt.Data.Store.reset(); } - const result = bundler.resolver.resolve(bundler.fs.top_level_dir, entry, .entry_point) catch |err| { + const result = transpiler.resolver.resolve(transpiler.fs.top_level_dir, entry, .entry_point) catch |err| { Output.prettyError("Error resolving \"{s}\": {s}\n", .{ entry, @errorName(err) }); continue; }; @@ -1800,7 +1793,7 @@ pub const Bundler = struct { continue; } - if (bundler.linker.enqueueResolveResult(&result) catch unreachable) { + if (transpiler.linker.enqueueResolveResult(&result) catch unreachable) { entry_points[entry_point_i] = result; entry_point_i += 1; } @@ -1810,44 +1803,44 @@ pub const Bundler = struct { } pub fn transform( - bundler: *Bundler, + transpiler: *Transpiler, allocator: std.mem.Allocator, log: *logger.Log, opts: Api.TransformOptions, ) !options.TransformResult { _ = opts; - var entry_points = try allocator.alloc(_resolver.Result, bundler.options.entry_points.len); - entry_points = entry_points[0..bundler.enqueueEntryPoints(entry_points, true)]; + var entry_points = try allocator.alloc(_resolver.Result, transpiler.options.entry_points.len); + entry_points = entry_points[0..transpiler.enqueueEntryPoints(entry_points, true)]; if (log.level.atLeast(.debug)) { - bundler.resolver.debug_logs = try DebugLogs.init(allocator); + transpiler.resolver.debug_logs = try DebugLogs.init(allocator); } - bundler.options.transform_only = true; + transpiler.options.transform_only = true; const did_start = false; - if (bundler.options.output_dir_handle == null) { + if (transpiler.options.output_dir_handle == null) { const outstream = bun.sys.File.from(std.io.getStdOut()); if (!did_start) { - try switch (bundler.options.import_path_format) { - .relative => bundler.processResolveQueue(.relative, false, @TypeOf(outstream), outstream), - .absolute_url => bundler.processResolveQueue(.absolute_url, false, @TypeOf(outstream), outstream), - .absolute_path => bundler.processResolveQueue(.absolute_path, false, @TypeOf(outstream), outstream), - .package_path => bundler.processResolveQueue(.package_path, false, @TypeOf(outstream), outstream), + try switch (transpiler.options.import_path_format) { + .relative => transpiler.processResolveQueue(.relative, false, @TypeOf(outstream), outstream), + .absolute_url => transpiler.processResolveQueue(.absolute_url, false, @TypeOf(outstream), outstream), + .absolute_path => transpiler.processResolveQueue(.absolute_path, false, @TypeOf(outstream), outstream), + .package_path => transpiler.processResolveQueue(.package_path, false, @TypeOf(outstream), outstream), }; } } else { - const output_dir = bundler.options.output_dir_handle orelse { + const output_dir = transpiler.options.output_dir_handle orelse { Output.printError("Invalid or missing output directory.", .{}); Global.crash(); }; if (!did_start) { - try switch (bundler.options.import_path_format) { - .relative => bundler.processResolveQueue(.relative, false, std.fs.Dir, output_dir), - .absolute_url => bundler.processResolveQueue(.absolute_url, false, std.fs.Dir, output_dir), - .absolute_path => bundler.processResolveQueue(.absolute_path, false, std.fs.Dir, output_dir), - .package_path => bundler.processResolveQueue(.package_path, false, std.fs.Dir, output_dir), + try switch (transpiler.options.import_path_format) { + .relative => transpiler.processResolveQueue(.relative, false, std.fs.Dir, output_dir), + .absolute_url => transpiler.processResolveQueue(.absolute_url, false, std.fs.Dir, output_dir), + .absolute_path => transpiler.processResolveQueue(.absolute_path, false, std.fs.Dir, output_dir), + .package_path => transpiler.processResolveQueue(.package_path, false, std.fs.Dir, output_dir), }; } } @@ -1858,8 +1851,8 @@ pub const Bundler = struct { // } // } - if (bundler.linker.any_needs_runtime) { - // try bundler.output_files.append( + if (transpiler.linker.any_needs_runtime) { + // try transpiler.output_files.append( // options.OutputFile.initBuf( // runtime.Runtime.source_code, // bun.default_allocator, @@ -1871,32 +1864,32 @@ pub const Bundler = struct { // ); } - if (FeatureFlags.tracing and bundler.options.log.level.atLeast(.info)) { + if (FeatureFlags.tracing and transpiler.options.log.level.atLeast(.info)) { Output.prettyErrorln( "\n---Tracing---\nResolve time: {d}\nParsing time: {d}\n---Tracing--\n\n", .{ - bundler.resolver.elapsed, - bundler.elapsed, + transpiler.resolver.elapsed, + transpiler.elapsed, }, ); } - var final_result = try options.TransformResult.init(try allocator.dupe(u8, bundler.result.outbase), try bundler.output_files.toOwnedSlice(), log, allocator); - final_result.root_dir = bundler.options.output_dir_handle; + var final_result = try options.TransformResult.init(try allocator.dupe(u8, transpiler.result.outbase), try transpiler.output_files.toOwnedSlice(), log, allocator); + final_result.root_dir = transpiler.options.output_dir_handle; return final_result; } - // pub fn processResolveQueueWithThreadPool(bundler) + // pub fn processResolveQueueWithThreadPool(transpiler) pub fn processResolveQueue( - bundler: *Bundler, + transpiler: *Transpiler, comptime import_path_format: options.BundleOptions.ImportPathFormat, comptime wrap_entry_point: bool, comptime Outstream: type, outstream: Outstream, ) !void { // var count: u8 = 0; - while (bundler.resolve_queue.readItem()) |item| { + while (transpiler.resolve_queue.readItem()) |item| { js_ast.Expr.Data.Store.reset(); js_ast.Stmt.Data.Store.reset(); @@ -1904,21 +1897,21 @@ pub const Bundler = struct { if (comptime wrap_entry_point) { const path = item.pathConst() orelse unreachable; - const loader = bundler.options.loader(path.name.ext); + const loader = transpiler.options.loader(path.name.ext); if (item.import_kind == .entry_point and loader.supportsClientEntryPoint()) { - var client_entry_point = try bundler.allocator.create(EntryPoints.ClientEntryPoint); + var client_entry_point = try transpiler.allocator.create(EntryPoints.ClientEntryPoint); client_entry_point.* = EntryPoints.ClientEntryPoint{}; - try client_entry_point.generate(Bundler, bundler, path.name, bundler.options.framework.?.client.path); + try client_entry_point.generate(Transpiler, transpiler, path.name, transpiler.options.framework.?.client.path); - const entry_point_output_file = bundler.buildWithResolveResultEager( + const entry_point_output_file = transpiler.buildWithResolveResultEager( item, import_path_format, Outstream, outstream, client_entry_point, ) catch continue orelse continue; - bundler.output_files.append(entry_point_output_file) catch unreachable; + transpiler.output_files.append(entry_point_output_file) catch unreachable; js_ast.Expr.Data.Store.reset(); js_ast.Stmt.Data.Store.reset(); @@ -1927,29 +1920,29 @@ pub const Bundler = struct { // So we just immediately build it. var item_not_entrypointed = item; item_not_entrypointed.import_kind = .stmt; - const original_output_file = bundler.buildWithResolveResultEager( + const original_output_file = transpiler.buildWithResolveResultEager( item_not_entrypointed, import_path_format, Outstream, outstream, null, ) catch continue orelse continue; - bundler.output_files.append(original_output_file) catch unreachable; + transpiler.output_files.append(original_output_file) catch unreachable; continue; } } - const output_file = bundler.buildWithResolveResultEager( + const output_file = transpiler.buildWithResolveResultEager( item, import_path_format, Outstream, outstream, null, ) catch continue orelse continue; - bundler.output_files.append(output_file) catch unreachable; + transpiler.output_files.append(output_file) catch unreachable; - // if (count >= 3) return try bundler.processResolveQueueWithThreadPool(import_path_format, wrap_entry_point, Outstream, outstream); + // if (count >= 3) return try transpiler.processResolveQueueWithThreadPool(import_path_format, wrap_entry_point, Outstream, outstream); } } }; diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index 28ad2eb78c..68af41ca9e 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -663,7 +663,7 @@ function expectBundled( } } - // Run bun build cli. In the future we can move to using `Bun.Bundler` + // Run bun build cli. In the future we can move to using `Bun.Transpiler.` let warningReference: Record = {}; const expectedErrors = bundleErrors ? Object.entries(bundleErrors).flatMap(([file, v]) => v.map(error => ({ file, error }))) From 14b44aeb49122db206feabca82b3aee8563e368b Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Sat, 21 Dec 2024 00:45:39 -0800 Subject: [PATCH 082/125] fix(process): `process.kill` allows zero or negative pids (#15920) --- src/bun.js/bindings/BunProcess.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 452c89b97e..fdc1bf72c7 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -2948,9 +2948,6 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionKill, auto pid_value = callFrame->argument(0); int pid = pid_value.toInt32(globalObject); RETURN_IF_EXCEPTION(scope, {}); - if (pid < 0) { - return Bun::ERR::OUT_OF_RANGE(scope, globalObject, "pid"_s, "a positive integer"_s, pid_value); - } JSC::JSValue signalValue = callFrame->argument(1); int signal = SIGTERM; if (signalValue.isNumber()) { From b63a6c83b49f182bca6142acf78e209a7489128b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 21 Dec 2024 21:28:17 -0800 Subject: [PATCH 083/125] deps: update libdeflate to v1.23 (#15934) Co-authored-by: Jarred-Sumner --- cmake/targets/BuildLibDeflate.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/targets/BuildLibDeflate.cmake b/cmake/targets/BuildLibDeflate.cmake index f629d52fe5..f2820e3e79 100644 --- a/cmake/targets/BuildLibDeflate.cmake +++ b/cmake/targets/BuildLibDeflate.cmake @@ -4,7 +4,7 @@ register_repository( REPOSITORY ebiggers/libdeflate COMMIT - 9d624d1d8ba82c690d6d6be1d0a961fc5a983ea4 + 733848901289eca058804ca0737f8796875204c8 ) register_cmake_command( From a6ad3b9be45ed6dfaef3cdb0678770c57ce51e39 Mon Sep 17 00:00:00 2001 From: Martin Amps Date: Sun, 22 Dec 2024 15:14:46 +0700 Subject: [PATCH 084/125] add --elide-lines override flag for workspace filtering (#15837) --- src/bunfig.zig | 8 +++ src/cli.zig | 22 +++++- src/cli/filter_run.zig | 14 +++- test/cli/run/filter-workspace.test.ts | 96 ++++++++++++++++++++++++++- 4 files changed, 134 insertions(+), 6 deletions(-) diff --git a/src/bunfig.zig b/src/bunfig.zig index ac2ff21f20..8ca56ec0ee 100644 --- a/src/bunfig.zig +++ b/src/bunfig.zig @@ -597,6 +597,14 @@ pub const Bunfig = struct { } } + if (run_expr.get("elide-lines")) |elide_lines| { + if (elide_lines.data == .e_number) { + this.ctx.bundler_options.elide_lines = @intFromFloat(elide_lines.data.e_number.value); + } else { + try this.addError(elide_lines.loc, "Expected number"); + } + } + if (run_expr.get("shell")) |shell| { if (shell.asString(allocator)) |value| { if (strings.eqlComptime(value, "bun")) { diff --git a/src/cli.zig b/src/cli.zig index d49b37200c..95c5a10a04 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -243,6 +243,7 @@ pub const Arguments = struct { const auto_only_params = [_]ParamType{ // clap.parseParam("--all") catch unreachable, clap.parseParam("--silent Don't print the script command") catch unreachable, + clap.parseParam("--elide-lines Number of lines of script output shown when using --filter (default: 10). Set to 0 to show all lines.") catch unreachable, clap.parseParam("-v, --version Print version and exit") catch unreachable, clap.parseParam("--revision Print version with revision and exit") catch unreachable, } ++ auto_or_run_params; @@ -250,6 +251,7 @@ pub const Arguments = struct { const run_only_params = [_]ParamType{ clap.parseParam("--silent Don't print the script command") catch unreachable, + clap.parseParam("--elide-lines Number of lines of script output shown when using --filter (default: 10). Set to 0 to show all lines.") catch unreachable, } ++ auto_or_run_params; pub const run_params = run_only_params ++ runtime_params_ ++ transpiler_params_ ++ base_params_; @@ -501,6 +503,15 @@ pub const Arguments = struct { if (cmd == .RunCommand or cmd == .AutoCommand) { ctx.filters = args.options("--filter"); + + if (args.option("--elide-lines")) |elide_lines| { + if (elide_lines.len > 0) { + ctx.bundler_options.elide_lines = std.fmt.parseInt(usize, elide_lines, 10) catch { + Output.prettyErrorln("error: Invalid elide-lines: \"{s}\"", .{elide_lines}); + Global.exit(1); + }; + } + } } if (cmd == .TestCommand) { @@ -1106,6 +1117,15 @@ pub const Arguments = struct { ctx.debug.silent = true; } + if (args.option("--elide-lines")) |elide_lines| { + if (elide_lines.len > 0) { + ctx.bundler_options.elide_lines = std.fmt.parseInt(usize, elide_lines, 10) catch { + Output.prettyErrorln("error: Invalid elide-lines: \"{s}\"", .{elide_lines}); + Global.exit(1); + }; + } + } + if (opts.define) |define| { if (define.keys.len > 0) bun.JSC.RuntimeTranspilerCache.is_disabled = true; @@ -1513,7 +1533,7 @@ pub const Command = struct { env_behavior: Api.DotEnvBehavior = .disable, env_prefix: []const u8 = "", - + elide_lines: ?usize = null, // Compile options compile: bool = false, compile_target: Cli.CompileTarget = .{}, diff --git a/src/cli/filter_run.zig b/src/cli/filter_run.zig index cede921e3f..9093ee3fa2 100644 --- a/src/cli/filter_run.zig +++ b/src/cli/filter_run.zig @@ -29,6 +29,7 @@ const ScriptConfig = struct { // ../../node_modules/.bin // and so forth, in addition to the user's $PATH. PATH: []const u8, + elide_count: ?usize, fn cmp(_: void, a: @This(), b: @This()) bool { return bun.strings.cmpStringsAsc({}, a.package_name, b.package_name); @@ -247,7 +248,7 @@ const State = struct { if (data[data.len - 1] == '\n') { data = data[0 .. data.len - 1]; } - if (max_lines == null) return .{ .content = data, .elided_count = 0 }; + if (max_lines == null or max_lines.? == 0) return .{ .content = data, .elided_count = 0 }; var i: usize = data.len; var lines: usize = 0; while (i > 0) : (i -= 1) { @@ -282,7 +283,9 @@ const State = struct { } for (this.handles) |*handle| { // normally we truncate the output to 10 lines, but on abort we print everything to aid debugging - const e = elide(handle.buffer.items, if (is_abort) null else 10); + const elide_lines = if (is_abort) null else handle.config.elide_count orelse 10; + const e = elide(handle.buffer.items, elide_lines); + try this.draw_buf.writer().print(fmt("{s} {s} $ {s}\n"), .{ handle.config.package_name, handle.config.script_name, handle.config.script_content }); if (e.elided_count > 0) { try this.draw_buf.writer().print( @@ -513,6 +516,7 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn { .combined = copy_script.items[0 .. copy_script.items.len - 1 :0], .deps = pkgjson.dependencies, .PATH = PATH, + .elide_count = ctx.bundler_options.elide_lines, }); } } @@ -536,6 +540,12 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn { .env = this_transpiler.env, }; + // Check if elide-lines is used in a non-terminal environment + if (ctx.bundler_options.elide_lines != null and !state.pretty_output) { + Output.prettyErrorln("error: --elide-lines is only supported in terminal environments", .{}); + Global.exit(1); + } + // initialize the handles var map = bun.StringHashMap(std.ArrayList(*ProcessHandle)).init(ctx.allocator); for (scripts.items, 0..) |*script, i| { diff --git a/test/cli/run/filter-workspace.test.ts b/test/cli/run/filter-workspace.test.ts index a6c402c8a6..2d5b4f4fe9 100644 --- a/test/cli/run/filter-workspace.test.ts +++ b/test/cli/run/filter-workspace.test.ts @@ -86,6 +86,8 @@ function runInCwdSuccess({ antipattern, command = ["present"], auto = false, + env = {}, + elideCount, }: { cwd: string; pattern: string | string[]; @@ -93,8 +95,16 @@ function runInCwdSuccess({ antipattern?: RegExp | RegExp[]; command?: string[]; auto?: boolean; + env?: Record; + elideCount?: number; }) { const cmd = auto ? [bunExe()] : [bunExe(), "run"]; + + // Add elide-lines first if specified + if (elideCount !== undefined) { + cmd.push("--elide-lines", elideCount.toString()); + } + if (Array.isArray(pattern)) { for (const p of pattern) { cmd.push("--filter", p); @@ -102,13 +112,15 @@ function runInCwdSuccess({ } else { cmd.push("--filter", pattern); } + for (const c of command) { cmd.push(c); } + const { exitCode, stdout, stderr } = spawnSync({ - cwd: cwd, - cmd: cmd, - env: bunEnv, + cwd, + cmd, + env: { ...bunEnv, ...env }, stdout: "pipe", stderr: "pipe", }); @@ -416,4 +428,82 @@ describe("bun", () => { expect(stdoutval).toMatch(/code 23/); expect(exitCode).toBe(23); }); + + function runElideLinesTest({ + elideLines, + target_pattern, + antipattern, + win32ExpectedError, + }: { + elideLines: number; + target_pattern: RegExp[]; + antipattern?: RegExp[]; + win32ExpectedError: RegExp; + }) { + const dir = tempDirWithFiles("testworkspace", { + packages: { + dep0: { + "index.js": Array(20).fill("console.log('log_line');").join("\n"), + "package.json": JSON.stringify({ + name: "dep0", + scripts: { + script: `${bunExe()} run index.js`, + }, + }), + }, + }, + "package.json": JSON.stringify({ + name: "ws", + workspaces: ["packages/*"], + }), + }); + + if (process.platform === "win32") { + const { exitCode, stderr } = spawnSync({ + cwd: dir, + cmd: [bunExe(), "run", "--filter", "./packages/dep0", "--elide-lines", String(elideLines), "script"], + env: { ...bunEnv, FORCE_COLOR: "1", NO_COLOR: "0" }, + stdout: "pipe", + stderr: "pipe", + }); + expect(stderr.toString()).toMatch(win32ExpectedError); + expect(exitCode).not.toBe(0); + return; + } + + runInCwdSuccess({ + cwd: dir, + pattern: "./packages/dep0", + env: { FORCE_COLOR: "1", NO_COLOR: "0" }, + target_pattern, + antipattern, + command: ["script"], + elideCount: elideLines, + }); + } + + test("elides output by default when using --filter", () => { + runElideLinesTest({ + elideLines: 10, + target_pattern: [/\[10 lines elided\]/, /(?:log_line[\s\S]*?){20}/], + win32ExpectedError: /--elide-lines is only supported in terminal environments/, + }); + }); + + test("respects --elide-lines argument", () => { + runElideLinesTest({ + elideLines: 15, + target_pattern: [/\[5 lines elided\]/, /(?:log_line[\s\S]*?){20}/], + win32ExpectedError: /--elide-lines is only supported in terminal environments/, + }); + }); + + test("--elide-lines=0 shows all output", () => { + runElideLinesTest({ + elideLines: 0, + target_pattern: [/(?:log_line[\s\S]*?){20}/], + antipattern: [/lines elided/], + win32ExpectedError: /--elide-lines is only supported in terminal environments/, + }); + }); }); From 4f8a6b33c4535e69a04e3a3bf0c7a2eaf75a2a6c Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 22 Dec 2024 20:39:42 -0800 Subject: [PATCH 085/125] +5 passing node:zlib tests (#15944) --- src/bun.js/api/zlib.classes.ts | 40 +-- src/bun.js/node/node_zlib_binding.zig | 85 +++-- src/codegen/class-definitions.ts | 6 +- src/codegen/generate-classes.ts | 24 -- test/js/node/test/common/gc.js | 14 + test/js/node/test/common/index.js | 10 +- .../parallel/test-internal-module-require.js | 210 ++++++------ .../test-zlib-deflate-constructors.js | 309 ++++++++++++++++++ .../test/parallel/test-zlib-dictionary.js | 175 ++++++++++ .../test/parallel/test-zlib-failed-init.js | 46 +++ .../test/parallel/test-zlib-flush-flags.js | 48 +++ .../test-zlib-invalid-input-memory.js | 28 ++ 12 files changed, 796 insertions(+), 199 deletions(-) create mode 100644 test/js/node/test/parallel/test-zlib-deflate-constructors.js create mode 100644 test/js/node/test/parallel/test-zlib-dictionary.js create mode 100644 test/js/node/test/parallel/test-zlib-failed-init.js create mode 100644 test/js/node/test/parallel/test-zlib-flush-flags.js create mode 100644 test/js/node/test/parallel/test-zlib-invalid-input-memory.js diff --git a/src/bun.js/api/zlib.classes.ts b/src/bun.js/api/zlib.classes.ts index a89af81e32..d907e3c838 100644 --- a/src/bun.js/api/zlib.classes.ts +++ b/src/bun.js/api/zlib.classes.ts @@ -1,40 +1,16 @@ import { define } from "../../codegen/class-definitions"; -export default [ - define({ - name: "NativeZlib", +function generate(name: string) { + return define({ + name, construct: true, noConstructor: false, - wantsThis: true, - finalize: true, - configurable: false, - // estimatedSize: true, - klass: {}, - JSType: "0b11101110", - values: ["callback"], - - proto: { - init: { fn: "init" }, - write: { fn: "write" }, - writeSync: { fn: "writeSync" }, - params: { fn: "params" }, - reset: { fn: "reset" }, - close: { fn: "close" }, - onerror: { setter: "setOnError", getter: "getOnError" }, - }, - }), - - define({ - name: "NativeBrotli", - construct: true, - noConstructor: false, - wantsThis: true, finalize: true, configurable: false, estimatedSize: true, klass: {}, JSType: "0b11101110", - values: ["callback"], + values: ["writeCallback", "errorCallback"], proto: { init: { fn: "init" }, @@ -43,7 +19,9 @@ export default [ params: { fn: "params" }, reset: { fn: "reset" }, close: { fn: "close" }, - onerror: { setter: "setOnError", getter: "getOnError" }, + onerror: { setter: "setOnError", this: true, getter: "getOnError" }, }, - }), -]; + }); +} + +export default [generate("NativeZlib"), generate("NativeBrotli")]; diff --git a/src/bun.js/node/node_zlib_binding.zig b/src/bun.js/node/node_zlib_binding.zig index 19f5e7d556..d892844e4a 100644 --- a/src/bun.js/node/node_zlib_binding.zig +++ b/src/bun.js/node/node_zlib_binding.zig @@ -6,6 +6,7 @@ const string = bun.string; const Output = bun.Output; const ZigString = JSC.ZigString; const validators = @import("./util/validators.zig"); +const debug = bun.Output.scoped(.zlib, true); pub fn crc32(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { const arguments = callframe.arguments_old(2).ptr; @@ -71,6 +72,8 @@ pub fn CompressionStream(comptime T: type) type { var in: ?[]const u8 = null; var out: ?[]u8 = null; + const this_value = callframe.this(); + bun.assert(!arguments[0].isUndefined()); // must provide flush value flush = arguments[0].toU32(); _ = std.meta.intToEnum(bun.zlib.FlushValue, flush) catch bun.assert(false); // Invalid flush value @@ -102,7 +105,9 @@ pub fn CompressionStream(comptime T: type) type { this.stream.setBuffers(in, out); this.stream.setFlush(@intCast(flush)); - // + // Only create the strong handle when we have a pending write + // And make sure to clear it when we are done. + this.this_value.set(globalThis, this_value); const vm = globalThis.bunVM(); this.task = .{ .callback = &AsyncJob.runTask }; @@ -136,13 +141,23 @@ pub fn CompressionStream(comptime T: type) type { this.write_in_progress = false; - if (!(this.checkError(globalThis) catch return globalThis.reportActiveExceptionAsUnhandled(error.JSError))) { + // Clear the strong handle before we call any callbacks. + const this_value = this.this_value.trySwap() orelse { + debug("this_value is null in runFromJSThread", .{}); + return; + }; + + this_value.ensureStillAlive(); + + if (!(this.checkError(globalThis, this_value) catch return globalThis.reportActiveExceptionAsUnhandled(error.JSError))) { return; } this.stream.updateWriteResult(&this.write_result.?[1], &this.write_result.?[0]); + this_value.ensureStillAlive(); - _ = this.write_callback.get().?.call(globalThis, this.this_value.get().?, &.{}) catch |err| globalThis.reportActiveExceptionAsUnhandled(err); + const write_callback: JSC.JSValue = T.writeCallbackGetCached(this_value).?; + _ = write_callback.call(globalThis, this_value, &.{}) catch |err| globalThis.reportActiveExceptionAsUnhandled(err); if (this.pending_close) _ = this._close(); } @@ -192,11 +207,10 @@ pub fn CompressionStream(comptime T: type) type { this.stream.setBuffers(in, out); this.stream.setFlush(@intCast(flush)); - - // + const this_value = callframe.this(); this.stream.doWork(); - if (try this.checkError(globalThis)) { + if (try this.checkError(globalThis, this_value)) { this.stream.updateWriteResult(&this.write_result.?[1], &this.write_result.?[0]); this.write_in_progress = false; } @@ -206,11 +220,9 @@ pub fn CompressionStream(comptime T: type) type { } pub fn reset(this: *T, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { - _ = callframe; - const err = this.stream.reset(); if (err.isError()) { - try this.emitError(globalThis, err); + try this.emitError(globalThis, callframe.this(), err); } return .undefined; } @@ -233,34 +245,34 @@ pub fn CompressionStream(comptime T: type) type { this.stream.close(); } - pub fn setOnError(this: *T, globalThis: *JSC.JSGlobalObject, value: JSC.JSValue) bool { + pub fn setOnError(_: *T, this_value: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) bool { if (value.isFunction()) { - this.onerror_value.set(globalThis, value); + T.errorCallbackSetCached(this_value, globalObject, value); } return true; } - pub fn getOnError(this: *T, globalThis: *JSC.JSGlobalObject) JSC.JSValue { - _ = globalThis; - return this.onerror_value.get() orelse .undefined; + pub fn getOnError(_: *T, this_value: JSC.JSValue, _: *JSC.JSGlobalObject) JSC.JSValue { + return T.errorCallbackGetCached(this_value) orelse .undefined; } /// returns true if no error was detected/emitted - fn checkError(this: *T, globalThis: *JSC.JSGlobalObject) !bool { + fn checkError(this: *T, globalThis: *JSC.JSGlobalObject, this_value: JSC.JSValue) !bool { const err = this.stream.getErrorInfo(); if (!err.isError()) return true; - try this.emitError(globalThis, err); + try this.emitError(globalThis, this_value, err); return false; } - fn emitError(this: *T, globalThis: *JSC.JSGlobalObject, err_: Error) !void { + fn emitError(this: *T, globalThis: *JSC.JSGlobalObject, this_value: JSC.JSValue, err_: Error) !void { var msg_str = bun.String.createFormat("{s}", .{std.mem.sliceTo(err_.msg, 0) orelse ""}) catch bun.outOfMemory(); const msg_value = msg_str.transferToJS(globalThis); const err_value = JSC.jsNumber(err_.err); var code_str = bun.String.createFormat("{s}", .{std.mem.sliceTo(err_.code, 0) orelse ""}) catch bun.outOfMemory(); const code_value = code_str.transferToJS(globalThis); - _ = try this.onerror_value.get().?.call(globalThis, this.this_value.get().?, &.{ msg_value, err_value, code_value }); + const callback: JSC.JSValue = T.errorCallbackGetCached(this_value) orelse Output.panic("Assertion failure: cachedErrorCallback is null in node:zlib binding", .{}); + _ = try callback.call(globalThis, this_value, &.{ msg_value, err_value, code_value }); this.write_in_progress = false; if (this.pending_close) _ = this._close(); @@ -307,8 +319,6 @@ pub const SNativeZlib = struct { globalThis: *JSC.JSGlobalObject, stream: ZlibContext = .{}, write_result: ?[*]u32 = null, - write_callback: JSC.Strong = .{}, - onerror_value: JSC.Strong = .{}, poll_ref: CountedKeepAlive = .{}, this_value: JSC.Strong = .{}, write_in_progress: bool = false, @@ -341,11 +351,10 @@ pub const SNativeZlib = struct { } //// adding this didnt help much but leaving it here to compare the number with later - // pub fn estimatedSize(this: *const SNativeZlib) usize { - // _ = this; - // const internal_state_size = 3309; // @sizeOf(@cImport(@cInclude("deflate.h")).internal_state) @ cloudflare/zlib @ 92530568d2c128b4432467b76a3b54d93d6350bd - // return @sizeOf(SNativeZlib) + internal_state_size; - // } + pub fn estimatedSize(_: *const SNativeZlib) usize { + const internal_state_size = 3309; // @sizeOf(@cImport(@cInclude("deflate.h")).internal_state) @ cloudflare/zlib @ 92530568d2c128b4432467b76a3b54d93d6350bd + return @sizeOf(SNativeZlib) + internal_state_size; + } pub fn init(this: *SNativeZlib, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { const arguments = callframe.argumentsUndef(7).slice(); @@ -364,7 +373,7 @@ pub const SNativeZlib = struct { const dictionary = if (arguments[6].isUndefined()) null else arguments[6].asArrayBuffer(globalThis).?.byteSlice(); this.write_result = writeResult; - this.write_callback.set(globalThis, writeCallback); + SNativeZlib.writeCallbackSetCached(callframe.this(), globalThis, writeCallback); this.stream.init(level, windowBits, memLevel, strategy, dictionary); @@ -383,15 +392,15 @@ pub const SNativeZlib = struct { const err = this.stream.setParams(level, strategy); if (err.isError()) { - try this.emitError(globalThis, err); + try this.emitError(globalThis, callframe.this(), err); } return .undefined; } pub fn deinit(this: *@This()) void { - this.write_callback.deinit(); - this.onerror_value.deinit(); + this.this_value.deinit(); this.poll_ref.deinit(); + this.stream.close(); this.destroy(); } }; @@ -662,7 +671,7 @@ pub const NativeBrotli = JSC.Codegen.JSNativeBrotli.getConstructor; pub const SNativeBrotli = struct { pub usingnamespace bun.NewRefCounted(@This(), deinit); - pub usingnamespace JSC.Codegen.JSNativeZlib; + pub usingnamespace JSC.Codegen.JSNativeBrotli; pub usingnamespace CompressionStream(@This()); ref_count: u32 = 1, @@ -670,8 +679,6 @@ pub const SNativeBrotli = struct { globalThis: *JSC.JSGlobalObject, stream: BrotliContext = .{}, write_result: ?[*]u32 = null, - write_callback: JSC.Strong = .{}, - onerror_value: JSC.Strong = .{}, poll_ref: CountedKeepAlive = .{}, this_value: JSC.Strong = .{}, write_in_progress: bool = false, @@ -718,6 +725,7 @@ pub const SNativeBrotli = struct { pub fn init(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { const arguments = callframe.argumentsUndef(3).slice(); + const this_value = callframe.this(); if (arguments.len != 3) { return globalThis.ERR_MISSING_ARGS("init(params, writeResult, writeCallback)", .{}).throw(); } @@ -725,12 +733,14 @@ pub const SNativeBrotli = struct { // this does not get gc'd because it is stored in the JS object's `this._writeState`. and the JS object is tied to the native handle as `_handle[owner_symbol]`. const writeResult = arguments[1].asArrayBuffer(globalThis).?.asU32().ptr; const writeCallback = try validators.validateFunction(globalThis, arguments[2], "writeCallback", .{}); + this.write_result = writeResult; - this.write_callback.set(globalThis, writeCallback); + + SNativeBrotli.writeCallbackSetCached(this_value, globalThis, writeCallback); var err = this.stream.init(); if (err.isError()) { - try this.emitError(globalThis, err); + try this.emitError(globalThis, this_value, err); return JSC.jsBoolean(false); } @@ -759,9 +769,12 @@ pub const SNativeBrotli = struct { } pub fn deinit(this: *@This()) void { - this.write_callback.deinit(); - this.onerror_value.deinit(); + this.this_value.deinit(); this.poll_ref.deinit(); + switch (this.stream.mode) { + .BROTLI_ENCODE, .BROTLI_DECODE => this.stream.close(), + else => {}, + } this.destroy(); } }; diff --git a/src/codegen/class-definitions.ts b/src/codegen/class-definitions.ts index ec2f9e8a43..daf15ed5b5 100644 --- a/src/codegen/class-definitions.ts +++ b/src/codegen/class-definitions.ts @@ -58,7 +58,11 @@ export interface ClassDefinition { values?: string[]; JSType?: string; noConstructor?: boolean; - wantsThis?: boolean; + + // Do not try to track the `this` value in the constructor automatically. + // That is a memory leak. + wantsThis?: never; + /** * Called from any thread. * diff --git a/src/codegen/generate-classes.ts b/src/codegen/generate-classes.ts index 6f30301b08..b333caf88b 100644 --- a/src/codegen/generate-classes.ts +++ b/src/codegen/generate-classes.ts @@ -361,12 +361,6 @@ JSC_DECLARE_CUSTOM_GETTER(js${typeName}Constructor); `; } - if (obj.wantsThis) { - externs += ` -extern JSC_CALLCONV void* JSC_HOST_CALL_ATTRIBUTES ${classSymbolName(typeName, "_setThis")}(JSC::JSGlobalObject*, void*, JSC::EncodedJSValue); -`; - } - if (obj.structuredClone) { externs += `extern JSC_CALLCONV void JSC_HOST_CALL_ATTRIBUTES ${symbolName( @@ -652,13 +646,6 @@ JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES ${name}::construct(JSC::JSGlobalObj } auto value = JSValue::encode(instance); -${ - obj.wantsThis - ? ` - ${classSymbolName(typeName, "_setThis")}(globalObject, ptr, value); -` - : "" -} RELEASE_AND_RETURN(scope, value); } @@ -1661,7 +1648,6 @@ function generateZig( construct, finalize, noConstructor = false, - wantsThis = false, overridesToJS = false, estimatedSize, call = false, @@ -1794,16 +1780,6 @@ const JavaScriptCoreBindings = struct { `; } - if (construct && !noConstructor && wantsThis) { - exports.set("_setThis", classSymbolName(typeName, "_setThis")); - output += ` - pub fn ${classSymbolName(typeName, "_setThis")}(globalObject: *JSC.JSGlobalObject, ptr: *anyopaque, this: JSC.JSValue) callconv(JSC.conv) void { - const real: *${typeName} = @ptrCast(@alignCast(ptr)); - real.this_value.set(globalObject, this); - } - `; - } - if (call) { exports.set("call", classSymbolName(typeName, "call")); output += ` diff --git a/test/js/node/test/common/gc.js b/test/js/node/test/common/gc.js index 8e2c5ee5da..3774f81cc8 100644 --- a/test/js/node/test/common/gc.js +++ b/test/js/node/test/common/gc.js @@ -120,8 +120,22 @@ async function checkIfCollectableByCounting(fn, ctor, count, waitTime = 20) { throw new Error(`${name} cannot be collected`); } +var finalizationRegistry = new FinalizationRegistry(heldValue => { + heldValue.ongc(); +}) + +function onGC(value, holder) { + if (holder?.ongc) { + + finalizationRegistry.register(value, { ongc: holder.ongc }); + } +} + module.exports = { checkIfCollectable, runAndBreathe, checkIfCollectableByCounting, + onGC, }; + + diff --git a/test/js/node/test/common/index.js b/test/js/node/test/common/index.js index c5822beb34..6b5d1079ff 100644 --- a/test/js/node/test/common/index.js +++ b/test/js/node/test/common/index.js @@ -120,8 +120,8 @@ if (process.argv.length === 2 && // invalid. The test itself should handle this case. (process.features.inspector || !flag.startsWith('--inspect'))) { if (flag === "--expose-gc" && process.versions.bun) { - globalThis.gc ??= Bun.gc; - continue; + globalThis.gc ??= () => Bun.gc(true); + break; } console.log( 'NOTE: The test started as a child_process using these flags:', @@ -134,7 +134,9 @@ if (process.argv.length === 2 && if (result.signal) { process.kill(0, result.signal); } else { - process.exit(result.status); + // Ensure we don't call the "exit" callbacks, as that will cause the + // test to fail when it may have passed in the child process. + process.kill(process.pid, result.status); } } } @@ -1216,3 +1218,5 @@ module.exports = new Proxy(common, { return obj[prop]; }, }); + + diff --git a/test/js/node/test/parallel/test-internal-module-require.js b/test/js/node/test/parallel/test-internal-module-require.js index c6e2057d3d..3a02e25cd0 100644 --- a/test/js/node/test/parallel/test-internal-module-require.js +++ b/test/js/node/test/parallel/test-internal-module-require.js @@ -1,112 +1,114 @@ 'use strict'; -// Flags: --expose-internals -// This verifies that -// 1. We do not leak internal modules unless the --require-internals option -// is on. -// 2. We do not accidentally leak any modules to the public global scope. -// 3. Deprecated modules are properly deprecated. +// // Flags: --expose-internals +// // This verifies that +// // 1. We do not leak internal modules unless the --require-internals option +// // is on. +// // 2. We do not accidentally leak any modules to the public global scope. +// // 3. Deprecated modules are properly deprecated. const common = require('../common'); -if (!common.isMainThread) { - common.skip('Cannot test the existence of --expose-internals from worker'); -} +common.skip("This test is not going to be implemented in Bun. We do not support --expose-internals.") -const assert = require('assert'); -const fork = require('child_process').fork; +// if (!common.isMainThread) { +// common.skip('Cannot test the existence of --expose-internals from worker'); +// } -const expectedPublicModules = new Set([ - '_http_agent', - '_http_client', - '_http_common', - '_http_incoming', - '_http_outgoing', - '_http_server', - '_stream_duplex', - '_stream_passthrough', - '_stream_readable', - '_stream_transform', - '_stream_wrap', - '_stream_writable', - '_tls_common', - '_tls_wrap', - 'assert', - 'async_hooks', - 'buffer', - 'child_process', - 'cluster', - 'console', - 'constants', - 'crypto', - 'dgram', - 'dns', - 'domain', - 'events', - 'fs', - 'http', - 'http2', - 'https', - 'inspector', - 'module', - 'net', - 'os', - 'path', - 'perf_hooks', - 'process', - 'punycode', - 'querystring', - 'readline', - 'repl', - 'stream', - 'string_decoder', - 'sys', - 'timers', - 'tls', - 'trace_events', - 'tty', - 'url', - 'util', - 'v8', - 'vm', - 'worker_threads', - 'zlib', -]); +// const assert = require('assert'); +// const fork = require('child_process').fork; -if (process.argv[2] === 'child') { - assert(!process.execArgv.includes('--expose-internals')); - process.once('message', ({ allBuiltins }) => { - const publicModules = new Set(); - for (const id of allBuiltins) { - if (id.startsWith('internal/')) { - assert.throws(() => { - require(id); - }, { - code: 'MODULE_NOT_FOUND', - message: `Cannot find module '${id}'` - }); - } else { - require(id); - publicModules.add(id); - } - } - assert(allBuiltins.length > publicModules.size); - // Make sure all the public modules are available through - // require('module').builtinModules - assert.deepStrictEqual( - publicModules, - new Set(require('module').builtinModules) - ); - assert.deepStrictEqual(publicModules, expectedPublicModules); - }); -} else { - assert(process.execArgv.includes('--expose-internals')); - const child = fork(__filename, ['child'], { - execArgv: [] - }); - const { builtinModules } = require('module'); - // When --expose-internals is on, require('module').builtinModules - // contains internal modules. - const message = { allBuiltins: builtinModules }; - child.send(message); -} +// const expectedPublicModules = new Set([ +// '_http_agent', +// '_http_client', +// '_http_common', +// '_http_incoming', +// '_http_outgoing', +// '_http_server', +// '_stream_duplex', +// '_stream_passthrough', +// '_stream_readable', +// '_stream_transform', +// '_stream_wrap', +// '_stream_writable', +// '_tls_common', +// '_tls_wrap', +// 'assert', +// 'async_hooks', +// 'buffer', +// 'child_process', +// 'cluster', +// 'console', +// 'constants', +// 'crypto', +// 'dgram', +// 'dns', +// 'domain', +// 'events', +// 'fs', +// 'http', +// 'http2', +// 'https', +// 'inspector', +// 'module', +// 'net', +// 'os', +// 'path', +// 'perf_hooks', +// 'process', +// 'punycode', +// 'querystring', +// 'readline', +// 'repl', +// 'stream', +// 'string_decoder', +// 'sys', +// 'timers', +// 'tls', +// 'trace_events', +// 'tty', +// 'url', +// 'util', +// 'v8', +// 'vm', +// 'worker_threads', +// 'zlib', +// ]); + +// if (process.argv[2] === 'child') { +// assert(!process.execArgv.includes('--expose-internals')); +// process.once('message', ({ allBuiltins }) => { +// const publicModules = new Set(); +// for (const id of allBuiltins) { +// if (id.startsWith('internal/')) { +// assert.throws(() => { +// require(id); +// }, { +// code: 'MODULE_NOT_FOUND', +// message: `Cannot find module '${id}'` +// }); +// } else { +// require(id); +// publicModules.add(id); +// } +// } +// assert(allBuiltins.length > publicModules.size); +// // Make sure all the public modules are available through +// // require('module').builtinModules +// assert.deepStrictEqual( +// publicModules, +// new Set(require('module').builtinModules) +// ); +// assert.deepStrictEqual(publicModules, expectedPublicModules); +// }); +// } else { +// assert(process.execArgv.includes('--expose-internals')); +// const child = fork(__filename, ['child'], { +// execArgv: [] +// }); +// const { builtinModules } = require('module'); +// // When --expose-internals is on, require('module').builtinModules +// // contains internal modules. +// const message = { allBuiltins: builtinModules }; +// child.send(message); +// } diff --git a/test/js/node/test/parallel/test-zlib-deflate-constructors.js b/test/js/node/test/parallel/test-zlib-deflate-constructors.js new file mode 100644 index 0000000000..6a5d410086 --- /dev/null +++ b/test/js/node/test/parallel/test-zlib-deflate-constructors.js @@ -0,0 +1,309 @@ +'use strict'; + +require('../common'); + +const zlib = require('zlib'); +const assert = require('assert'); + +// Work with and without `new` keyword +assert.ok(zlib.Deflate() instanceof zlib.Deflate); +assert.ok(new zlib.Deflate() instanceof zlib.Deflate); + +assert.ok(zlib.DeflateRaw() instanceof zlib.DeflateRaw); +assert.ok(new zlib.DeflateRaw() instanceof zlib.DeflateRaw); + +// Throws if `options.chunkSize` is invalid +assert.throws( + () => new zlib.Deflate({ chunkSize: 'test' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.chunkSize" property must be of type number. ' + + 'Received "test"' + } +); + +assert.throws( + () => new zlib.Deflate({ chunkSize: -Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.chunkSize" is out of range. It must ' + + 'be a finite number. Received -Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ chunkSize: 0 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.chunkSize" is out of range. It must ' + + 'be >= 64. Received: 0' + } +); + +// Confirm that maximum chunk size cannot be exceeded because it is `Infinity`. +assert.strictEqual(zlib.constants.Z_MAX_CHUNK, Infinity); + +// Throws if `options.windowBits` is invalid +assert.throws( + () => new zlib.Deflate({ windowBits: 'test' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.windowBits" property must be of type number. ' + + 'Received "test"' + } +); + +assert.throws( + () => new zlib.Deflate({ windowBits: -Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.windowBits" is out of range. It must ' + + 'be a finite number. Received -Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ windowBits: Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.windowBits" is out of range. It must ' + + 'be a finite number. Received Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ windowBits: 0 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.windowBits" is out of range. It must ' + + 'be >= 8 and <= 15. Received 0' + } +); + +// Throws if `options.level` is invalid +assert.throws( + () => new zlib.Deflate({ level: 'test' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.level" property must be of type number. ' + + 'Received "test"' + } +); + +assert.throws( + () => new zlib.Deflate({ level: -Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.level" is out of range. It must ' + + 'be a finite number. Received -Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ level: Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.level" is out of range. It must ' + + 'be a finite number. Received Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ level: -2 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.level" is out of range. It must ' + + 'be >= -1 and <= 9. Received -2' + } +); + +// Throws if `level` invalid in `Deflate.prototype.params()` +assert.throws( + () => new zlib.Deflate().params('test'), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "level" argument must be of type number. ' + + 'Received "test"' + } +); + +assert.throws( + () => new zlib.Deflate().params(-Infinity), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "level" is out of range. It must ' + + 'be a finite number. Received -Infinity' + } +); + +assert.throws( + () => new zlib.Deflate().params(Infinity), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "level" is out of range. It must ' + + 'be a finite number. Received Infinity' + } +); + +assert.throws( + () => new zlib.Deflate().params(-2), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "level" is out of range. It must ' + + 'be >= -1 and <= 9. Received -2' + } +); + +// Throws if options.memLevel is invalid +assert.throws( + () => new zlib.Deflate({ memLevel: 'test' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.memLevel" property must be of type number. ' + + 'Received "test"' + } +); + +assert.throws( + () => new zlib.Deflate({ memLevel: -Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.memLevel" is out of range. It must ' + + 'be a finite number. Received -Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ memLevel: Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.memLevel" is out of range. It must ' + + 'be a finite number. Received Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ memLevel: -2 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.memLevel" is out of range. It must ' + + 'be >= 1 and <= 9. Received -2' + } +); + +// Does not throw if opts.strategy is valid +new zlib.Deflate({ strategy: zlib.constants.Z_FILTERED }); +new zlib.Deflate({ strategy: zlib.constants.Z_HUFFMAN_ONLY }); +new zlib.Deflate({ strategy: zlib.constants.Z_RLE }); +new zlib.Deflate({ strategy: zlib.constants.Z_FIXED }); +new zlib.Deflate({ strategy: zlib.constants.Z_DEFAULT_STRATEGY }); + +// Throws if options.strategy is invalid +assert.throws( + () => new zlib.Deflate({ strategy: 'test' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.strategy" property must be of type number. ' + + 'Received "test"' + } +); + +assert.throws( + () => new zlib.Deflate({ strategy: -Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.strategy" is out of range. It must ' + + 'be a finite number. Received -Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ strategy: Infinity }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.strategy" is out of range. It must ' + + 'be a finite number. Received Infinity' + } +); + +assert.throws( + () => new zlib.Deflate({ strategy: -2 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.strategy" is out of range. It must ' + + 'be >= 0 and <= 4. Received -2' + } +); + +// Throws TypeError if `strategy` is invalid in `Deflate.prototype.params()` +assert.throws( + () => new zlib.Deflate().params(0, 'test'), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "strategy" argument must be of type number. ' + + 'Received "test"' + } +); + +assert.throws( + () => new zlib.Deflate().params(0, -Infinity), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "strategy" is out of range. It must ' + + 'be a finite number. Received -Infinity' + } +); + +assert.throws( + () => new zlib.Deflate().params(0, Infinity), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "strategy" is out of range. It must ' + + 'be a finite number. Received Infinity' + } +); + +assert.throws( + () => new zlib.Deflate().params(0, -2), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "strategy" is out of range. It must ' + + 'be >= 0 and <= 4. Received -2' + } +); + +// Throws if opts.dictionary is not a Buffer +assert.throws( + () => new zlib.Deflate({ dictionary: 'not a buffer' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + } +); \ No newline at end of file diff --git a/test/js/node/test/parallel/test-zlib-dictionary.js b/test/js/node/test/parallel/test-zlib-dictionary.js new file mode 100644 index 0000000000..47eaaa62d0 --- /dev/null +++ b/test/js/node/test/parallel/test-zlib-dictionary.js @@ -0,0 +1,175 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +// Test compression/decompression with dictionary + +const common = require('../common'); +const assert = require('assert'); +const zlib = require('zlib'); + +const spdyDict = Buffer.from([ + 'optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-', + 'languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi', + 'f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser', + '-agent10010120020120220320420520630030130230330430530630740040140240340440', + '5406407408409410411412413414415416417500501502503504505accept-rangesageeta', + 'glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic', + 'ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran', + 'sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati', + 'oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo', + 'ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe', + 'pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic', + 'ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1', + '.1statusversionurl\0', +].join('')); + +const input = [ + 'HTTP/1.1 200 Ok', + 'Server: node.js', + 'Content-Length: 0', + '', +].join('\r\n'); + +function basicDictionaryTest(spdyDict) { + let output = ''; + const deflate = zlib.createDeflate({ dictionary: spdyDict }); + const inflate = zlib.createInflate({ dictionary: spdyDict }); + inflate.setEncoding('utf-8'); + + deflate.on('data', function(chunk) { + inflate.write(chunk); + }); + + inflate.on('data', function(chunk) { + output += chunk; + }); + + deflate.on('end', function() { + inflate.end(); + }); + + inflate.on('end', common.mustCall(function() { + assert.strictEqual(input, output); + })); + + deflate.write(input); + deflate.end(); +} + +function deflateResetDictionaryTest(spdyDict) { + let doneReset = false; + let output = ''; + const deflate = zlib.createDeflate({ dictionary: spdyDict }); + const inflate = zlib.createInflate({ dictionary: spdyDict }); + inflate.setEncoding('utf-8'); + + deflate.on('data', function(chunk) { + if (doneReset) + inflate.write(chunk); + }); + + inflate.on('data', function(chunk) { + output += chunk; + }); + + deflate.on('end', function() { + inflate.end(); + }); + + inflate.on('end', common.mustCall(function() { + assert.strictEqual(input, output); + })); + + deflate.write(input); + deflate.flush(function() { + deflate.reset(); + doneReset = true; + deflate.write(input); + deflate.end(); + }); +} + +function rawDictionaryTest(spdyDict) { + let output = ''; + const deflate = zlib.createDeflateRaw({ dictionary: spdyDict }); + const inflate = zlib.createInflateRaw({ dictionary: spdyDict }); + inflate.setEncoding('utf-8'); + + deflate.on('data', function(chunk) { + inflate.write(chunk); + }); + + inflate.on('data', function(chunk) { + output += chunk; + }); + + deflate.on('end', function() { + inflate.end(); + }); + + inflate.on('end', common.mustCall(function() { + assert.strictEqual(input, output); + })); + + deflate.write(input); + deflate.end(); +} + +function deflateRawResetDictionaryTest(spdyDict) { + let doneReset = false; + let output = ''; + const deflate = zlib.createDeflateRaw({ dictionary: spdyDict }); + const inflate = zlib.createInflateRaw({ dictionary: spdyDict }); + inflate.setEncoding('utf-8'); + + deflate.on('data', function(chunk) { + if (doneReset) + inflate.write(chunk); + }); + + inflate.on('data', function(chunk) { + output += chunk; + }); + + deflate.on('end', function() { + inflate.end(); + }); + + inflate.on('end', common.mustCall(function() { + assert.strictEqual(input, output); + })); + + deflate.write(input); + deflate.flush(function() { + deflate.reset(); + doneReset = true; + deflate.write(input); + deflate.end(); + }); +} + +for (const dict of [spdyDict, ...common.getBufferSources(spdyDict)]) { + basicDictionaryTest(dict); + deflateResetDictionaryTest(dict); + rawDictionaryTest(dict); + deflateRawResetDictionaryTest(dict); +} \ No newline at end of file diff --git a/test/js/node/test/parallel/test-zlib-failed-init.js b/test/js/node/test/parallel/test-zlib-failed-init.js new file mode 100644 index 0000000000..d47b61de66 --- /dev/null +++ b/test/js/node/test/parallel/test-zlib-failed-init.js @@ -0,0 +1,46 @@ +'use strict'; + +require('../common'); + +const assert = require('assert'); +const zlib = require('zlib'); + +assert.throws( + () => zlib.createGzip({ chunkSize: 0 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.chunkSize" is out of range. It must ' + + 'be >= 64. Received: 0' + } +); + +assert.throws( + () => zlib.createGzip({ windowBits: 0 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.windowBits" is out of range. It must ' + + 'be >= 9 and <= 15. Received 0' + } +); + +assert.throws( + () => zlib.createGzip({ memLevel: 0 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.memLevel" is out of range. It must ' + + 'be >= 1 and <= 9. Received 0' + } +); + +{ + const stream = zlib.createGzip({ level: NaN }); + assert.strictEqual(stream._level, zlib.constants.Z_DEFAULT_COMPRESSION); +} + +{ + const stream = zlib.createGzip({ strategy: NaN }); + assert.strictEqual(stream._strategy, zlib.constants.Z_DEFAULT_STRATEGY); +} \ No newline at end of file diff --git a/test/js/node/test/parallel/test-zlib-flush-flags.js b/test/js/node/test/parallel/test-zlib-flush-flags.js new file mode 100644 index 0000000000..1cb552390c --- /dev/null +++ b/test/js/node/test/parallel/test-zlib-flush-flags.js @@ -0,0 +1,48 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const zlib = require('zlib'); + +zlib.createGzip({ flush: zlib.constants.Z_SYNC_FLUSH }); + +assert.throws( + () => zlib.createGzip({ flush: 'foobar' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.flush" property must be of type number. ' + + 'Received "foobar"' + } +); + +assert.throws( + () => zlib.createGzip({ flush: 10000 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.flush" is out of range. It must ' + + 'be >= 0 and <= 5. Received 10000' + } +); + +zlib.createGzip({ finishFlush: zlib.constants.Z_SYNC_FLUSH }); + +assert.throws( + () => zlib.createGzip({ finishFlush: 'foobar' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "options.finishFlush" property must be of type number. ' + + 'Received "foobar"' + } +); + +assert.throws( + () => zlib.createGzip({ finishFlush: 10000 }), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + message: 'The value of "options.finishFlush" is out of range. It must ' + + 'be >= 0 and <= 5. Received 10000' + } +); \ No newline at end of file diff --git a/test/js/node/test/parallel/test-zlib-invalid-input-memory.js b/test/js/node/test/parallel/test-zlib-invalid-input-memory.js new file mode 100644 index 0000000000..c4dbe4c081 --- /dev/null +++ b/test/js/node/test/parallel/test-zlib-invalid-input-memory.js @@ -0,0 +1,28 @@ +// Flags: --expose-gc +'use strict'; +const common = require('../common'); +const { onGC } = require('../common/gc'); +const assert = require('assert'); +const zlib = require('zlib'); + +// Checks that, if a zlib context fails with an error, it can still be GC'ed: +// Refs: https://github.com/nodejs/node/issues/22705 + +const ongc = common.mustCall(); + +{ + const input = Buffer.from('foobar'); + const strm = zlib.createInflate(); + strm.end(input); + strm.once('error', common.mustCall((err) => { + assert(err); + setImmediate(() => { + global.gc(); + // Keep the event loop alive for seeing the async_hooks destroy hook + // we use for GC tracking... + // TODO(addaleax): This should maybe not be necessary? + setImmediate(() => {}); + }); + })); + onGC(strm, { ongc }); +} \ No newline at end of file From 1fa6d9e695f8ec01522950062ae4dc514fa8f4ef Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 01:45:13 -0800 Subject: [PATCH 086/125] +2 passing node:events tests (#15952) --- src/js/node/events.ts | 26 ++-- .../parallel/test-event-emitter-listeners.js | 124 ++++++++++++++++++ .../test/parallel/test-event-emitter-once.js | 70 ++++++++++ 3 files changed, 211 insertions(+), 9 deletions(-) create mode 100644 test/js/node/test/parallel/test-event-emitter-listeners.js create mode 100644 test/js/node/test/parallel/test-event-emitter-once.js diff --git a/src/js/node/events.ts b/src/js/node/events.ts index 8e3d875d45..7759a0d18c 100644 --- a/src/js/node/events.ts +++ b/src/js/node/events.ts @@ -261,25 +261,33 @@ function overflowWarning(emitter, type, handlers) { process.emitWarning(warn); } -function onceWrapper(type, listener, ...args) { - this.removeListener(type, listener); - listener.$apply(this, args); +function _onceWrap(target, type, listener) { + const state = { fired: false, wrapFn: undefined, target, type, listener }; + const wrapped = onceWrapper.bind(state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + if (arguments.length === 0) return this.listener.$call(this.target); + return this.listener.$apply(this.target, arguments); + } } EventEmitterPrototype.once = function once(type, fn) { checkListener(fn); - const bound = onceWrapper.bind(this, type, fn); - bound.listener = fn; - this.addListener(type, bound); + this.on(type, _onceWrap(this, type, fn)); return this; }; Object.defineProperty(EventEmitterPrototype.once, "name", { value: "once" }); EventEmitterPrototype.prependOnceListener = function prependOnceListener(type, fn) { checkListener(fn); - const bound = onceWrapper.bind(this, type, fn); - bound.listener = fn; - this.prependListener(type, bound); + this.prependListener(type, _onceWrap(this, type, fn)); return this; }; diff --git a/test/js/node/test/parallel/test-event-emitter-listeners.js b/test/js/node/test/parallel/test-event-emitter-listeners.js new file mode 100644 index 0000000000..eb1da829c9 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-listeners.js @@ -0,0 +1,124 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +require('../common'); +const assert = require('assert'); +const events = require('events'); + +function listener() {} + +function listener2() {} + +function listener3() { + return 0; +} + +function listener4() { + return 1; +} + +{ + const ee = new events.EventEmitter(); + ee.on('foo', listener); + const fooListeners = ee.listeners('foo'); + assert.deepStrictEqual(ee.listeners('foo'), [listener]); + ee.removeAllListeners('foo'); + assert.deepStrictEqual(ee.listeners('foo'), []); + assert.deepStrictEqual(fooListeners, [listener]); +} + +{ + const ee = new events.EventEmitter(); + ee.on('foo', listener); + const eeListenersCopy = ee.listeners('foo'); + assert.deepStrictEqual(eeListenersCopy, [listener]); + assert.deepStrictEqual(ee.listeners('foo'), [listener]); + eeListenersCopy.push(listener2); + assert.deepStrictEqual(ee.listeners('foo'), [listener]); + assert.deepStrictEqual(eeListenersCopy, [listener, listener2]); +} + +{ + const ee = new events.EventEmitter(); + ee.on('foo', listener); + const eeListenersCopy = ee.listeners('foo'); + ee.on('foo', listener2); + assert.deepStrictEqual(ee.listeners('foo'), [listener, listener2]); + assert.deepStrictEqual(eeListenersCopy, [listener]); +} + +{ + const ee = new events.EventEmitter(); + ee.once('foo', listener); + assert.deepStrictEqual(ee.listeners('foo'), [listener]); +} + +{ + const ee = new events.EventEmitter(); + ee.on('foo', listener); + ee.once('foo', listener2); + assert.deepStrictEqual(ee.listeners('foo'), [listener, listener2]); +} + +{ + const ee = new events.EventEmitter(); + ee._events = undefined; + assert.deepStrictEqual(ee.listeners('foo'), []); +} + +{ + class TestStream extends events.EventEmitter {} + const s = new TestStream(); + assert.deepStrictEqual(s.listeners('foo'), []); +} + +{ + const ee = new events.EventEmitter(); + ee.on('foo', listener); + const wrappedListener = ee.rawListeners('foo'); + assert.strictEqual(wrappedListener.length, 1); + assert.strictEqual(wrappedListener[0], listener); + assert.notStrictEqual(wrappedListener, ee.rawListeners('foo')); + ee.once('foo', listener); + const wrappedListeners = ee.rawListeners('foo'); + assert.strictEqual(wrappedListeners.length, 2); + assert.strictEqual(wrappedListeners[0], listener); + assert.notStrictEqual(wrappedListeners[1], listener); + assert.strictEqual(wrappedListeners[1].listener, listener); + assert.notStrictEqual(wrappedListeners, ee.rawListeners('foo')); + ee.emit('foo'); + assert.strictEqual(wrappedListeners.length, 2); + assert.strictEqual(wrappedListeners[1].listener, listener); +} + +{ + const ee = new events.EventEmitter(); + ee.once('foo', listener3); + ee.on('foo', listener4); + const rawListeners = ee.rawListeners('foo'); + assert.strictEqual(rawListeners.length, 2); + assert.strictEqual(rawListeners[0](), 0); + const rawListener = ee.rawListeners('foo'); + assert.strictEqual(rawListener.length, 1); + assert.strictEqual(rawListener[0](), 1); +} diff --git a/test/js/node/test/parallel/test-event-emitter-once.js b/test/js/node/test/parallel/test-event-emitter-once.js new file mode 100644 index 0000000000..983f6141b9 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-once.js @@ -0,0 +1,70 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const EventEmitter = require('events'); + +const e = new EventEmitter(); + +e.once('hello', common.mustCall()); + +e.emit('hello', 'a', 'b'); +e.emit('hello', 'a', 'b'); +e.emit('hello', 'a', 'b'); +e.emit('hello', 'a', 'b'); + +function remove() { + assert.fail('once->foo should not be emitted'); +} + +e.once('foo', remove); +e.removeListener('foo', remove); +e.emit('foo'); + +e.once('e', common.mustCall(function() { + e.emit('e'); +})); + +e.once('e', common.mustCall()); + +e.emit('e'); + +{ + // once() has different code paths based on the number of arguments being + // emitted. Verify that all of the cases are covered. + const maxArgs = 4; + + for (let i = 0; i <= maxArgs; ++i) { + const ee = new EventEmitter(); + const args = ['foo']; + + for (let j = 0; j < i; ++j) + args.push(j); + + ee.once('foo', common.mustCall((...params) => { + assert.deepStrictEqual(params, args.slice(1)); + })); + + EventEmitter.prototype.emit.apply(ee, args); + } +} From c6b22d399ff9168aed895efa11de1d3d6b3f8aa8 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 03:40:00 -0800 Subject: [PATCH 087/125] Fix showing source code that looks like `export default "file-path"` (#15957) --- src/bun.js/javascript.zig | 3 ++- src/bun.js/module_loader.zig | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 9418c2fe39..5db69ffbf2 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -3620,7 +3620,8 @@ pub const VirtualMachine = struct { if (frame.source_url.hasPrefixComptime("bun:") or frame.source_url.hasPrefixComptime("node:") or frame.source_url.isEmpty() or - frame.source_url.eqlComptime("native")) + frame.source_url.eqlComptime("native") or + frame.source_url.eqlComptime("unknown")) { top_frame_is_builtin = true; continue; diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index a16a51a4a4..b316a1d764 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -1505,6 +1505,19 @@ pub const ModuleLoader = struct { ) !ResolvedSource { const disable_transpilying = comptime flags.disableTranspiling(); + if (comptime disable_transpilying) { + if (!(loader.isJavaScriptLike() or loader == .toml or loader == .text or loader == .json)) { + // Don't print "export default " + return ResolvedSource{ + .allocator = null, + .source_code = bun.String.empty, + .specifier = input_specifier, + .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, + }; + } + } + switch (loader) { .js, .jsx, .ts, .tsx, .json, .toml, .text => { jsc_vm.transpiled_count += 1; From 774e30d383d8e83bc84d2a7ba3354eedbbe7f8a2 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 03:40:51 -0800 Subject: [PATCH 088/125] Make originalLine and originalColumn getter calls not observable (#15951) --- src/bun.js/bindings/ZigGlobalObject.cpp | 6 +- src/bun.js/bindings/bindings.cpp | 163 +++++++++++------- test/js/bun/util/inspect-error.test.js | 135 +++++++++++++-- .../parallel/util-inspect.test.js | 21 +-- 4 files changed, 228 insertions(+), 97 deletions(-) diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 42060e503b..a8a8ea91ce 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -457,7 +457,7 @@ WTF::String Bun::formatStackTrace( sb.append(remappedFrame.source_url.toWTFString()); if (remappedFrame.remapped) { - errorInstance->putDirect(vm, builtinNames(vm).originalLinePublicName(), jsNumber(originalLine.oneBasedInt()), 0); + errorInstance->putDirect(vm, builtinNames(vm).originalLinePublicName(), jsNumber(originalLine.oneBasedInt()), PropertyAttribute::DontEnum | 0); hasSet = true; line = remappedFrame.position.line(); } @@ -599,8 +599,8 @@ WTF::String Bun::formatStackTrace( if (remappedFrame.remapped) { if (errorInstance) { - errorInstance->putDirect(vm, builtinNames(vm).originalLinePublicName(), jsNumber(originalLine.oneBasedInt()), 0); - errorInstance->putDirect(vm, builtinNames(vm).originalColumnPublicName(), jsNumber(originalColumn.oneBasedInt()), 0); + errorInstance->putDirect(vm, builtinNames(vm).originalLinePublicName(), jsNumber(originalLine.oneBasedInt()), PropertyAttribute::DontEnum | 0); + errorInstance->putDirect(vm, builtinNames(vm).originalColumnPublicName(), jsNumber(originalColumn.oneBasedInt()), PropertyAttribute::DontEnum | 0); } } } diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 7df8634f02..cb1a0446df 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -4554,6 +4554,23 @@ static void populateStackTrace(JSC::VM& vm, const WTF::Vector& trace->frames_len = frame_i; } +static JSC::JSValue getNonObservable(JSC::VM& vm, JSC::JSGlobalObject* global, JSC::JSObject* obj, const JSC::PropertyName& propertyName) +{ + PropertySlot slot = PropertySlot(obj, PropertySlot::InternalMethodType::VMInquiry, &vm); + if (obj->getNonIndexPropertySlot(global, propertyName, slot)) { + if (slot.isAccessor()) { + return {}; + } + + JSValue value = slot.getValue(global, propertyName); + if (!value || value.isUndefinedOrNull()) { + return {}; + } + return value; + } + return {}; +} + #define SYNTAX_ERROR_CODE 4 static void fromErrorInstance(ZigException* except, JSC::JSGlobalObject* global, @@ -4593,6 +4610,10 @@ static void fromErrorInstance(ZigException* except, JSC::JSGlobalObject* global, except->message = Bun::toStringRef(err->sanitizedMessageString(global)); } + if (UNLIKELY(scope.exception())) { + scope.clearExceptionExceptTermination(); + } + except->name = Bun::toStringRef(err->sanitizedNameString(global)); except->runtime_type = err->runtimeTypeForCause(); @@ -4600,7 +4621,7 @@ static void fromErrorInstance(ZigException* except, JSC::JSGlobalObject* global, const auto& names = builtinNames(vm); if (except->code != SYNTAX_ERROR_CODE) { - if (JSC::JSValue syscall = obj->getIfPropertyExists(global, names.syscallPublicName())) { + if (JSC::JSValue syscall = getNonObservable(vm, global, obj, names.syscallPublicName())) { if (syscall.isString()) { except->syscall = Bun::toStringRef(global, syscall); } @@ -4610,7 +4631,7 @@ static void fromErrorInstance(ZigException* except, JSC::JSGlobalObject* global, scope.clearExceptionExceptTermination(); } - if (JSC::JSValue code = obj->getIfPropertyExists(global, names.codePublicName())) { + if (JSC::JSValue code = getNonObservable(vm, global, obj, names.codePublicName())) { if (code.isString() || code.isNumber()) { except->code_ = Bun::toStringRef(global, code); } @@ -4620,7 +4641,7 @@ static void fromErrorInstance(ZigException* except, JSC::JSGlobalObject* global, scope.clearExceptionExceptTermination(); } - if (JSC::JSValue path = obj->getIfPropertyExists(global, names.pathPublicName())) { + if (JSC::JSValue path = getNonObservable(vm, global, obj, names.pathPublicName())) { if (path.isString()) { except->path = Bun::toStringRef(global, path); } @@ -4630,7 +4651,7 @@ static void fromErrorInstance(ZigException* except, JSC::JSGlobalObject* global, scope.clearExceptionExceptTermination(); } - if (JSC::JSValue fd = obj->getIfPropertyExists(global, names.fdPublicName())) { + if (JSC::JSValue fd = getNonObservable(vm, global, obj, names.fdPublicName())) { if (fd.isNumber()) { except->fd = fd.toInt32(global); } @@ -4640,7 +4661,7 @@ static void fromErrorInstance(ZigException* except, JSC::JSGlobalObject* global, scope.clearExceptionExceptTermination(); } - if (JSC::JSValue errno_ = obj->getIfPropertyExists(global, names.errnoPublicName())) { + if (JSC::JSValue errno_ = getNonObservable(vm, global, obj, names.errnoPublicName())) { if (errno_.isNumber()) { except->errno_ = errno_.toInt32(global); } @@ -4652,87 +4673,103 @@ static void fromErrorInstance(ZigException* except, JSC::JSGlobalObject* global, } if (getFromSourceURL) { - // we don't want to serialize JSC::StackFrame longer than we need to - // so in this case, we parse the stack trace as a string - if (JSC::JSValue stackValue = obj->getIfPropertyExists(global, vm.propertyNames->stack)) { - if (stackValue.isString()) { - WTF::String stack = stackValue.toWTFString(global); - if (!stack.isEmpty()) { - V8StackTraceIterator iterator(stack); - const uint8_t frame_count = except->stack.frames_len; + { + // we don't want to serialize JSC::StackFrame longer than we need to + // so in this case, we parse the stack trace as a string - except->stack.frames_len = 0; + auto catchScope = DECLARE_CATCH_SCOPE(vm); - iterator.forEachFrame([&](const V8StackTraceIterator::StackFrame& frame, bool& stop) -> void { - ASSERT(except->stack.frames_len < frame_count); - auto& current = except->stack.frames_ptr[except->stack.frames_len]; - current = {}; + // This one intentionally calls getters. + if (JSC::JSValue stackValue = obj->getIfPropertyExists(global, vm.propertyNames->stack)) { + if (stackValue.isString()) { + WTF::String stack = stackValue.toWTFString(global); + if (UNLIKELY(catchScope.exception())) { + catchScope.clearExceptionExceptTermination(); + } + if (!stack.isEmpty()) { - String functionName = frame.functionName.toString(); - String sourceURL = frame.sourceURL.toString(); - current.function_name = Bun::toStringRef(functionName); - current.source_url = Bun::toStringRef(sourceURL); - current.position.line_zero_based = frame.lineNumber.zeroBasedInt(); - current.position.column_zero_based = frame.columnNumber.zeroBasedInt(); + V8StackTraceIterator iterator(stack); + const uint8_t frame_count = except->stack.frames_len; - current.remapped = true; + except->stack.frames_len = 0; - if (frame.isConstructor) { - current.code_type = ZigStackFrameCodeConstructor; - } else if (frame.isGlobalCode) { - current.code_type = ZigStackFrameCodeGlobal; + iterator.forEachFrame([&](const V8StackTraceIterator::StackFrame& frame, bool& stop) -> void { + ASSERT(except->stack.frames_len < frame_count); + auto& current = except->stack.frames_ptr[except->stack.frames_len]; + current = {}; + + String functionName = frame.functionName.toString(); + String sourceURL = frame.sourceURL.toString(); + current.function_name = Bun::toStringRef(functionName); + current.source_url = Bun::toStringRef(sourceURL); + current.position.line_zero_based = frame.lineNumber.zeroBasedInt(); + current.position.column_zero_based = frame.columnNumber.zeroBasedInt(); + + current.remapped = true; + + if (frame.isConstructor) { + current.code_type = ZigStackFrameCodeConstructor; + } else if (frame.isGlobalCode) { + current.code_type = ZigStackFrameCodeGlobal; + } + + except->stack.frames_len += 1; + + stop = except->stack.frames_len >= frame_count; + }); + + if (except->stack.frames_len > 0) { + getFromSourceURL = false; + except->remapped = true; + } else { + except->stack.frames_len = frame_count; } - - except->stack.frames_len += 1; - - stop = except->stack.frames_len >= frame_count; - }); - - if (except->stack.frames_len > 0) { - getFromSourceURL = false; - except->remapped = true; - } else { - except->stack.frames_len = frame_count; } } } + + if (UNLIKELY(catchScope.exception())) { + catchScope.clearExceptionExceptTermination(); + } } - if (getFromSourceURL) { + if (JSC::JSValue sourceURL = getNonObservable(vm, global, obj, vm.propertyNames->sourceURL)) { + if (sourceURL.isString()) { + except->stack.frames_ptr[0].source_url = Bun::toStringRef(global, sourceURL); - if (JSC::JSValue sourceURL = obj->getIfPropertyExists(global, vm.propertyNames->sourceURL)) { - if (sourceURL.isString()) { - except->stack.frames_ptr[0].source_url = Bun::toStringRef(global, sourceURL); + // Take care not to make these getter calls observable. - if (JSC::JSValue column = obj->getIfPropertyExists(global, vm.propertyNames->column)) { - if (column.isNumber()) { - except->stack.frames_ptr[0].position.column_zero_based = OrdinalNumber::fromOneBasedInt(column.toInt32(global)).zeroBasedInt(); - } + if (JSC::JSValue column = getNonObservable(vm, global, obj, vm.propertyNames->column)) { + if (column.isNumber()) { + except->stack.frames_ptr[0].position.column_zero_based = OrdinalNumber::fromOneBasedInt(column.toInt32(global)).zeroBasedInt(); } + } - if (JSC::JSValue line = obj->getIfPropertyExists(global, vm.propertyNames->line)) { - if (line.isNumber()) { - except->stack.frames_ptr[0].position.line_zero_based = OrdinalNumber::fromOneBasedInt(line.toInt32(global)).zeroBasedInt(); + if (JSC::JSValue line = getNonObservable(vm, global, obj, vm.propertyNames->line)) { + if (line.isNumber()) { + except->stack.frames_ptr[0].position.line_zero_based = OrdinalNumber::fromOneBasedInt(line.toInt32(global)).zeroBasedInt(); - if (JSC::JSValue lineText = obj->getIfPropertyExists(global, names.lineTextPublicName())) { - if (lineText.isString()) { - if (JSC::JSString* jsStr = lineText.toStringOrNull(global)) { - auto str = jsStr->value(global); - except->stack.source_lines_ptr[0] = Bun::toStringRef(str); - except->stack.source_lines_numbers[0] = except->stack.frames_ptr[0].position.line(); - except->stack.source_lines_len = 1; - except->remapped = true; - } + if (JSC::JSValue lineText = getNonObservable(vm, global, obj, builtinNames(vm).lineTextPublicName())) { + if (lineText.isString()) { + if (JSC::JSString* jsStr = lineText.toStringOrNull(global)) { + auto str = jsStr->value(global); + except->stack.source_lines_ptr[0] = Bun::toStringRef(str); + except->stack.source_lines_numbers[0] = except->stack.frames_ptr[0].position.line(); + except->stack.source_lines_len = 1; + except->remapped = true; } } } } - - except->stack.frames_len = 1; - except->stack.frames_ptr[0].remapped = obj->hasProperty(global, names.originalLinePublicName()); } } + + { + except->stack.frames_len = 1; + PropertySlot slot = PropertySlot(obj, PropertySlot::InternalMethodType::VMInquiry, &vm); + except->stack.frames_ptr[0].remapped = obj->getNonIndexPropertySlot(global, names.originalLinePublicName(), slot); + } } } diff --git a/test/js/bun/util/inspect-error.test.js b/test/js/bun/util/inspect-error.test.js index a65edd62b3..8e438f9cc1 100644 --- a/test/js/bun/util/inspect-error.test.js +++ b/test/js/bun/util/inspect-error.test.js @@ -1,22 +1,51 @@ -import { expect, test } from "bun:test"; +import { expect, test, describe, jest } from "bun:test"; test("error.cause", () => { const err = new Error("error 1"); const err2 = new Error("error 2", { cause: err }); expect( Bun.inspect(err2) - .replaceAll(import.meta.dir, "[dir]") - .replaceAll("\\", "/"), - ).toMatchSnapshot(); + .replaceAll("\\", "/") + .replaceAll(import.meta.dir.replaceAll("\\", "/"), "[dir]"), + ).toMatchInlineSnapshot(` +"1 | import { expect, test, describe, jest } from "bun:test"; +2 | +3 | test("error.cause", () => { +4 | const err = new Error("error 1"); +5 | const err2 = new Error("error 2", { cause: err }); + ^ +error: error 2 + at [dir]/inspect-error.test.js:5:16 + +1 | import { expect, test, describe, jest } from "bun:test"; +2 | +3 | test("error.cause", () => { +4 | const err = new Error("error 1"); + ^ +error: error 1 + at [dir]/inspect-error.test.js:4:15 +" +`); }); test("Error", () => { const err = new Error("my message"); expect( Bun.inspect(err) - .replaceAll(import.meta.dir, "[dir]") - .replaceAll("\\", "/"), - ).toMatchSnapshot(); + .replaceAll("\\", "/") + .replaceAll(import.meta.dir.replaceAll("\\", "/"), "[dir]"), + ).toMatchInlineSnapshot(` +"27 | " +28 | \`); +29 | }); +30 | +31 | test("Error", () => { +32 | const err = new Error("my message"); + ^ +error: my message + at [dir]/inspect-error.test.js:32:15 +" +`); }); test("BuildMessage", async () => { @@ -26,9 +55,19 @@ test("BuildMessage", async () => { } catch (e) { expect( Bun.inspect(e) - .replaceAll(import.meta.dir, "[dir]") - .replaceAll("\\", "/"), - ).toMatchSnapshot(); + .replaceAll("\\", "/") + .replaceAll(import.meta.dir.replaceAll("\\", "/"), "[dir]"), + ).toMatchInlineSnapshot(` +"2 | const duplicateConstDecl = 456; + ^ +error: "duplicateConstDecl" has already been declared + at [dir]/inspect-error-fixture-bad.js:2:7 + +1 | const duplicateConstDecl = 123; + ^ +note: "duplicateConstDecl" was originally declared here + at [dir]/inspect-error-fixture-bad.js:1:7" +`); } }); @@ -66,11 +105,23 @@ test("Error inside minified file (no color) ", () => { expect( normalizeError( Bun.inspect(e) - .replaceAll(import.meta.dir, "[dir]") .replaceAll("\\", "/") + .replaceAll(import.meta.dir.replaceAll("\\", "/"), "[dir]") .trim(), ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` +"21 | exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=Z; +22 | exports.cache=function(a){return function(){var b=U.current;if(!b)return a.apply(null,arguments);var c=b.getCacheForType(V);b=c.get(a);void 0===b&&(b=W(),c.set(a,b));c=0;for(var f=arguments.length;c { normalizeError( stripANSIColors( Bun.inspect(e, { colors: true }) - .replaceAll(import.meta.dir, "[dir]") .replaceAll("\\", "/") + .replaceAll(import.meta.dir.replaceAll("\\", "/"), "[dir]") .trim(), ).trim(), ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` +"21 | exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=Z; +22 | exports.cache=function(a){return function(){var b=U.current;if(!b)return a.apply(null,arguments);var c=b.getCacheForType(V);b=c.get(a);void 0===b&&(b=W(),c.set(a,b));c=0;for(var f=arguments.length;c { + const err = new Error("my message"); + expect( + require("util") + .inspect(err) + .replaceAll("\\", "/") + .replaceAll(import.meta.path.replaceAll("\\", "/"), "[file]"), + ).toMatchInlineSnapshot(` +"Error: my message + at ([file]:160:19)" +`); +}); + +describe("observable properties", () => { + for (let property of ["sourceURL", "line", "column"]) { + test(`${property} is observable`, () => { + const mock = jest.fn(); + const err = new Error("my message"); + Object.defineProperty(err, property, { + get: mock, + enumerable: true, + configurable: true, + }); + expect(mock).not.toHaveBeenCalled(); + Bun.inspect(err); + expect(mock).not.toHaveBeenCalled(); + }); + } +}); + +test("error.stack throwing an error doesn't lead to a crash", () => { + const err = new Error("my message"); + Object.defineProperty(err, "stack", { + get: () => { + throw new Error("my message"); + }, + enumerable: true, + configurable: true, + }); + expect(() => { + throw err; + }).toThrow(); +}); diff --git a/test/js/node/util/node-inspect-tests/parallel/util-inspect.test.js b/test/js/node/util/node-inspect-tests/parallel/util-inspect.test.js index 0c4bc55a79..5dffd034fa 100644 --- a/test/js/node/util/node-inspect-tests/parallel/util-inspect.test.js +++ b/test/js/node/util/node-inspect-tests/parallel/util-inspect.test.js @@ -656,14 +656,9 @@ test("no assertion failures 2", () => { // Prevent non-enumerable error properties from being printed. { - // TODO(bun): Make originalLine and originalColumn non-enumerable let err = new Error(); err.message = "foobar"; - let out = util - .inspect(err) - .replace(/\{\s*originalLine: .+\s*originalColumn: .+\s*\}/, "") - .trim() - .split("\n"); + let out = util.inspect(err).trim().split("\n"); assert.strictEqual(out[0], "Error: foobar"); assert(out.at(-1).startsWith(" at "), 'Expected "' + out.at(-1) + '" to start with " at "'); // Reset the error, the stack is otherwise not recreated. @@ -671,21 +666,13 @@ test("no assertion failures 2", () => { err.message = "foobar"; err.name = "Unique"; Object.defineProperty(err, "stack", { value: err.stack, enumerable: true }); - out = util - .inspect(err) - .replace(/\{\s*originalLine: .+\s*originalColumn: .+\s*\}/, "") - .trim() - .split("\n"); + out = util.inspect(err).trim().split("\n"); assert.strictEqual(out[0], "Unique: foobar"); assert(out.at(-1).startsWith(" at "), 'Expected "' + out.at(-1) + '" to start with " at "'); err.name = "Baz"; - out = util - .inspect(err) - .replace(/\n\s*originalLine: .+\s*originalColumn: .+/, "") - .trim() - .split("\n"); + out = util.inspect(err).trim().split("\n"); assert.strictEqual(out[0], "Unique: foobar"); - assert.strictEqual(out.at(-2), " name: 'Baz',"); + assert.strictEqual(out.at(-2), " name: 'Baz'"); assert.strictEqual(out.at(-1), "}"); } From da54e819555b8e8e26c9d541d1694ec53402dc66 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 11:04:38 -0800 Subject: [PATCH 089/125] Support bundling HTML files and their js, css, and assets in `Bun.build` and `bun build` (#15940) --- docs/bundler/html.md | 110 +++++ docs/bundler/loaders.md | 77 ++- docs/nav.ts | 7 +- packages/bun-types/bun.d.ts | 22 +- src/HTMLScanner.zig | 297 ++++++++++++ src/api/schema.d.ts | 3 + src/api/schema.js | 4 + src/api/schema.zig | 2 +- src/bake/DevServer.zig | 3 +- src/bake/bake.zig | 2 +- src/bun.js/api/JSBundler.zig | 29 +- src/bun_js.zig | 4 +- src/bundler/bundle_v2.zig | 586 +++++++++++++++++++---- src/cli.zig | 9 +- src/cli/build_command.zig | 2 +- src/codegen/bundle-modules.ts | 1 - src/deps/lol-html.zig | 10 +- src/js_ast.zig | 9 +- src/options.zig | 53 ++- src/transpiler.zig | 4 +- test/bundler/bun-build-api.test.ts | 74 +++ test/bundler/bundler_html.test.ts | 724 +++++++++++++++++++++++++++++ test/bundler/expectBundled.ts | 4 + 23 files changed, 1882 insertions(+), 154 deletions(-) create mode 100644 docs/bundler/html.md create mode 100644 src/HTMLScanner.zig create mode 100644 test/bundler/bundler_html.test.ts diff --git a/docs/bundler/html.md b/docs/bundler/html.md new file mode 100644 index 0000000000..59c9cd2583 --- /dev/null +++ b/docs/bundler/html.md @@ -0,0 +1,110 @@ +As of Bun v1.1.43, Bun's bundler now has first-class support for HTML. Build static sites, landing pages, and web applications with zero configuration. Just point Bun at your HTML file and it handles everything else. + +```html#index.html + + + + + + + + + + +``` + +One command is all you need (won't be experimental after Bun v1.2): + +{% codetabs %} + +```bash#CLI +$ bun build --experimental-html --experimental-css ./index.html --outdir=dist +``` + +```ts#API +Bun.build({ + entrypoints: ["./index.html"], + outdir: "./dist", + + // On by default in Bun v1.2+ + html: true, + experimentalCss: true, +}); +``` + +{% /codetabs %} + +Bun automatically: + +- Bundles, tree-shakes, and optimizes your JavaScript, JSX and TypeScript +- Bundles and optimizes your CSS +- Copies & hashes images and other assets +- Updates all references to local files or packages in your HTML + +## Zero Config, Maximum Performance + +The HTML bundler is enabled by default after Bun v1.2+. Drop in your existing HTML files and Bun will handle: + +- **TypeScript & JSX** - Write modern JavaScript for browsers without the setup +- **CSS** - Bundle CSS stylesheets directly from `` or `@import` +- **Images & Assets** - Automatic copying & hashing & rewriting of assets in JavaScript, CSS, and HTML + +## Watch mode + +You can run `bun build --watch` to watch for changes and rebuild automatically. + +You've never seen a watch mode this fast. + +## Plugin API + +Need more control? Configure the bundler through the JavaScript API and use Bun's builtin `HTMLRewriter` to preprocess HTML. + +```ts +await Bun.build({ + entrypoints: ["./index.html"], + outdir: "./dist", + html: true, + experimentalCss: true, + minify: true, + + plugins: [ + { + // A plugin that makes every HTML tag lowercase + name: "lowercase-html-plugin", + setup({ onLoad }) { + const rewriter = new HTMLRewriter().on("*", { + element(element) { + element.tagName = element.tagName.toLowerCase(); + }, + text(element) { + element.replace(element.text.toLowerCase()); + }, + }); + + onLoad({ filter: /\.html$/ }, async args => { + const html = await Bun.file(args.path).text(); + + return { + // Bun's bundler will scan the HTML for + + +``` + +{% /codetabs %} + +It will output a new HTML file with the bundled assets: + +{% codetabs %} + +```html#dist/output.html + + + + Local image + External image + + + +``` + +{% /codetabs %} + +Under the hood, it uses [`lol-html`](https://github.com/cloudflare/lol-html) to extract script and link tags as entrypoints, and other assets as external. + +Currently, the list of selectors is: + +- `audio[src]` +- `iframe[src]` +- `img[src]` +- `img[srcset]` +- `link:not([rel~='stylesheet']):not([rel~='modulepreload']):not([rel~='manifest']):not([rel~='icon']):not([rel~='apple-touch-icon'])[href]` +- `link[as='font'][href], link[type^='font/'][href]` +- `link[as='image'][href]` +- `link[as='style'][href]` +- `link[as='video'][href], link[as='audio'][href]` +- `link[as='worker'][href]` +- `link[rel='icon'][href], link[rel='apple-touch-icon'][href]` +- `link[rel='manifest'][href]` +- `link[rel='stylesheet'][href]` +- `script[src]` +- `source[src]` +- `source[srcset]` +- `video[poster]` +- `video[src]` + ### `sh` loader **Bun Shell loader**. Default for `.sh` files diff --git a/docs/nav.ts b/docs/nav.ts index 6dd5a06dca..900cfdcb24 100644 --- a/docs/nav.ts +++ b/docs/nav.ts @@ -214,9 +214,9 @@ export default { page("bundler", "`Bun.build`", { description: "Bundle code for consumption in the browser with Bun's native bundler.", }), - // page("bundler/intro", "How bundlers work", { - // description: "A visual introduction to bundling", - // }), + page("bundler/html", "HTML", { + description: `Bundle html files with Bun's native bundler.`, + }), page("bundler/loaders", "Loaders", { description: "Bun's built-in loaders for the bundler and runtime", }), @@ -226,6 +226,7 @@ export default { page("bundler/macros", "Macros", { description: `Run JavaScript functions at bundle-time and inline the results into your bundle`, }), + page("bundler/vs-esbuild", "vs esbuild", { description: `Guides for migrating from other bundlers to Bun.`, }), diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 1d14d6f15a..7cb2e45190 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -1630,10 +1630,28 @@ declare module "bun" { /** * **Experimental** * - * Enable CSS support. + * Bundle CSS files. + * + * This will be enabled by default in Bun v1.2. + * + * @default false (until Bunv 1.2) */ experimentalCss?: boolean; + /** + * **Experimental** + * + * Bundle JavaScript & CSS files from HTML files. JavaScript & CSS files + * from non-external ", .{js_chunk.unique_key}) catch bun.outOfMemory(); + defer allocator.free(script); + element.append(script, true) catch bun.outOfMemory(); + } + } + + const processor = HTMLScanner.HTMLProcessor(@This(), true); + + pub fn run(this: *@This(), input: []const u8) !void { + processor.run(this, input) catch bun.outOfMemory(); + } + }; + + var html_loader = HTMLLoader{ + .linker = c, + .source_index = chunk.entry_point.source_index, + .import_records = import_records[chunk.entry_point.source_index].slice(), + .log = c.log, + .allocator = worker.allocator, + .minify_whitespace = c.options.minify_whitespace, + .chunk = chunk, + .chunks = chunks, + .output = std.ArrayList(u8).init(worker.allocator), + .current_import_record_index = 0, + }; + + html_loader.run(sources[chunk.entry_point.source_index].contents) catch bun.outOfMemory(); + + return .{ + .html = .{ + .code = html_loader.output.items, + .source_index = chunk.entry_point.source_index, + }, + }; + } + + fn postProcessHTMLChunk(ctx: GenerateChunkCtx, worker: *ThreadPool.Worker, chunk: *Chunk) !void { + + // This is where we split output into pieces + + const c = ctx.c; + var j = StringJoiner{ + .allocator = worker.allocator, + .watcher = .{ + .input = chunk.unique_key, + }, + }; + + const compile_results = chunk.compile_results_for_chunk; + + for (compile_results) |compile_result| { + j.push(compile_result.code(), bun.default_allocator); + } + + j.ensureNewlineAtEnd(); + + chunk.intermediate_output = c.breakOutputIntoPieces( + worker.allocator, + &j, + @as(u32, @truncate(ctx.chunks.len)), + ) catch bun.outOfMemory(); + + chunk.isolated_hash = c.generateIsolatedHash(chunk); + } + // This runs after we've already populated the compile results fn postProcessCSSChunk(ctx: GenerateChunkCtx, worker: *ThreadPool.Worker, chunk: *Chunk) !void { const c = ctx.c; @@ -9565,7 +9893,7 @@ pub const LinkerContext = struct { c.source_(chunk.entry_point.source_index), print_options, cross_chunk_import_records.slice(), - &[_]js_ast.Part{ + &[_]Part{ .{ .stmts = chunk.content.javascript.cross_chunk_prefix_stmts.slice() }, }, chunk.renamer, @@ -9578,7 +9906,7 @@ pub const LinkerContext = struct { c.source_(chunk.entry_point.source_index), print_options, &.{}, - &[_]js_ast.Part{ + &[_]Part{ .{ .stmts = chunk.content.javascript.cross_chunk_suffix_stmts.slice() }, }, chunk.renamer, @@ -10688,7 +11016,7 @@ pub const LinkerContext = struct { c.source_(source_index), print_options, ast.import_records.slice(), - &[_]js_ast.Part{ + &[_]Part{ .{ .stmts = stmts.items, }, @@ -11583,7 +11911,7 @@ pub const LinkerContext = struct { allocator: std.mem.Allocator, temp_allocator: std.mem.Allocator, ) js_printer.PrintResult { - const parts: []js_ast.Part = c.graph.ast.items(.parts)[part_range.source_index.get()].slice()[part_range.part_index_begin..part_range.part_index_end]; + const parts: []Part = c.graph.ast.items(.parts)[part_range.source_index.get()].slice()[part_range.part_index_begin..part_range.part_index_end]; const all_flags: []const JSMeta.Flags = c.graph.meta.items(.flags); const flags = all_flags[part_range.source_index.get()]; const wrapper_part_index = if (flags.wrap != .none) @@ -12180,8 +12508,8 @@ pub const LinkerContext = struct { runtime_require_ref: ?Ref, source_index: Index, ) js_printer.PrintResult { - const parts_to_print = &[_]js_ast.Part{ - js_ast.Part{ .stmts = out_stmts }, + const parts_to_print = &[_]Part{ + Part{ .stmts = out_stmts }, }; const print_options = js_printer.Options{ @@ -12283,7 +12611,7 @@ pub const LinkerContext = struct { var has_js_chunk = false; var has_css_chunk = false; - + var has_html_chunk = false; bun.assert(chunks.len > 0); { @@ -12309,7 +12637,7 @@ pub const LinkerContext = struct { c.source_maps.line_offset_tasks.len = 0; } - if (c.options.experimental_css) { + if (c.options.experimental.css) { // Per CSS chunk: // Remove duplicate rules across files. This must be done in serial, not // in parallel, and must be done from the last rule to the first rule. @@ -12365,6 +12693,7 @@ pub const LinkerContext = struct { defer c.allocator.free(chunk_contexts); var wait_group = try c.allocator.create(sync.WaitGroup); wait_group.init(); + defer { wait_group.deinit(); c.allocator.destroy(wait_group); @@ -12386,6 +12715,13 @@ pub const LinkerContext = struct { total_count += chunk.content.css.imports_in_chunk_in_order.len; chunk.compile_results_for_chunk = c.allocator.alloc(CompileResult, chunk.content.css.imports_in_chunk_in_order.len) catch bun.outOfMemory(); }, + .html => { + has_html_chunk = true; + // HTML gets only one chunk. + chunk_ctx.* = .{ .wg = wait_group, .c = c, .chunks = chunks, .chunk = chunk }; + total_count += 1; + chunk.compile_results_for_chunk = c.allocator.alloc(CompileResult, 1) catch bun.outOfMemory(); + }, } } @@ -12425,8 +12761,7 @@ pub const LinkerContext = struct { } }, .css => { - for (chunk.content.css.imports_in_chunk_in_order.slice(), 0..) |css_import, i| { - _ = css_import; // autofix + for (0..chunk.content.css.imports_in_chunk_in_order.len) |i| { remaining_part_ranges[0] = .{ .part_range = .{}, .i = @as(u32, @truncate(i)), @@ -12440,6 +12775,19 @@ pub const LinkerContext = struct { remaining_part_ranges = remaining_part_ranges[1..]; } }, + .html => { + remaining_part_ranges[0] = .{ + .part_range = .{}, + .i = 0, + .task = ThreadPoolLib.Task{ + .callback = &generateCompileResultForHtmlChunk, + }, + .ctx = chunk_ctx, + }; + + batch.push(ThreadPoolLib.Batch.from(&remaining_part_ranges[0].task)); + remaining_part_ranges = remaining_part_ranges[1..]; + }, } } wait_group.counter = @as(u32, @truncate(total_count)); @@ -12591,7 +12939,7 @@ pub const LinkerContext = struct { ) catch unreachable; const root_path = c.resolver.opts.output_dir; - const more_than_one_output = c.parse_graph.additional_output_files.items.len > 0 or c.options.generate_bytecode_cache or (has_css_chunk and has_js_chunk); + const more_than_one_output = c.parse_graph.additional_output_files.items.len > 0 or c.options.generate_bytecode_cache or (has_css_chunk and has_js_chunk) or (has_html_chunk and (has_js_chunk or has_css_chunk)); if (!c.resolver.opts.compile and more_than_one_output and !c.resolver.opts.supports_multiple_outputs) { try c.log.addError(null, Logger.Loc.Empty, "cannot write multiple output files without an output directory"); @@ -12792,6 +13140,7 @@ pub const LinkerContext = struct { .referenced_css_files = switch (chunk.content) { .javascript => |js| @ptrCast(try bun.default_allocator.dupe(u32, js.css_chunks)), .css => &.{}, + .html => &.{}, }, })); if (sourcemap_output_file) |sourcemap_file| { @@ -13203,6 +13552,7 @@ pub const LinkerContext = struct { .referenced_css_files = switch (chunk.content) { .javascript => |js| @ptrCast(try bun.default_allocator.dupe(u32, js.css_chunks)), .css => &.{}, + .html => &.{}, }, })); @@ -13313,7 +13663,7 @@ pub const LinkerContext = struct { entry_points_count: usize, distances: []u32, distance: u32, - parts: []bun.BabyList(js_ast.Part), + parts: []bun.BabyList(Part), import_records: []bun.BabyList(bun.ImportRecord), file_entry_bits: []AutoBitSet, css_reprs: []?*bun.css.BundlerStyleSheet, @@ -13403,7 +13753,7 @@ pub const LinkerContext = struct { c: *LinkerContext, source_index: Index.Int, side_effects: []_resolver.SideEffects, - parts: []bun.BabyList(js_ast.Part), + parts: []bun.BabyList(Part), import_records: []bun.BabyList(bun.ImportRecord), entry_point_kinds: []EntryPoint.Kind, css_reprs: []?*bun.css.BundlerStyleSheet, @@ -13519,12 +13869,12 @@ pub const LinkerContext = struct { part_index: Index.Int, source_index: Index.Int, side_effects: []_resolver.SideEffects, - parts: []bun.BabyList(js_ast.Part), + parts: []bun.BabyList(Part), import_records: []bun.BabyList(bun.ImportRecord), entry_point_kinds: []EntryPoint.Kind, css_reprs: []?*bun.css.BundlerStyleSheet, ) void { - const part: *js_ast.Part = &parts[source_index].slice()[part_index]; + const part: *Part = &parts[source_index].slice()[part_index]; // only once if (part.is_live) { @@ -13899,7 +14249,7 @@ pub const LinkerContext = struct { for (common_js_parts) |part_id| { const runtime_parts = c.graph.ast.items(.parts)[Index.runtime.get()].slice(); - const part: *js_ast.Part = &runtime_parts[part_id]; + const part: *Part = &runtime_parts[part_id]; const symbol_refs = part.symbol_uses.keys(); for (symbol_refs) |ref| { if (ref.eql(c.cjs_runtime_ref)) continue; @@ -13922,7 +14272,7 @@ pub const LinkerContext = struct { .{ .stmts = &.{}, .symbol_uses = bun.from( - js_ast.Part.SymbolUseMap, + Part.SymbolUseMap, c.allocator, .{ .{ wrapper_ref, .{ .count_estimate = 1 } }, @@ -13983,7 +14333,7 @@ pub const LinkerContext = struct { source_index, .{ .symbol_uses = bun.from( - js_ast.Part.SymbolUseMap, + Part.SymbolUseMap, c.allocator, .{ .{ wrapper_ref, .{ .count_estimate = 1 } }, @@ -14615,6 +14965,7 @@ pub const Chunk = struct { entry_point: Chunk.EntryPoint = .{}, is_executable: bool = false, + has_html_chunk: bool = false, output_source_map: sourcemap.SourceMapPieces, @@ -14629,6 +14980,30 @@ pub const Chunk = struct { return this.entry_point.is_entry_point; } + pub fn getJSChunkForHTML(this: *const Chunk, chunks: []Chunk) ?*Chunk { + const entry_point_id = this.entry_point.entry_point_id; + for (chunks) |*other| { + if (other.content == .javascript) { + if (other.entry_point.entry_point_id == entry_point_id) { + return other; + } + } + } + return null; + } + + pub fn getCSSChunkForHTML(this: *const Chunk, chunks: []Chunk) ?*Chunk { + const entry_point_id = this.entry_point.entry_point_id; + for (chunks) |*other| { + if (other.content == .css) { + if (other.entry_point.entry_point_id == entry_point_id) { + return other; + } + } + } + return null; + } + pub inline fn entryBits(this: *const Chunk) *const AutoBitSet { return &this.entry_bits; } @@ -14980,11 +15355,12 @@ pub const Chunk = struct { pub const EntryPoint = packed struct(u64) { /// Index into `Graph.input_files` source_index: u32 = 0, - entry_point_id: u31 = 0, + entry_point_id: ID = 0, is_entry_point: bool = false, + is_html: bool = false, /// so `EntryPoint` can be a u64 - pub const ID = u31; + pub const ID = u30; }; pub const JavaScriptChunk = struct { @@ -15078,16 +15454,20 @@ pub const Chunk = struct { pub const ContentKind = enum { javascript, css, + html, }; + pub const HtmlChunk = struct {}; + pub const Content = union(ContentKind) { javascript: JavaScriptChunk, css: CssChunk, - + html: HtmlChunk, pub fn loader(this: *const Content) Loader { return switch (this.*) { .javascript => .js, .css => .css, + .html => .html, }; } @@ -15095,6 +15475,7 @@ pub const Chunk = struct { return switch (this.*) { .javascript => "js", .css => "css", + .html => "html", }; } }; @@ -15174,6 +15555,10 @@ pub const CompileResult = union(enum) { // TODO: we need to do this source_map: ?bun.sourcemap.Chunk = null, }, + html: struct { + source_index: Index.Int, + code: []const u8, + }, pub const empty = CompileResult{ .javascript = .{ @@ -15192,7 +15577,7 @@ pub const CompileResult = union(enum) { .result => |r2| r2.code, else => "", }, - .css => |*c| c.code, + inline .html, .css => |*c| c.code, }; } @@ -15203,14 +15588,13 @@ pub const CompileResult = union(enum) { else => null, }, .css => |*c| c.source_map, + .html => null, }; } pub fn sourceIndex(this: *const CompileResult) Index.Int { return switch (this.*) { - .javascript => |r| r.source_index, - .css => |*c| c.source_index, - // else => 0, + inline else => |*r| r.source_index, }; } }; @@ -15503,7 +15887,7 @@ pub const AstBuilder = struct { bun.assert(p.scopes.items.len == 0); const module_scope = p.current_scope; - var parts = try js_ast.Part.List.initCapacity(p.allocator, 2); + var parts = try Part.List.initCapacity(p.allocator, 2); parts.len = 2; parts.mut(0).* = .{}; parts.mut(1).* = .{ @@ -15512,7 +15896,7 @@ pub const AstBuilder = struct { // pretend that every symbol was used .symbol_uses = uses: { - var map: js_ast.Part.SymbolUseMap = .{}; + var map: Part.SymbolUseMap = .{}; try map.ensureTotalCapacity(p.allocator, p.symbols.items.len); for (0..p.symbols.items.len) |i| { map.putAssumeCapacity(Ref{ diff --git a/src/cli.zig b/src/cli.zig index 95c5a10a04..15eebedb3d 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -286,8 +286,9 @@ pub const Arguments = struct { clap.parseParam("--minify-syntax Minify syntax and inline data") catch unreachable, clap.parseParam("--minify-whitespace Minify whitespace") catch unreachable, clap.parseParam("--minify-identifiers Minify identifiers") catch unreachable, - clap.parseParam("--experimental-css Enabled experimental CSS bundling") catch unreachable, + clap.parseParam("--experimental-css Enable experimental CSS bundling") catch unreachable, clap.parseParam("--experimental-css-chunking Chunk CSS files together to reduce duplicated CSS loaded in a browser. Only has an affect when multiple entrypoints import CSS") catch unreachable, + clap.parseParam("--experimental-html Use .html files as entry points for JavaScript & CSS") catch unreachable, clap.parseParam("--dump-environment-variables") catch unreachable, clap.parseParam("--conditions ... Pass custom conditions to resolve") catch unreachable, clap.parseParam("--app (EXPERIMENTAL) Build a web app for production using Bun Bake.") catch unreachable, @@ -841,7 +842,9 @@ pub const Arguments = struct { } const experimental_css = args.flag("--experimental-css"); - ctx.bundler_options.experimental_css = experimental_css; + const experimental_html = args.flag("--experimental-html"); + ctx.bundler_options.experimental.css = experimental_css; + ctx.bundler_options.experimental.html = experimental_html; ctx.bundler_options.css_chunking = args.flag("--experimental-css-chunking"); const minify_flag = args.flag("--minify"); @@ -1524,7 +1527,7 @@ pub const Command = struct { bytecode: bool = false, banner: []const u8 = "", footer: []const u8 = "", - experimental_css: bool = false, + experimental: options.Loader.Experimental = .{}, css_chunking: bool = false, bake: bool = false, diff --git a/src/cli/build_command.zig b/src/cli/build_command.zig index 88c449fc4f..073bceb129 100644 --- a/src/cli/build_command.zig +++ b/src/cli/build_command.zig @@ -109,7 +109,7 @@ pub const BuildCommand = struct { this_transpiler.options.footer = ctx.bundler_options.footer; this_transpiler.options.drop = ctx.args.drop; - this_transpiler.options.experimental_css = ctx.bundler_options.experimental_css; + this_transpiler.options.experimental = ctx.bundler_options.experimental; this_transpiler.options.css_chunking = ctx.bundler_options.css_chunking; this_transpiler.options.output_dir = ctx.bundler_options.outdir; diff --git a/src/codegen/bundle-modules.ts b/src/codegen/bundle-modules.ts index b98828c5e5..3427102121 100644 --- a/src/codegen/bundle-modules.ts +++ b/src/codegen/bundle-modules.ts @@ -412,7 +412,6 @@ writeIfNotChanged( ESM = 5, JSONForObjectLoader = 6, ExportsObject = 7, - // Built in modules are loaded through InternalModuleRegistry by numerical ID. // In this enum are represented as \`(1 << 9) & id\` InternalModuleRegistryFlag = 1 << 9, diff --git a/src/deps/lol-html.zig b/src/deps/lol-html.zig index d5e747c773..bafd833c90 100644 --- a/src/deps/lol-html.zig +++ b/src/deps/lol-html.zig @@ -33,7 +33,9 @@ pub const HTMLRewriter = opaque { pub fn write(rewriter: *HTMLRewriter, chunk: []const u8) Error!void { auto_disable(); - if (rewriter.lol_html_rewriter_write(ptrWithoutPanic(chunk), chunk.len) < 0) + const ptr = ptrWithoutPanic(chunk); + const rc = rewriter.lol_html_rewriter_write(ptr, chunk.len); + if (rc < 0) return error.Fail; } @@ -207,17 +209,17 @@ pub const HTMLRewriter = opaque { auto_disable(); return switch (builder.lol_html_rewriter_builder_add_element_content_handlers( selector, - if (element_handler_data != null) + if (element_handler != null and element_handler_data != null) DirectiveHandler(Element, ElementHandler, element_handler.?) else null, element_handler_data, - if (comment_handler_data != null) + if (comment_handler != null and comment_handler_data != null) DirectiveHandler(Comment, CommentHandler, comment_handler.?) else null, comment_handler_data, - if (text_chunk_handler_data != null) + if (text_chunk_handler != null and text_chunk_handler_data != null) DirectiveHandler(TextChunk, TextChunkHandler, text_chunk_handler.?) else null, diff --git a/src/js_ast.zig b/src/js_ast.zig index cb62b226f1..02bdd61094 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -29,7 +29,7 @@ const TypeScript = @import("./js_parser.zig").TypeScript; const ThreadlocalArena = @import("./mimalloc_arena.zig").Arena; const MimeType = bun.http.MimeType; const OOM = bun.OOM; - +const Loader = bun.options.Loader; /// This is the index to the automatically-generated part containing code that /// calls "__export(exports, { ... getters ... })". This is used to generate /// getters on an exports object for ES6 export statements, and is both for @@ -7008,7 +7008,7 @@ pub const BundledAst = struct { hashbang: string = "", parts: Part.List = .{}, css: ?*bun.css.BundlerStyleSheet = null, - url_for_css: ?[]const u8 = null, + url_for_css: []const u8 = "", symbols: Symbol.List = .{}, module_scope: Scope = .{}, char_freq: CharFreq = undefined, @@ -7125,7 +7125,6 @@ pub const BundledAst = struct { .import_records = ast.import_records, .hashbang = ast.hashbang, - // .url_for_css = ast.url_for_css orelse "", .parts = ast.parts, // This list may be mutated later, so we should store the capacity .symbols = ast.symbols, @@ -7173,12 +7172,12 @@ pub const BundledAst = struct { pub fn addUrlForCss( this: *BundledAst, allocator: std.mem.Allocator, - css_enabled: bool, + experimental: Loader.Experimental, source: *const logger.Source, mime_type_: ?[]const u8, unique_key: ?[]const u8, ) void { - if (css_enabled) { + if (experimental.css) { const mime_type = if (mime_type_) |m| m else MimeType.byExtension(bun.strings.trimLeadingChar(std.fs.path.extension(source.path.text), '.')).value; const contents = source.contents; // TODO: make this configurable diff --git a/src/options.zig b/src/options.zig index 1b1a674686..63e6582d1a 100644 --- a/src/options.zig +++ b/src/options.zig @@ -644,6 +644,14 @@ pub const Loader = enum(u8) { bunsh, sqlite, sqlite_embedded, + html, + + pub fn disableHTML(this: Loader) Loader { + return switch (this) { + .html => .file, + else => this, + }; + } pub inline fn isSQLite(this: Loader) bool { return switch (this) { @@ -652,28 +660,22 @@ pub const Loader = enum(u8) { }; } - pub fn shouldCopyForBundling(this: Loader, experimental_css: bool) bool { - if (experimental_css) { - return switch (this) { - .file, - .napi, - .sqlite, - .sqlite_embedded, - // TODO: loader for reading bytes and creating module or instance - .wasm, - => true, - else => false, - }; - } + pub const Experimental = struct { + css: bool = bun.FeatureFlags.breaking_changes_1_2, + html: bool = bun.FeatureFlags.breaking_changes_1_2, + }; + + pub fn shouldCopyForBundling(this: Loader, experimental: Experimental) bool { return switch (this) { .file, - .css, .napi, .sqlite, .sqlite_embedded, // TODO: loader for reading bytes and creating module or instance .wasm, => true, + .css => !experimental.css, + .html => !experimental.html, else => false, }; } @@ -684,6 +686,7 @@ pub const Loader = enum(u8) { .css => bun.http.MimeType.css, .toml, .json => bun.http.MimeType.json, .wasm => bun.http.MimeType.wasm, + .html => bun.http.MimeType.html, else => bun.http.MimeType.other, }; } @@ -719,6 +722,7 @@ pub const Loader = enum(u8) { map.set(.napi, "input.node"); map.set(.text, "input.txt"); map.set(.bunsh, "input.sh"); + map.set(.html, "input.html"); break :brk map; }; @@ -764,6 +768,7 @@ pub const Loader = enum(u8) { .{ "sh", .bunsh }, .{ "sqlite", .sqlite }, .{ "sqlite_embedded", .sqlite_embedded }, + .{ "html", .html }, }); pub const api_names = bun.ComptimeStringMap(Api.Loader, .{ @@ -787,6 +792,7 @@ pub const Loader = enum(u8) { .{ "text", .text }, .{ "sh", .file }, .{ "sqlite", .sqlite }, + .{ "html", .html }, }); pub fn fromString(slice_: string) ?Loader { @@ -812,6 +818,7 @@ pub const Loader = enum(u8) { .ts => .ts, .tsx => .tsx, .css => .css, + .html => .html, .file, .bunsh => .file, .json => .json, .toml => .toml, @@ -840,6 +847,7 @@ pub const Loader = enum(u8) { .base64 => .base64, .dataurl => .dataurl, .text => .text, + .html => .html, .sqlite => .sqlite, _ => .file, }; @@ -899,6 +907,7 @@ const default_loaders_posix = .{ .{ ".node", .napi }, .{ ".txt", .text }, .{ ".text", .text }, + .{ ".html", .html }, }; const default_loaders_win32 = default_loaders_posix ++ .{ .{ ".sh", .bunsh }, @@ -1289,6 +1298,11 @@ const default_loader_ext = [_]string{ ".txt", ".text", }; +// Only set it for browsers by default. +const default_loader_ext_browser = [_]string{ + ".html", +}; + const node_modules_default_loader_ext_bun = [_]string{".node"}; const node_modules_default_loader_ext = [_]string{ ".jsx", @@ -1305,6 +1319,7 @@ const node_modules_default_loader_ext = [_]string{ ".cts", ".wasm", ".text", + ".html", }; pub const ResolveFileExtensions = struct { @@ -1359,6 +1374,12 @@ pub fn loadersFromTransformOptions(allocator: std.mem.Allocator, _loaders: ?Api. } } + if (target == .browser) { + inline for (default_loader_ext_browser) |ext| { + _ = try loaders.getOrPutValue(ext, defaultLoaders.get(ext).?); + } + } + return loaders; } @@ -1513,7 +1534,7 @@ pub const BundleOptions = struct { minify_identifiers: bool = false, dead_code_elimination: bool = true, - experimental_css: bool, + experimental: Loader.Experimental = .{}, css_chunking: bool, ignore_dce_annotations: bool = false, @@ -1698,7 +1719,7 @@ pub const BundleOptions = struct { .out_extensions = undefined, .env = Env.init(allocator), .transform_options = transform, - .experimental_css = false, + .experimental = .{}, .css_chunking = false, .drop = transform.drop, }; diff --git a/src/transpiler.zig b/src/transpiler.zig index fb2e8bacf5..b0078da193 100644 --- a/src/transpiler.zig +++ b/src/transpiler.zig @@ -932,7 +932,7 @@ pub const Transpiler = struct { Output.panic("TODO: dataurl, base64", .{}); // TODO }, .css => { - if (transpiler.options.experimental_css) { + if (transpiler.options.experimental.css) { const alloc = transpiler.allocator; const entry = transpiler.resolver.caches.fs.readFileWithAllocator( @@ -1038,7 +1038,7 @@ pub const Transpiler = struct { } }, - .bunsh, .sqlite_embedded, .sqlite, .wasm, .file, .napi => { + .html, .bunsh, .sqlite_embedded, .sqlite, .wasm, .file, .napi => { const hashed_name = try transpiler.linker.getHashedFilename(file_path, null); var pathname = try transpiler.allocator.alloc(u8, hashed_name.len + file_path.name.ext.len); bun.copy(u8, pathname, hashed_name); diff --git a/test/bundler/bun-build-api.test.ts b/test/bundler/bun-build-api.test.ts index 3ea2c0416a..195f8fbe1d 100644 --- a/test/bundler/bun-build-api.test.ts +++ b/test/bundler/bun-build-api.test.ts @@ -567,4 +567,78 @@ describe("Bun.build", () => { expect(await bundle.outputs[0].text()).toBe("var o=/*@__PURE__*/console.log(1);export{o as OUT};\n"); }); + + test("you can write onLoad and onResolve plugins using the 'html' loader, and it includes script and link tags as bundled entrypoints", async () => { + const fixture = tempDirWithFiles("build-html-plugins", { + "index.html": ` + + + + + + + + `, + "style.css": ".foo { color: red; }", + + // Check we actually do bundle the script + "script.js": "console.log(1 + 2)", + }); + + let onLoadCalled = false; + let onResolveCalled = false; + + const build = await Bun.build({ + entrypoints: [join(fixture, "index.html")], + html: true, + experimentalCss: true, + minify: { + syntax: true, + }, + plugins: [ + { + name: "test-plugin", + setup(build) { + build.onLoad({ filter: /\.html$/ }, async args => { + onLoadCalled = true; + const contents = await Bun.file(args.path).text(); + return { + contents: contents.replace("", ""), + loader: "html", + }; + }); + + build.onResolve({ filter: /\.(js|css)$/ }, args => { + onResolveCalled = true; + return { + path: join(fixture, args.path), + namespace: "file", + }; + }); + }, + }, + ], + }); + + expect(build.success).toBe(true); + expect(onLoadCalled).toBe(true); + expect(onResolveCalled).toBe(true); + + // Should have 3 outputs - HTML, JS and CSS + expect(build.outputs).toHaveLength(3); + + // Verify we have one of each type + const types = build.outputs.map(o => o.type); + expect(types).toContain("text/html;charset=utf-8"); + expect(types).toContain("text/javascript;charset=utf-8"); + expect(types).toContain("text/css;charset=utf-8"); + + // Verify the JS output contains the __dirname + const js = build.outputs.find(o => o.type === "text/javascript;charset=utf-8"); + expect(await js?.text()).toContain("console.log(3)"); + + // Verify our plugin modified the HTML + const html = build.outputs.find(o => o.type === "text/html;charset=utf-8"); + expect(await html?.text()).toContain(""); + }); }); diff --git a/test/bundler/bundler_html.test.ts b/test/bundler/bundler_html.test.ts new file mode 100644 index 0000000000..29ac02c90f --- /dev/null +++ b/test/bundler/bundler_html.test.ts @@ -0,0 +1,724 @@ +import { describe, expect } from "bun:test"; +import { itBundled } from "./expectBundled"; + +describe("bundler", () => { + // Basic test for bundling HTML with JS and CSS + itBundled("html/basic", { + outdir: "out/", + files: { + "/index.html": ` + + + + + + + +

Hello World

+ +`, + "/styles.css": "body { background-color: red; }", + "/script.js": "console.log('Hello World')", + }, + experimentalHtml: true, + experimentalCss: true, + entryPoints: ["/index.html"], + + onAfterBundle(api) { + // Check that output HTML references hashed filenames + api.expectFile("out/index.html").not.toContain("styles.css"); + api.expectFile("out/index.html").not.toContain("script.js"); + api.expectFile("out/index.html").toMatch(/href=".*\.css"/); + api.expectFile("out/index.html").toMatch(/src=".*\.js"/); + }, + }); + + // Test multiple script and style bundling + itBundled("html/multiple-assets", { + outdir: "out/", + files: { + "/index.html": ` + + + + + + + + + +

Multiple Assets

+ +`, + "/style1.css": "body { color: blue; }", + "/style2.css": "h1 { color: red; }", + "/script1.js": "console.log('First script')", + "/script2.js": "console.log('Second script')", + }, + experimentalHtml: true, + experimentalCss: true, + entryPoints: ["/index.html"], + onAfterBundle(api) { + // Should combine CSS files into one + api.expectFile("out/index.html").toMatch(/href=".*\.css"/); + api.expectFile("out/index.html").not.toMatch(/href=".*style1\.css"/); + api.expectFile("out/index.html").not.toMatch(/href=".*style2\.css"/); + + // Should combine JS files into one + api.expectFile("out/index.html").toMatch(/src=".*\.js"/); + api.expectFile("out/index.html").not.toMatch(/src=".*script1\.js"/); + api.expectFile("out/index.html").not.toMatch(/src=".*script2\.js"/); + }, + }); + + // Test image hashing + itBundled("html/image-hashing", { + outdir: "out/", + files: { + "/index.html": ` + + + + Local image + External image + +`, + "/image.jpg": "fake image content", + }, + experimentalHtml: true, + experimentalCss: true, + entryPoints: ["/index.html"], + onAfterBundle(api) { + // Local image should be hashed + api.expectFile("out/index.html").not.toContain("./image.jpg"); + api.expectFile("out/index.html").toMatch(/src=".*-[a-zA-Z0-9]+\.jpg"/); + + // External image URL should remain unchanged + api.expectFile("out/index.html").toContain("https://example.com/image.jpg"); + }, + }); + + // Test external assets preservation + itBundled("html/external-assets", { + outdir: "out/", + files: { + "/index.html": ` + + + + + + + +

External Assets

+ +`, + }, + experimentalHtml: true, + experimentalCss: true, + entryPoints: ["/index.html"], + onAfterBundle(api) { + // External URLs should remain unchanged + api.expectFile("out/index.html").toContain("https://cdn.example.com/style.css"); + api.expectFile("out/index.html").toContain("https://cdn.example.com/script.js"); + }, + }); + + // Test mixed local and external assets + itBundled("html/mixed-assets", { + outdir: "out/", + files: { + "/index.html": ` + + + + + + + + + +

Mixed Assets

+ + + +`, + "/local.css": "body { margin: 0; }", + "/local.js": "console.log('Local script')", + "/local.jpg": "fake image content", + }, + experimentalHtml: true, + experimentalCss: true, + entryPoints: ["/index.html"], + onAfterBundle(api) { + // Local assets should be hashed + api.expectFile("out/index.html").not.toContain("local.css"); + api.expectFile("out/index.html").not.toContain("local.js"); + api.expectFile("out/index.html").not.toContain("local.jpg"); + + // External assets should remain unchanged + api.expectFile("out/index.html").toContain("https://cdn.example.com/style.css"); + api.expectFile("out/index.html").toContain("https://cdn.example.com/script.js"); + api.expectFile("out/index.html").toContain("https://cdn.example.com/image.jpg"); + }, + }); + + // Test JS imports + itBundled("html/js-imports", { + outdir: "out/", + files: { + "/in/index.html": ` + + + + + + +

JS Imports

+ +`, + "/in/main.js": ` +import { greeting } from './utils/strings.js'; +import { formatDate } from './utils/date.js'; +console.log(greeting('World')); +console.log(formatDate(new Date()));`, + "/in/utils/strings.js": ` +export const greeting = (name) => \`Hello, \${name}!\`;`, + "/in/utils/date.js": ` +import { padZero } from './numbers.js'; +export const formatDate = (date) => \`\${date.getFullYear()}-\${padZero(date.getMonth() + 1)}-\${padZero(date.getDate())}\`;`, + "/in/utils/numbers.js": ` +export const padZero = (num) => String(num).padStart(2, '0');`, + }, + experimentalHtml: true, + experimentalCss: true, + entryPoints: ["/in/index.html"], + onAfterBundle(api) { + // All JS should be bundled into one file + api.expectFile("out/index.html").toMatch(/src=".*\.js"/); + api.expectFile("out/index.html").not.toContain("main.js"); + + const htmlContent = api.readFile("out/index.html"); + // Check that the bundle contains all the imported code + const jsMatch = htmlContent.match(/src="(.*\.js)"/); + const jsBundle = api.readFile("out/" + jsMatch![1]); + expect(jsBundle).toContain("Hello"); + expect(jsBundle).toContain("padZero"); + expect(jsBundle).toContain("formatDate"); + }, + }); + + // Test CSS imports + itBundled("html/css-imports", { + outdir: "out/", + files: { + "/in/index.html": ` + + + + + + +

CSS Imports

+ +`, + "/in/styles/main.css": ` +@import './variables.css'; +@import './typography.css'; +body { + background-color: var(--background-color); +}`, + "/in/styles/variables.css": ` +:root { + --background-color: #f0f0f0; + --text-color: #333; + --heading-color: #000; +}`, + "/in/styles/typography.css": ` +@import './fonts.css'; +h1 { + color: var(--heading-color); + font-family: var(--heading-font); +}`, + "/in/styles/fonts.css": ` +:root { + --heading-font: 'Arial', sans-serif; + --body-font: 'Helvetica', sans-serif; +}`, + }, + experimentalHtml: true, + experimentalCss: true, + entryPoints: ["/in/index.html"], + onAfterBundle(api) { + // All CSS should be bundled into one file + api.expectFile("out/index.html").toMatch(/href=".*\.css"/); + api.expectFile("out/index.html").not.toContain("main.css"); + + // Check that the bundle contains all the imported CSS + const htmlContent = api.readFile("out/index.html"); + const cssMatch = htmlContent.match(/href="(.*?\.css)"/); + if (!cssMatch) throw new Error("Could not find CSS file reference in HTML"); + const cssBundle = api.readFile("out/" + cssMatch[1]); + expect(cssBundle).toContain("--background-color"); + expect(cssBundle).toContain("--heading-font"); + expect(cssBundle).toContain("font-family"); + }, + }); + + // Test multiple HTML entry points + itBundled("html/multiple-entries", { + outdir: "out/", + files: { + "/in/pages/index.html": ` + + + + + + + +

Home Page

+ About + +`, + "/in/pages/about.html": ` + + + + + + + +

About Page

+ Home + +`, + "/in/styles/home.css": ` +@import './common.css'; +.home { color: blue; }`, + "/in/styles/about.css": ` +@import './common.css'; +.about { color: green; }`, + "/in/styles/common.css": ` +body { margin: 0; padding: 20px; }`, + "/in/scripts/home.js": ` +import { initNav } from './common.js'; +console.log('Home page'); +initNav();`, + "/in/scripts/about.js": ` +import { initNav } from './common.js'; +console.log('About page'); +initNav();`, + "/in/scripts/common.js": ` +export const initNav = () => console.log('Navigation initialized');`, + }, + entryPoints: ["/in/pages/index.html", "/in/pages/about.html"], + experimentalHtml: true, + experimentalCss: true, + onAfterBundle(api) { + // Check index.html + api.expectFile("out/index.html").toMatch(/href=".*\.css"/); + api.expectFile("out/index.html").toMatch(/src=".*\.js"/); + api.expectFile("out/index.html").not.toContain("home.css"); + api.expectFile("out/index.html").not.toContain("home.js"); + + // Check about.html + api.expectFile("out/about.html").toMatch(/href=".*\.css"/); + api.expectFile("out/about.html").toMatch(/src=".*\.js"/); + api.expectFile("out/about.html").not.toContain("about.css"); + api.expectFile("out/about.html").not.toContain("about.js"); + + // Verify we don't update the filenames for these + const indexHtml = api.readFile("out/index.html"); + const aboutHtml = api.readFile("out/about.html"); + expect(indexHtml).toContain('href="./about.html"'); + expect(aboutHtml).toContain('href="index.html"'); + + // Check that each page has its own bundle + const indexHtmlContent = api.readFile("out/index.html"); + const aboutHtmlContent = api.readFile("out/about.html"); + + const indexJsMatch = indexHtmlContent.match(/src="(.*\.js)"/); + const aboutJsMatch = aboutHtmlContent.match(/src="(.*\.js)"/); + + const indexJs = api.readFile("out/" + indexJsMatch![1]); + const aboutJs = api.readFile("out/" + aboutJsMatch![1]); + + expect(indexJs).toContain("Home page"); + expect(aboutJs).toContain("About page"); + expect(indexJs).toContain("Navigation initialized"); + expect(aboutJs).toContain("Navigation initialized"); + + // Check that each page has its own CSS bundle + const indexCssMatch = indexHtmlContent.match(/href="(.*\.css)"/); + const aboutCssMatch = aboutHtmlContent.match(/href="(.*\.css)"/); + + const indexCss = api.readFile("out/" + indexCssMatch![1]); + const aboutCss = api.readFile("out/" + aboutCssMatch![1]); + + expect(indexCss).toContain(".home"); + expect(aboutCss).toContain(".about"); + expect(indexCss).toContain("margin: 0"); + expect(aboutCss).toContain("margin: 0"); + }, + }); + + // Test multiple HTML entries with shared chunks + itBundled("html/shared-chunks", { + outdir: "out/", + // Makes this test easier to write + minifyWhitespace: true, + + files: { + "/in/pages/page1.html": ` + + + + + + + +

Page 1

+ +`, + "/in/pages/page2.html": ` + + + + + + + +

Page 2

+ +`, + "/in/styles/page1.css": ` +@import './shared.css'; +.page1 { font-size: 20px; }`, + "/in/styles/page2.css": ` +@import './shared.css'; +.page2 { font-size: 18px; }`, + "/in/styles/shared.css": ` +@import './reset.css'; +.shared { color: blue; }`, + "/in/styles/reset.css": ` +* { box-sizing: border-box; }`, + "/in/scripts/page1.js": ` +import { sharedUtil } from './shared.js'; +import { largeModule } from './large-module.js'; +console.log('Page 1'); +sharedUtil();`, + "/in/scripts/page2.js": ` +import { sharedUtil } from './shared.js'; +import { largeModule } from './large-module.js'; +console.log('Page 2'); +sharedUtil();`, + "/in/scripts/shared.js": ` +export const sharedUtil = () => console.log('Shared utility');`, + "/in/scripts/large-module.js": ` +export const largeModule = { + // Simulate a large shared module + bigData: new Array(1000).fill('data'), + methods: { /* ... */ } +};`, + }, + entryPoints: ["/in/pages/page1.html", "/in/pages/page2.html"], + experimentalHtml: true, + experimentalCss: true, + splitting: true, + onAfterBundle(api) { + // Check both pages + for (const page of ["page1", "page2"]) { + api.expectFile(`out/${page}.html`).toMatch(/href=".*\.css"/); + api.expectFile(`out/${page}.html`).toMatch(/src=".*\.js"/); + api.expectFile(`out/${page}.html`).not.toContain(`${page}.css`); + api.expectFile(`out/${page}.html`).not.toContain(`${page}.js`); + } + + // Verify that shared code exists in both bundles + const page1Html = api.readFile("out/page1.html"); + const page2Html = api.readFile("out/page2.html"); + + const page1JsPath = page1Html.match(/src="(.*\.js)"/)?.[1]; + const page2JsPath = page2Html.match(/src="(.*\.js)"/)?.[1]; + + expect(page1JsPath).toBeDefined(); + expect(page2JsPath).toBeDefined(); + + const page1Js = api.readFile("out/" + page1JsPath!); + const page2Js = api.readFile("out/" + page2JsPath!); + + // Check we imported the shared module + expect(page2Js).toContain("import{sharedUtil}"); + expect(page1Js).toContain("import{sharedUtil}"); + + // Check CSS bundles + const page1CssPath = page1Html.match(/href="(.*\.css)"/)?.[1]; + const page2CssPath = page2Html.match(/href="(.*\.css)"/)?.[1]; + + expect(page1CssPath).toBeDefined(); + expect(page2CssPath).toBeDefined(); + + const page1Css = api.readFile("out/" + page1CssPath!); + const page2Css = api.readFile("out/" + page2CssPath!); + expect(page1Css).toContain("box-sizing:border-box"); + expect(page2Css).toContain("box-sizing:border-box"); + expect(page1Css).toContain(".shared"); + expect(page2Css).toContain(".shared"); + }, + }); + + // Test JS importing HTML + itBundled("html/js-importing-html", { + outdir: "out/", + files: { + "/in/entry.js": ` +import htmlContent from './template.html'; +console.log('Loaded HTML:', htmlContent);`, + + "/in/template.html": ` + + + + HTML Template + + +

HTML Template

+ +`, + }, + experimentalHtml: true, + + // This becomes: + // + // - out/entry.js + // - out/template-hash.html + // + // Like a regular asset. + entryPoints: ["/in/entry.js"], + onAfterBundle(api) { + const entryBundle = api.readFile("out/entry.js"); + // Check taht we dind't bundle the HTML file + expect(entryBundle).toMatch(/\.\/template-.*\.html/); + }, + }); + + itBundled("html/js-importing-html-and-entry-point-side-effect-import", { + outdir: "out/", + target: "browser", + files: { + "/in/2nd.js": ` +console.log('2nd');`, + "/in/entry.js": ` +import './template.html'; +console.log('Loaded HTML!');`, + + "/in/template.html": ` + + + + HTML Template + + +

HTML Template

+ + + +`, + }, + experimentalHtml: true, + // This becomes: + // - ./template.html + // - ./template-*.js + // - ./entry.js + entryPointsRaw: ["in/template.html", "in/entry.js"], + onAfterBundle(api) { + const templateBundle = api.readFile("out/template.html"); + expect(templateBundle).toContain("HTML Template"); + + // Get the entry.js file from looking at + + +`, + }, + experimentalHtml: true, + entryPointsRaw: ["in/template.html", "in/entry.js"], + bundleErrors: { + "/in/entry.js": ['No matching export in "in/template.html" for import "default"'], + }, + onAfterBundle(api) { + const templateBundle = api.readFile("out/template.html"); + expect(templateBundle).toContain("HTML Template"); + + // Get the entry.js file from looking at + + +`, + }, + experimentalHtml: false, + entryPointsRaw: ["in/template.html", "in/entry.js"], + onAfterBundle(api) { + const entryBundle = api.readFile("out/entry.js"); + + // Verify we DID bundle the HTML file + expect(entryBundle).toMatch(/\.\/template-.*\.html/); + const filename = entryBundle.match(/\.\/(template-.*\.html)/)?.[1]; + expect(filename).toBeDefined(); + const templateBundle = api.readFile("out/" + filename!); + expect(templateBundle).toContain("HTML Template"); + }, + }); + + // Test circular dependencies between JS and HTML + itBundled("html/circular-js-html", { + outdir: "out/", + files: { + "/in/main.js": ` +import page from './page.html'; +console.log('Main JS loaded page:', page);`, + + "/in/page.html": ` + + + + + + +
Circular Import Test
+ +`, + }, + experimentalHtml: true, + entryPoints: ["/in/main.js"], + onAfterBundle(api) { + const bundle = api.readFile("out/main.js"); + + // Check that it is a hashed file + expect(bundle).toMatch(/\.\/page-.*\.html/); + }, + }); + + // Test HTML with only CSS (no JavaScript) + itBundled("html/css-only", { + outdir: "out/", + files: { + "/in/page.html": ` + + + + + + + +
+

Styled Page

+

This page only has CSS styling.

+
+ +`, + "/in/styles-imported.css": ` +* { + box-sizing: border-box; +} +`, + "/in/styles.css": ` +@import "./styles-imported.css"; +.container { + max-width: 800px; + margin: 0 auto; + padding: 20px; +} +.title { + color: navy; +}`, + "/in/theme.css": ` +@import "./styles-imported.css"; +.content { + line-height: 1.6; + color: #333; +} +body { + background-color: #f5f5f5; +}`, + }, + experimentalHtml: true, + experimentalCss: true, + entryPoints: ["/in/page.html"], + onAfterBundle(api) { + const htmlBundle = api.readFile("out/page.html"); + + // Check that CSS is properly referenced and hashed + expect(htmlBundle).toMatch(/href=".*\.css"/); + expect(htmlBundle).not.toContain("styles.css"); + expect(htmlBundle).not.toContain("theme.css"); + + // Get the CSS bundle path + const cssPath = htmlBundle.match(/href="(.*\.css)"/)?.[1]; + expect(cssPath).toBeDefined(); + + // Check the CSS bundle contents + const cssBundle = api.readFile("out/" + cssPath!); + expect(cssBundle).toContain(".container"); + expect(cssBundle).toContain(".title"); + expect(cssBundle).toContain(".content"); + expect(cssBundle).toContain("background-color"); + expect(cssBundle).toContain("box-sizing: border-box"); + }, + }); +}); diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index 68af41ca9e..a96a3aed1c 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -194,6 +194,7 @@ export interface BundlerTestInput { minifyIdentifiers?: boolean; minifySyntax?: boolean; experimentalCss?: boolean; + experimentalHtml?: boolean; targetFromAPI?: "TargetWasConfigured"; minifyWhitespace?: boolean; splitting?: boolean; @@ -448,6 +449,7 @@ function expectBundled( minifySyntax, minifyWhitespace, experimentalCss, + experimentalHtml, onAfterBundle, outdir, dotenv, @@ -695,6 +697,7 @@ function expectBundled( minifyWhitespace && `--minify-whitespace`, drop?.length && drop.map(x => ["--drop=" + x]), experimentalCss && "--experimental-css", + experimentalHtml && "--experimental-html", globalName && `--global-name=${globalName}`, jsx.runtime && ["--jsx-runtime", jsx.runtime], jsx.factory && ["--jsx-factory", jsx.factory], @@ -1033,6 +1036,7 @@ function expectBundled( emitDCEAnnotations, ignoreDCEAnnotations, experimentalCss, + html: experimentalHtml ? true : undefined, drop, define: define ?? {}, } as BuildConfig; From 60cb505a98e63fef49f51f94ad4773dac1748930 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 12:33:11 -0800 Subject: [PATCH 090/125] Use JSObject instead of JSFunction in Bun.plugin (#15968) --- src/bun.js/bindings/BunPlugin.cpp | 26 ++++++++++++++++---------- src/bun.js/bindings/BunPlugin.h | 8 ++++---- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/bun.js/bindings/BunPlugin.cpp b/src/bun.js/bindings/BunPlugin.cpp index 8f1bb8d06e..0f56b920d9 100644 --- a/src/bun.js/bindings/BunPlugin.cpp +++ b/src/bun.js/bindings/BunPlugin.cpp @@ -1,5 +1,6 @@ #include "BunPlugin.h" +#include "JavaScriptCore/ExceptionScope.h" #include "JavaScriptCore/JSCast.h" #include "headers-handwritten.h" #include "helpers.h" @@ -57,9 +58,11 @@ static JSC::EncodedJSValue jsFunctionAppendOnLoadPluginBody(JSC::JSGlobalObject* RETURN_IF_EXCEPTION(scope, {}); JSC::RegExpObject* filter = nullptr; if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, Identifier::fromString(vm, "filter"_s))) { + RETURN_IF_EXCEPTION(scope, {}); if (filterValue.isCell() && filterValue.asCell()->inherits()) filter = jsCast(filterValue); } + RETURN_IF_EXCEPTION(scope, {}); if (!filter) { throwException(globalObject, scope, createError(globalObject, "onLoad() expects first argument to be an object with a filter RegExp"_s)); @@ -76,8 +79,8 @@ static JSC::EncodedJSValue jsFunctionAppendOnLoadPluginBody(JSC::JSGlobalObject* return {}; } } - RETURN_IF_EXCEPTION(scope, {}); } + RETURN_IF_EXCEPTION(scope, {}); auto func = callframe->uncheckedArgument(1); RETURN_IF_EXCEPTION(scope, {}); @@ -87,7 +90,7 @@ static JSC::EncodedJSValue jsFunctionAppendOnLoadPluginBody(JSC::JSGlobalObject* return {}; } - plugin.append(vm, filter->regExp(), jsCast(func), namespaceString); + plugin.append(vm, filter->regExp(), func.getObject(), namespaceString); callback(ctx, globalObject); return JSValue::encode(jsUndefined()); @@ -163,9 +166,11 @@ static JSC::EncodedJSValue jsFunctionAppendOnResolvePluginBody(JSC::JSGlobalObje RETURN_IF_EXCEPTION(scope, {}); JSC::RegExpObject* filter = nullptr; if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, Identifier::fromString(vm, "filter"_s))) { + RETURN_IF_EXCEPTION(scope, {}); if (filterValue.isCell() && filterValue.asCell()->inherits()) filter = jsCast(filterValue); } + RETURN_IF_EXCEPTION(scope, {}); if (!filter) { throwException(globalObject, scope, createError(globalObject, "onResolve() expects first argument to be an object with a filter RegExp"_s)); @@ -194,7 +199,8 @@ static JSC::EncodedJSValue jsFunctionAppendOnResolvePluginBody(JSC::JSGlobalObje return {}; } - plugin.append(vm, filter->regExp(), jsCast(func), namespaceString); + RETURN_IF_EXCEPTION(scope, {}); + plugin.append(vm, filter->regExp(), jsCast(func), namespaceString); callback(ctx, globalObject); return JSValue::encode(jsUndefined()); @@ -321,7 +327,7 @@ static inline JSC::EncodedJSValue setupBunPlugin(JSC::JSGlobalObject* globalObje JSC::MarkedArgumentBuffer args; args.append(builderObject); - JSFunction* function = jsCast(setupFunctionValue); + JSObject* function = jsCast(setupFunctionValue); JSC::CallData callData = JSC::getCallData(function); JSValue result = call(globalObject, function, callData, JSC::jsUndefined(), args); @@ -334,13 +340,13 @@ static inline JSC::EncodedJSValue setupBunPlugin(JSC::JSGlobalObject* globalObje RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined())); } -void BunPlugin::Group::append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSFunction* func) +void BunPlugin::Group::append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSObject* func) { filters.append(JSC::Strong { vm, filter }); - callbacks.append(JSC::Strong { vm, func }); + callbacks.append(JSC::Strong { vm, func }); } -void BunPlugin::Base::append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSFunction* func, String& namespaceString) +void BunPlugin::Base::append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSObject* func, String& namespaceString) { if (namespaceString.isEmpty() || namespaceString == "file"_s) { this->fileNamespace.append(vm, filter, func); @@ -354,7 +360,7 @@ void BunPlugin::Base::append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSFunction* } } -JSFunction* BunPlugin::Group::find(JSC::JSGlobalObject* globalObject, String& path) +JSC::JSObject* BunPlugin::Group::find(JSC::JSGlobalObject* globalObject, String& path) { size_t count = filters.size(); for (size_t i = 0; i < count; i++) { @@ -691,7 +697,7 @@ EncodedJSValue BunPlugin::OnLoad::run(JSC::JSGlobalObject* globalObject, BunStri auto pathString = path->toWTFString(BunString::ZeroCopy); - JSC::JSFunction* function = group.find(globalObject, pathString); + auto* function = group.find(globalObject, pathString); if (!function) { return JSValue::encode(JSC::jsUndefined()); } @@ -777,7 +783,7 @@ EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, BunS if (!filters[i].get()->match(globalObject, pathString, 0)) { continue; } - JSC::JSFunction* function = callbacks[i].get(); + auto* function = callbacks[i].get(); if (UNLIKELY(!function)) { continue; } diff --git a/src/bun.js/bindings/BunPlugin.h b/src/bun.js/bindings/BunPlugin.h index a8edf0d3aa..09562f90f5 100644 --- a/src/bun.js/bindings/BunPlugin.h +++ b/src/bun.js/bindings/BunPlugin.h @@ -25,11 +25,11 @@ public: // We want JIT! // TODO: evaluate if using JSInternalFieldImpl(2) is faster Vector> filters = {}; - Vector> callbacks = {}; + Vector> callbacks = {}; BunPluginTarget target { BunPluginTargetBun }; - void append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSFunction* func); - JSFunction* find(JSC::JSGlobalObject* globalObj, String& path); + void append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSObject* func); + JSObject* find(JSC::JSGlobalObject* globalObj, String& path); void clear() { filters.clear(); @@ -58,7 +58,7 @@ public: return nullptr; } - void append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSFunction* func, String& namespaceString); + void append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSObject* func, String& namespaceString); }; class OnLoad final : public Base { From 52a568d2b283fed25ab79340e6bb483121504323 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 24 Dec 2024 02:27:07 -0800 Subject: [PATCH 091/125] Fix flaky zlib dictionary test (#15976) --- src/bun.js/api/zlib.classes.ts | 2 +- src/bun.js/node/node_zlib_binding.zig | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/bun.js/api/zlib.classes.ts b/src/bun.js/api/zlib.classes.ts index d907e3c838..3a0b9b59b5 100644 --- a/src/bun.js/api/zlib.classes.ts +++ b/src/bun.js/api/zlib.classes.ts @@ -10,7 +10,7 @@ function generate(name: string) { estimatedSize: true, klass: {}, JSType: "0b11101110", - values: ["writeCallback", "errorCallback"], + values: ["writeCallback", "errorCallback", "dictionary"], proto: { init: { fn: "init" }, diff --git a/src/bun.js/node/node_zlib_binding.zig b/src/bun.js/node/node_zlib_binding.zig index d892844e4a..cd233554c7 100644 --- a/src/bun.js/node/node_zlib_binding.zig +++ b/src/bun.js/node/node_zlib_binding.zig @@ -358,6 +358,7 @@ pub const SNativeZlib = struct { pub fn init(this: *SNativeZlib, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { const arguments = callframe.argumentsUndef(7).slice(); + const this_value = callframe.this(); if (arguments.len != 7) { return globalThis.ERR_MISSING_ARGS("init(windowBits, level, memLevel, strategy, writeResult, writeCallback, dictionary)", .{}).throw(); @@ -373,7 +374,12 @@ pub const SNativeZlib = struct { const dictionary = if (arguments[6].isUndefined()) null else arguments[6].asArrayBuffer(globalThis).?.byteSlice(); this.write_result = writeResult; - SNativeZlib.writeCallbackSetCached(callframe.this(), globalThis, writeCallback); + SNativeZlib.writeCallbackSetCached(this_value, globalThis, writeCallback); + + // Keep the dictionary alive by keeping a reference to it in the JS object. + if (dictionary != null) { + SNativeZlib.dictionarySetCached(this_value, globalThis, arguments[6]); + } this.stream.init(level, windowBits, memLevel, strategy, dictionary); @@ -723,7 +729,7 @@ pub const SNativeBrotli = struct { }; } - pub fn init(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { + pub fn init(this: *SNativeBrotli, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { const arguments = callframe.argumentsUndef(3).slice(); const this_value = callframe.this(); if (arguments.len != 3) { From 608101c9751c12d5d1e361c6304584f69e20b9b9 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 24 Dec 2024 04:20:24 -0800 Subject: [PATCH 092/125] Add zlib microbenchmark need to improve this --- bench/snippets/zlib.mjs | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 bench/snippets/zlib.mjs diff --git a/bench/snippets/zlib.mjs b/bench/snippets/zlib.mjs new file mode 100644 index 0000000000..8bfc87e308 --- /dev/null +++ b/bench/snippets/zlib.mjs @@ -0,0 +1,62 @@ +import { bench, run } from "../runner.mjs"; +import zlib from "node:zlib"; +import { promisify } from "node:util"; + +const deflate = promisify(zlib.deflate); +const inflate = promisify(zlib.inflate); + +const short = "Hello World!"; +const long = "Hello World!".repeat(1024); +const veryLong = "Hello World!".repeat(10240); + +// Pre-compress some data for decompression tests +const shortBuf = Buffer.from(short); +const longBuf = Buffer.from(long); +const veryLongBuf = Buffer.from(veryLong); + +let [shortCompressed, longCompressed, veryLongCompressed] = await Promise.all([ + deflate(shortBuf, { level: 6 }), + deflate(longBuf, { level: 6 }), + deflate(veryLongBuf, { level: 6 }), +]); + +const format = new Intl.NumberFormat("en-US", { notation: "compact", unit: "byte" }); +// Compression tests at different levels +bench(`deflate ${format.format(short.length)}B (level 1)`, async () => { + await deflate(shortBuf, { level: 1 }); +}); + +bench(`deflate ${format.format(short.length)} (level 6)`, async () => { + await deflate(shortBuf, { level: 6 }); +}); + +bench(`deflate ${format.format(long.length)} (level 1)`, async () => { + await deflate(longBuf, { level: 1 }); +}); + +bench(`deflate ${format.format(long.length)} (level 6)`, async () => { + await deflate(longBuf, { level: 6 }); +}); + +bench(`deflate ${format.format(veryLong.length)} (level 1)`, async () => { + await deflate(veryLongBuf, { level: 1 }); +}); + +bench(`deflate ${format.format(veryLong.length)} (level 6)`, async () => { + await deflate(veryLongBuf, { level: 6 }); +}); + +// Decompression tests +bench(`inflate ${format.format(short.length)}`, async () => { + await inflate(shortCompressed); +}); + +bench(`inflate ${format.format(long.length)}`, async () => { + await inflate(longCompressed); +}); + +bench(`inflate ${format.format(veryLong.length)}`, async () => { + await inflate(veryLongCompressed); +}); + +await run(); From 7317c7b4a2e8579755b4c31baa79f1969e1931f4 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 25 Dec 2024 18:04:46 -0800 Subject: [PATCH 093/125] Compress completions list to make `zig build` a little faster (#15992) --- misctools/generate-add-completions.ts | 231 ++++++++++++++++++++++++++ src/cli.zig | 4 +- src/cli/add_completions.txt | 2 + src/cli/add_completions.zig | 121 ++++++++------ 4 files changed, 303 insertions(+), 55 deletions(-) create mode 100644 misctools/generate-add-completions.ts diff --git a/misctools/generate-add-completions.ts b/misctools/generate-add-completions.ts new file mode 100644 index 0000000000..8605cae027 --- /dev/null +++ b/misctools/generate-add-completions.ts @@ -0,0 +1,231 @@ +import * as fs from "fs"; +import path from "path"; +import { execSync } from "child_process"; + +interface LetterGroup { + offset: number; + length: number; + packages: string[]; +} + +// Read and parse input file +const content = fs.readFileSync(path.join(__dirname, "..", "src", "cli", "add_completions.txt"), "utf8"); +const packages = content + .split("\n") + .map(line => line.trim()) + .filter(line => line.length > 0) + .sort(); + +// Group packages by first letter +const letterGroups = new Map(); +let currentOffset = 0; +let maxListSize = 0; + +for (const pkg of packages) { + if (pkg.length === 0) continue; + const firstLetter = pkg[0].toLowerCase(); + if (!letterGroups.has(firstLetter)) { + letterGroups.set(firstLetter, { + offset: currentOffset, + length: 0, + packages: [], + }); + } + const group = letterGroups.get(firstLetter)!; + group.packages.push(pkg); + group.length++; + maxListSize = Math.max(maxListSize, group.length); +} + +// Helper to ensure temp dir exists +const tmpDir = path.join(__dirname, "tmp"); +if (!fs.existsSync(tmpDir)) { + fs.mkdirSync(tmpDir); +} + +// Create a single buffer with all package data +const dataChunks: Buffer[] = []; +let totalUncompressed = 0; + +// Store total package count first +const totalCountBuf = Buffer.alloc(4); +totalCountBuf.writeUInt32LE(packages.length, 0); +dataChunks.push(totalCountBuf); +totalUncompressed += 4; + +// Then all packages with length prefixes +for (const pkg of packages) { + const lenBuf = Buffer.alloc(2); + lenBuf.writeUInt16LE(pkg.length, 0); + dataChunks.push(lenBuf); + dataChunks.push(Buffer.from(pkg, "utf8")); + totalUncompressed += 2 + pkg.length; +} + +const uncompressedData = Buffer.concat(dataChunks); + +// Write to temp file and compress with zstd +const uncompressedPath = path.join(tmpDir, "packages.bin"); +const compressedPath = path.join(tmpDir, "packages.bin.zst"); + +fs.writeFileSync(uncompressedPath, uncompressedData); +execSync(`zstd -1 --rm -f "${uncompressedPath}" -o "${compressedPath}"`); + +// Read back compressed data +const compressedData = fs.readFileSync(compressedPath); +fs.unlinkSync(compressedPath); + +// Calculate compression ratio +const totalCompressed = compressedData.length; +const ratio = ((totalCompressed / totalUncompressed) * 100).toFixed(1); + +console.log("\nCompression statistics:"); +console.log(`Uncompressed size: ${totalUncompressed} bytes`); +console.log(`Compressed size: ${totalCompressed} bytes`); +console.log(`Compression ratio: ${ratio}%`); + +// Generate Zig code +const chunks: string[] = []; + +// Header with comments and imports +chunks.push(`// Auto-generated file. Do not edit. +// To regenerate this file, run: +// +// bun misctools/generate-add-completions.ts +// +// If you update add_completions.txt, then you should run this script again. +// +// This used to be a comptime block, but it made the build too slow. +// Compressing the completions list saves about 100 KB of binary size. +const std = @import("std"); +const bun = @import("root").bun; +const zstd = bun.zstd; +const Environment = bun.Environment; + +pub const FirstLetter = enum(u8) { + a = 'a', + b = 'b', + c = 'c', + d = 'd', + e = 'e', + f = 'f', + g = 'g', + h = 'h', + i = 'i', + j = 'j', + k = 'k', + l = 'l', + m = 'm', + n = 'n', + o = 'o', + p = 'p', + q = 'q', + r = 'r', + s = 's', + t = 't', + u = 'u', + v = 'v', + w = 'w', + x = 'x', + y = 'y', + z = 'z', +};`); + +// Add the compressed data +chunks.push(`const compressed_data = [_]u8{${[...compressedData].join(",")}};`); + +// Add uncompressed size constant +chunks.push(`const uncompressed_size: usize = ${totalUncompressed};`); + +// Generate index entries +const indexEntries: string[] = []; +let offset = 0; +for (const letter of "abcdefghijklmnopqrstuvwxyz") { + const group = letterGroups.get(letter); + if (group) { + indexEntries.push(` .${letter} = .{ .offset = ${offset}, .length = ${group.length} }`); + offset += group.length; + } else { + indexEntries.push(` .${letter} = .{ .offset = ${offset}, .length = 0 }`); + } +} + +// Generate index type and instance +chunks.push(`pub const IndexEntry = struct { + offset: usize, + length: usize, +}; + +pub const Index = std.EnumArray(FirstLetter, IndexEntry); + +pub const index = Index.init(.{ +${indexEntries.join(",\n")} + });`); + +// Generate the decompression and access function +chunks.push(`var decompressed_data: ?[]u8 = null; +var packages_list: ?[][]const u8 = null; + +pub fn init(allocator: std.mem.Allocator) !void { + // Decompress data + var data = try allocator.alloc(u8, uncompressed_size); + errdefer allocator.free(data); + + const result = zstd.decompress(data, &compressed_data); + decompressed_data = data[0..result.success]; + + // Parse package list + const total_count = std.mem.readInt(u32, data[0..4], .little); + var packages = try allocator.alloc([]const u8, total_count); + errdefer allocator.free(packages); + + var pos: usize = 4; + var i: usize = 0; + while (i < total_count) : (i += 1) { + const len = std.mem.readInt(u16, data[pos..][0..2], .little); + pos += 2; + packages[i] = data[pos..pos + len]; + pos += len; + } + + packages_list = packages; +} + +pub fn deinit(allocator: std.mem.Allocator) void { + if (packages_list) |pkgs| { + allocator.free(pkgs); + packages_list = null; + } + + if (decompressed_data) |data| { + allocator.free(data); + decompressed_data = null; + } +} + +pub fn getPackages(letter: FirstLetter) []const []const u8 { + const entry = index.get(letter); + if (entry.length == 0) return &[_][]const u8{}; + + return packages_list.?[entry.offset..entry.offset + entry.length]; +}`); + +// Add biggest_list constant +chunks.push(`pub const biggest_list: usize = ${maxListSize};`); + +// Write the output +let zigCode = chunks.join("\n\n"); + +zigCode = execSync("zig fmt --stdin", { + input: zigCode, + encoding: "utf8", +}).toString(); + +fs.writeFileSync(path.join(__dirname, "..", "src", "cli", "add_completions.zig"), zigCode); + +// Clean up temp dir +try { + fs.rmdirSync(tmpDir); +} catch {} + +console.log(`\nGenerated Zig completions for ${packages.length} packages`); diff --git a/src/cli.zig b/src/cli.zig index 15eebedb3d..54037e2965 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -1941,7 +1941,6 @@ pub const Command = struct { completions = try RunCommand.completions(ctx, null, &reject_list, .script_and_descriptions); } else if (strings.eqlComptime(filter[0], "a")) { const FirstLetter = AddCompletions.FirstLetter; - const index = AddCompletions.index; outer: { if (filter.len > 1 and filter[1].len > 0) { @@ -1974,7 +1973,8 @@ pub const Command = struct { 'z' => FirstLetter.z, else => break :outer, }; - const results = index.get(first_letter); + AddCompletions.init(bun.default_allocator) catch bun.outOfMemory(); + const results = AddCompletions.getPackages(first_letter); var prefilled_i: usize = 0; for (results) |cur| { diff --git a/src/cli/add_completions.txt b/src/cli/add_completions.txt index 7f2670cf7f..4f7de89059 100644 --- a/src/cli/add_completions.txt +++ b/src/cli/add_completions.txt @@ -2218,6 +2218,7 @@ elm-hot elm-hot-webpack-loader elm-test elm-webpack-loader +elsysia email-validator emailjs-base64 emailjs-imap-client @@ -3700,6 +3701,7 @@ homebridge-config-ui-x homedir homedir-polyfill honeybadger-js +hono hook-std hookable hooks diff --git a/src/cli/add_completions.zig b/src/cli/add_completions.zig index b96f1c1e81..a07c3a8b5b 100644 --- a/src/cli/add_completions.zig +++ b/src/cli/add_completions.zig @@ -1,6 +1,15 @@ -pub const add_completions: []const u8 = @embedFile("add_completions.txt"); +// Auto-generated file. Do not edit. +// To regenerate this file, run: +// +// bun misctools/generate-add-completions.ts +// +// If you update add_completions.txt, then you should run this script again. +// +// This used to be a comptime block, but it made the build too slow. const std = @import("std"); -const Environment = @import("../env.zig"); +const bun = @import("root").bun; +const zstd = bun.zstd; +const Environment = bun.Environment; pub const FirstLetter = enum(u8) { a = 'a', @@ -31,58 +40,64 @@ pub const FirstLetter = enum(u8) { z = 'z', }; -pub const Index = std.EnumArray(FirstLetter, []const []const u8); -pub const index: Index = if (Environment.isDebug) Index.initFill(&.{"OOMWorkAround"}) else brk: { - var array: Index = Index.initFill(&[_][]const u8{}); +const compressed_data = [_]u8{ 40, 181, 47, 253, 164, 157, 121, 2, 0, 156, 101, 6, 158, 128, 75, 130, 29, 50, 176, 110, 136, 168, 13, 197, 255, 138, 8, 111, 46, 215, 144, 108, 221, 73, 168, 182, 179, 179, 179, 179, 179, 179, 51, 237, 133, 67, 129, 22, 40, 149, 155, 13, 77, 238, 238, 175, 34, 93, 183, 136, 45, 12, 248, 199, 52, 72, 79, 1, 55, 29, 153, 29, 167, 29, 235, 37, 92, 124, 219, 151, 239, 224, 193, 181, 73, 119, 101, 17, 191, 237, 69, 28, 40, 90, 23, 246, 210, 75, 200, 80, 249, 38, 68, 112, 232, 47, 107, 117, 80, 218, 229, 37, 108, 104, 236, 17, 254, 137, 39, 108, 176, 212, 110, 10, 196, 195, 108, 211, 246, 97, 118, 226, 9, 27, 38, 158, 208, 49, 241, 132, 10, 152, 126, 158, 112, 225, 61, 161, 130, 79, 135, 226, 158, 112, 225, 158, 176, 193, 216, 61, 225, 2, 187, 39, 84, 240, 134, 111, 218, 233, 144, 178, 116, 7, 148, 108, 39, 125, 178, 111, 202, 94, 211, 137, 94, 27, 180, 246, 223, 2, 14, 11, 126, 189, 100, 84, 49, 80, 154, 90, 78, 84, 54, 224, 150, 205, 61, 225, 162, 45, 115, 127, 45, 35, 238, 9, 25, 223, 152, 113, 79, 216, 144, 176, 177, 48, 78, 238, 9, 23, 205, 139, 147, 123, 122, 169, 139, 123, 194, 7, 4, 247, 132, 142, 79, 135, 178, 214, 50, 79, 99, 135, 188, 35, 222, 202, 73, 175, 126, 173, 191, 237, 233, 100, 63, 27, 106, 204, 180, 116, 190, 217, 241, 214, 138, 109, 42, 225, 111, 245, 78, 55, 209, 76, 241, 73, 151, 186, 39, 108, 124, 82, 197, 173, 85, 146, 210, 77, 128, 56, 32, 97, 118, 180, 57, 33, 135, 239, 130, 144, 164, 246, 130, 180, 237, 242, 8, 114, 223, 95, 72, 4, 181, 69, 238, 9, 31, 216, 113, 152, 120, 167, 89, 165, 56, 88, 79, 3, 39, 189, 246, 63, 208, 138, 117, 244, 141, 153, 111, 204, 32, 247, 132, 12, 215, 109, 125, 19, 144, 123, 194, 137, 214, 111, 118, 148, 43, 169, 66, 238, 9, 25, 184, 178, 108, 14, 174, 154, 41, 143, 74, 60, 161, 4, 114, 79, 216, 224, 158, 80, 193, 90, 234, 60, 161, 68, 115, 5, 156, 123, 66, 5, 247, 132, 141, 102, 104, 42, 225, 111, 218, 170, 150, 77, 225, 120, 58, 15, 136, 43, 226, 164, 138, 19, 106, 165, 18, 69, 48, 131, 235, 218, 198, 187, 167, 19, 46, 124, 211, 73, 4, 136, 219, 10, 228, 158, 147, 134, 219, 138, 246, 38, 34, 220, 185, 31, 147, 166, 13, 119, 238, 132, 18, 30, 105, 180, 58, 199, 157, 112, 209, 236, 160, 13, 221, 9, 31, 141, 59, 161, 130, 183, 254, 202, 180, 191, 157, 84, 103, 66, 191, 74, 59, 33, 4, 51, 52, 119, 107, 83, 231, 221, 115, 37, 9, 231, 18, 125, 74, 109, 136, 37, 61, 247, 143, 41, 156, 75, 244, 21, 109, 15, 109, 43, 203, 32, 41, 153, 243, 112, 60, 29, 101, 217, 76, 171, 163, 5, 141, 247, 153, 57, 56, 42, 41, 210, 79, 237, 132, 143, 8, 18, 82, 39, 132, 68, 144, 128, 82, 39, 100, 72, 157, 80, 65, 42, 150, 157, 144, 161, 65, 118, 66, 200, 227, 18, 42, 168, 184, 132, 10, 158, 75, 8, 105, 151, 80, 65, 196, 181, 132, 24, 151, 80, 66, 215, 50, 200, 37, 92, 248, 90, 141, 245, 150, 150, 239, 139, 208, 193, 243, 155, 144, 126, 190, 55, 64, 68, 64, 252, 72, 2, 98, 95, 244, 72, 120, 227, 180, 168, 201, 197, 160, 167, 243, 83, 161, 7, 162, 56, 161, 167, 191, 61, 174, 80, 182, 143, 84, 75, 228, 186, 253, 237, 113, 194, 6, 232, 219, 83, 201, 14, 44, 115, 78, 156, 144, 193, 155, 19, 42, 168, 69, 141, 155, 19, 58, 168, 236, 198, 61, 7, 84, 170, 147, 234, 158, 71, 30, 209, 230, 135, 246, 115, 16, 228, 17, 164, 141, 84, 155, 19, 62, 164, 125, 231, 214, 228, 42, 8, 14, 193, 117, 13, 160, 77, 254, 174, 9, 206, 64, 39, 173, 222, 180, 237, 116, 252, 129, 206, 197, 223, 231, 187, 3, 138, 238, 100, 81, 10, 106, 32, 109, 227, 165, 136, 208, 218, 212, 49, 210, 181, 12, 3, 11, 156, 75, 180, 192, 178, 203, 121, 31, 78, 122, 101, 82, 219, 65, 173, 102, 10, 226, 181, 212, 65, 206, 53, 120, 200, 9, 171, 230, 132, 11, 215, 181, 204, 4, 226, 71, 95, 97, 208, 171, 80, 132, 196, 243, 27, 143, 123, 80, 133, 30, 199, 9, 33, 30, 199, 9, 21, 124, 161, 107, 25, 199, 55, 245, 198, 233, 43, 175, 161, 5, 16, 14, 13, 157, 17, 132, 14, 231, 151, 130, 62, 237, 167, 93, 172, 245, 28, 84, 169, 168, 131, 190, 117, 194, 30, 65, 252, 104, 105, 170, 232, 2, 247, 132, 190, 37, 244, 215, 50, 236, 203, 24, 63, 56, 192, 183, 117, 252, 219, 46, 119, 160, 117, 97, 218, 128, 54, 39, 111, 64, 82, 87, 0, 2, 236, 74, 11, 48, 126, 6, 58, 215, 107, 90, 162, 7, 208, 202, 198, 251, 77, 39, 141, 19, 50, 200, 102, 120, 94, 174, 2, 253, 184, 241, 254, 2, 186, 150, 124, 109, 89, 106, 127, 131, 36, 229, 187, 51, 90, 159, 92, 218, 188, 30, 211, 120, 63, 187, 89, 138, 111, 202, 22, 172, 199, 68, 180, 123, 30, 130, 158, 231, 183, 95, 82, 23, 128, 175, 66, 19, 184, 112, 62, 29, 242, 6, 102, 218, 162, 118, 240, 85, 188, 173, 14, 41, 109, 155, 255, 192, 63, 189, 126, 103, 60, 204, 58, 133, 46, 199, 109, 191, 229, 59, 168, 103, 66, 223, 242, 35, 152, 224, 147, 23, 131, 152, 182, 14, 37, 92, 233, 167, 218, 9, 253, 84, 187, 216, 91, 62, 132, 134, 125, 142, 214, 111, 219, 14, 233, 90, 242, 23, 52, 188, 34, 28, 45, 238, 6, 185, 216, 91, 167, 67, 237, 49, 3, 165, 16, 255, 88, 217, 190, 86, 236, 210, 55, 65, 253, 65, 69, 155, 4, 81, 60, 173, 111, 194, 114, 108, 29, 53, 46, 66, 253, 165, 83, 204, 36, 24, 180, 46, 209, 211, 252, 190, 78, 3, 142, 231, 98, 26, 180, 159, 55, 165, 104, 88, 229, 167, 122, 112, 192, 133, 175, 92, 120, 53, 8, 53, 109, 253, 49, 141, 19, 62, 200, 212, 44, 211, 222, 147, 161, 102, 153, 150, 78, 66, 16, 100, 96, 26, 39, 84, 152, 112, 109, 187, 40, 218, 144, 122, 83, 213, 56, 97, 132, 166, 150, 170, 249, 209, 146, 233, 68, 63, 155, 62, 220, 37, 115, 126, 41, 12, 26, 92, 50, 228, 64, 6, 138, 238, 4, 241, 183, 213, 127, 14, 156, 173, 66, 250, 47, 226, 174, 189, 64, 227, 135, 174, 101, 221, 181, 33, 77, 62, 114, 215, 118, 215, 134, 248, 164, 145, 229, 57, 82, 237, 65, 48, 97, 150, 131, 154, 29, 124, 83, 135, 180, 101, 42, 81, 171, 75, 168, 175, 126, 14, 77, 149, 242, 142, 219, 61, 252, 182, 58, 223, 116, 18, 225, 164, 84, 213, 118, 65, 21, 93, 206, 225, 109, 43, 203, 144, 123, 58, 136, 198, 235, 173, 147, 7, 95, 253, 90, 39, 76, 221, 97, 45, 77, 72, 233, 2, 196, 96, 45, 77, 16, 93, 77, 75, 132, 13, 173, 173, 170, 105, 35, 73, 39, 123, 208, 202, 232, 85, 141, 202, 50, 218, 14, 57, 159, 78, 162, 225, 133, 26, 55, 180, 93, 80, 227, 236, 141, 48, 248, 182, 171, 105, 197, 190, 227, 125, 25, 227, 132, 139, 138, 54, 218, 13, 14, 241, 77, 25, 227, 132, 144, 197, 252, 72, 219, 174, 8, 127, 223, 138, 34, 213, 28, 92, 223, 202, 9, 82, 154, 140, 113, 66, 6, 17, 32, 212, 131, 75, 38, 225, 109, 23, 198, 9, 29, 30, 102, 27, 123, 139, 19, 54, 250, 49, 186, 206, 59, 218, 186, 100, 12, 213, 249, 26, 197, 32, 137, 176, 104, 126, 228, 210, 52, 106, 246, 78, 247, 120, 223, 133, 148, 101, 123, 80, 150, 13, 194, 48, 171, 28, 223, 58, 105, 156, 80, 243, 226, 132, 13, 191, 190, 19, 8, 151, 12, 53, 94, 7, 143, 64, 112, 104, 147, 173, 19, 78, 104, 2, 19, 244, 73, 215, 74, 244, 73, 215, 226, 9, 253, 117, 40, 72, 221, 229, 90, 156, 144, 162, 45, 39, 116, 52, 156, 80, 193, 195, 108, 163, 65, 149, 97, 56, 33, 131, 219, 95, 204, 143, 42, 238, 96, 237, 63, 84, 225, 69, 181, 116, 85, 156, 208, 1, 109, 210, 49, 188, 181, 81, 120, 29, 127, 141, 207, 134, 230, 110, 157, 64, 170, 56, 97, 132, 175, 205, 70, 141, 57, 113, 66, 200, 210, 253, 148, 36, 78, 216, 120, 146, 235, 74, 78, 200, 248, 77, 10, 226, 132, 11, 245, 135, 56, 33, 67, 246, 87, 20, 57, 131, 56, 225, 131, 113, 51, 136, 19, 58, 180, 50, 170, 16, 39, 100, 32, 78, 216, 120, 20, 47, 136, 19, 46, 56, 225, 163, 178, 204, 179, 131, 216, 58, 142, 20, 75, 248, 160, 88, 194, 134, 214, 247, 183, 18, 58, 236, 91, 9, 21, 42, 190, 18, 42, 180, 166, 236, 111, 228, 43, 225, 67, 169, 132, 217, 65, 190, 18, 58, 144, 175, 132, 144, 167, 179, 45, 107, 102, 114, 49, 14, 255, 166, 19, 125, 80, 120, 169, 199, 43, 225, 195, 90, 6, 189, 171, 179, 58, 175, 132, 11, 103, 240, 207, 247, 135, 122, 99, 231, 14, 78, 85, 65, 180, 241, 74, 184, 144, 120, 37, 84, 216, 183, 43, 225, 194, 3, 121, 28, 39, 228, 160, 58, 121, 113, 187, 18, 54, 24, 102, 87, 194, 5, 111, 188, 238, 234, 232, 155, 62, 56, 175, 150, 210, 164, 191, 134, 126, 166, 246, 250, 95, 62, 36, 172, 132, 14, 230, 219, 182, 163, 232, 78, 180, 29, 74, 40, 209, 250, 204, 12, 154, 112, 215, 110, 16, 178, 75, 39, 191, 11, 163, 41, 36, 41, 255, 241, 234, 13, 72, 179, 220, 57, 24, 109, 244, 219, 52, 172, 126, 45, 117, 37, 116, 240, 8, 67, 196, 90, 143, 65, 174, 15, 141, 194, 10, 81, 228, 167, 210, 230, 132, 90, 173, 132, 13, 87, 150, 205, 225, 17, 8, 239, 187, 124, 151, 196, 103, 130, 208, 216, 35, 104, 129, 7, 95, 251, 239, 193, 64, 107, 196, 251, 46, 135, 47, 67, 53, 253, 138, 34, 196, 229, 74, 168, 32, 193, 167, 212, 126, 240, 198, 251, 217, 14, 68, 208, 104, 254, 85, 42, 73, 200, 104, 236, 145, 132, 11, 173, 21, 93, 200, 35, 9, 33, 252, 173, 202, 110, 253, 166, 137, 65, 154, 70, 81, 51, 131, 26, 123, 100, 193, 211, 185, 94, 234, 77, 184, 128, 122, 46, 8, 31, 223, 54, 161, 130, 171, 77, 168, 160, 54, 161, 195, 59, 39, 8, 109, 66, 136, 133, 35, 104, 19, 54, 76, 154, 162, 77, 200, 160, 24, 36, 237, 57, 9, 25, 240, 8, 210, 37, 73, 235, 144, 4, 123, 203, 128, 52, 120, 223, 133, 92, 233, 231, 122, 76, 27, 240, 197, 252, 19, 85, 14, 82, 45, 44, 23, 114, 74, 34, 141, 240, 8, 74, 198, 237, 36, 108, 116, 163, 176, 147, 144, 97, 87, 66, 157, 106, 37, 236, 36, 132, 184, 166, 101, 39, 97, 68, 43, 102, 78, 66, 134, 10, 52, 124, 69, 213, 90, 39, 97, 68, 219, 124, 238, 137, 58, 9, 29, 188, 173, 234, 36, 92, 184, 183, 96, 143, 65, 161, 205, 239, 223, 116, 87, 138, 240, 102, 214, 220, 173, 72, 226, 11, 225, 186, 146, 164, 78, 66, 9, 39, 125, 82, 144, 75, 117, 18, 62, 36, 105, 37, 13, 198, 92, 49, 225, 75, 151, 92, 249, 169, 184, 181, 68, 30, 121, 164, 138, 219, 68, 243, 226, 212, 240, 77, 25, 51, 6, 30, 249, 247, 253, 78, 39, 33, 227, 213, 59, 157, 132, 11, 214, 233, 36, 92, 80, 187, 114, 210, 22, 105, 106, 218, 202, 104, 51, 0, 241, 164, 108, 116, 61, 136, 96, 177, 119, 144, 3, 215, 253, 253, 166, 168, 245, 83, 118, 58, 9, 37, 58, 157, 132, 14, 136, 138, 54, 218, 107, 25, 212, 240, 114, 240, 160, 158, 9, 105, 211, 82, 75, 39, 33, 67, 75, 39, 161, 194, 174, 212, 234, 144, 172, 116, 18, 46, 176, 108, 73, 58, 9, 23, 148, 244, 214, 28, 212, 190, 231, 186, 206, 29, 74, 191, 217, 157, 170, 66, 20, 94, 43, 29, 111, 160, 146, 93, 141, 198, 30, 137, 168, 122, 43, 85, 20, 162, 236, 169, 104, 202, 152, 161, 108, 95, 63, 85, 67, 91, 22, 190, 233, 36, 124, 72, 154, 153, 132, 11, 254, 141, 153, 132, 12, 223, 118, 161, 198, 36, 100, 76, 154, 50, 9, 23, 22, 38, 161, 2, 143, 64, 88, 120, 45, 136, 73, 232, 104, 205, 174, 68, 173, 223, 52, 33, 164, 241, 126, 126, 211, 109, 70, 107, 105, 66, 8, 253, 236, 69, 151, 38, 108, 248, 4, 36, 42, 225, 194, 87, 82, 66, 5, 100, 104, 154, 151, 132, 11, 188, 36, 108, 52, 47, 9, 21, 40, 153, 80, 129, 175, 119, 58, 159, 9, 27, 43, 159, 103, 66, 6, 198, 10, 57, 158, 9, 25, 206, 231, 122, 83, 71, 234, 153, 208, 0, 234, 153, 80, 161, 237, 226, 153, 144, 161, 117, 187, 51, 225, 130, 87, 103, 194, 133, 149, 109, 85, 103, 66, 134, 234, 165, 19, 119, 240, 41, 181, 81, 3, 255, 166, 173, 241, 210, 153, 48, 226, 183, 162, 72, 251, 61, 47, 228, 109, 243, 93, 38, 132, 172, 108, 118, 153, 112, 145, 191, 46, 19, 66, 154, 73, 203, 132, 11, 191, 12, 114, 120, 78, 24, 180, 98, 87, 166, 109, 252, 187, 32, 139, 114, 172, 75, 164, 254, 150, 177, 66, 234, 79, 210, 118, 177, 199, 81, 203, 132, 143, 39, 151, 227, 127, 137, 90, 38, 132, 104, 197, 50, 212, 51, 53, 212, 51, 161, 165, 44, 19, 58, 84, 115, 210, 70, 250, 235, 15, 106, 81, 171, 254, 186, 182, 174, 149, 9, 25, 240, 193, 1, 162, 218, 46, 104, 173, 76, 216, 112, 139, 82, 154, 137, 67, 154, 230, 26, 117, 145, 6, 102, 27, 4, 241, 86, 183, 43, 19, 50, 180, 151, 93, 153, 112, 129, 14, 250, 169, 86, 38, 92, 52, 10, 55, 116, 178, 159, 75, 81, 68, 184, 39, 97, 94, 72, 215, 146, 16, 46, 41, 238, 206, 167, 243, 85, 218, 15, 124, 149, 54, 175, 227, 233, 32, 103, 208, 130, 214, 38, 91, 178, 134, 166, 223, 56, 73, 168, 231, 130, 142, 9, 36, 12, 128, 66, 16, 33, 161, 130, 250, 82, 60, 194, 82, 251, 33, 142, 47, 35, 233, 34, 215, 127, 30, 92, 255, 89, 112, 65, 255, 89, 208, 161, 21, 235, 13, 231, 155, 166, 11, 233, 63, 11, 62, 244, 159, 5, 21, 180, 237, 122, 22, 100, 240, 8, 114, 75, 89, 112, 241, 240, 226, 111, 65, 6, 254, 237, 126, 11, 46, 52, 101, 191, 66, 220, 80, 69, 49, 190, 224, 249, 215, 118, 46, 61, 114, 60, 223, 27, 94, 19, 45, 159, 124, 218, 91, 144, 193, 73, 159, 148, 199, 82, 237, 45, 216, 208, 222, 130, 10, 146, 173, 183, 224, 66, 54, 237, 68, 107, 189, 5, 29, 107, 189, 5, 21, 156, 225, 170, 56, 33, 127, 223, 246, 215, 38, 107, 172, 253, 71, 209, 90, 255, 211, 225, 3, 165, 153, 183, 224, 194, 218, 127, 190, 144, 164, 116, 146, 100, 30, 97, 52, 74, 58, 71, 74, 29, 154, 43, 79, 219, 201, 3, 255, 2, 103, 235, 56, 68, 189, 117, 162, 253, 244, 77, 128, 168, 91, 167, 234, 36, 214, 90, 230, 49, 129, 59, 188, 65, 217, 62, 250, 150, 43, 223, 4, 93, 64, 29, 148, 73, 111, 15, 77, 36, 94, 43, 81, 43, 195, 188, 5, 33, 15, 179, 186, 150, 183, 32, 67, 127, 23, 74, 254, 5, 27, 201, 191, 160, 66, 99, 95, 80, 65, 146, 212, 73, 19, 144, 192, 23, 108, 76, 64, 2, 95, 80, 161, 213, 57, 125, 71, 190, 160, 163, 249, 147, 70, 218, 162, 87, 231, 182, 57, 242, 5, 39, 92, 221, 38, 109, 228, 11, 58, 124, 193, 134, 36, 229, 251, 174, 132, 220, 181, 221, 147, 144, 3, 73, 202, 247, 86, 167, 64, 190, 105, 147, 173, 254, 208, 251, 46, 111, 117, 138, 239, 122, 44, 187, 42, 30, 102, 23, 180, 102, 253, 33, 189, 27, 123, 4, 105, 147, 146, 148, 174, 193, 202, 135, 217, 137, 149, 223, 148, 105, 167, 182, 232, 97, 214, 25, 212, 224, 170, 208, 195, 108, 171, 227, 54, 161, 135, 89, 71, 241, 48, 235, 144, 164, 116, 237, 73, 18, 47, 228, 75, 126, 196, 62, 148, 218, 227, 186, 235, 119, 57, 111, 88, 196, 143, 88, 106, 191, 235, 90, 82, 165, 118, 3, 202, 246, 219, 65, 12, 36, 41, 29, 68, 21, 55, 212, 44, 65, 173, 132, 183, 170, 84, 167, 93, 107, 211, 150, 153, 152, 52, 125, 124, 210, 87, 229, 224, 173, 78, 225, 109, 202, 195, 195, 236, 106, 222, 59, 133, 75, 214, 234, 173, 255, 174, 204, 182, 100, 72, 215, 243, 222, 128, 162, 239, 13, 142, 167, 131, 182, 93, 181, 31, 81, 120, 185, 75, 134, 220, 211, 221, 91, 139, 187, 105, 235, 200, 61, 189, 179, 251, 166, 11, 48, 211, 22, 169, 226, 22, 209, 218, 94, 2, 90, 43, 118, 37, 107, 110, 104, 1, 237, 164, 232, 82, 106, 153, 174, 101, 22, 52, 111, 81, 229, 208, 224, 51, 53, 78, 15, 238, 9, 181, 212, 149, 90, 215, 58, 111, 217, 255, 64, 127, 155, 194, 96, 226, 18, 75, 91, 123, 12, 82, 44, 209, 46, 78, 137, 123, 193, 9, 103, 122, 65, 5, 213, 76, 105, 184, 167, 163, 111, 203, 78, 146, 218, 11, 62, 56, 175, 82, 123, 65, 135, 247, 76, 189, 32, 131, 68, 57, 114, 82, 203, 94, 208, 177, 40, 5, 169, 246, 183, 205, 94, 176, 193, 25, 26, 175, 183, 236, 5, 31, 116, 41, 197, 12, 53, 230, 22, 124, 52, 188, 239, 114, 110, 65, 6, 111, 156, 182, 194, 11, 50, 154, 86, 120, 193, 5, 137, 170, 240, 130, 144, 79, 234, 21, 94, 176, 161, 149, 226, 17, 135, 82, 120, 65, 136, 182, 126, 188, 32, 195, 167, 54, 4, 105, 188, 244, 227, 5, 23, 106, 223, 163, 240, 71, 37, 232, 151, 49, 242, 181, 255, 30, 52, 222, 207, 102, 39, 217, 208, 163, 18, 119, 93, 15, 60, 157, 170, 61, 110, 14, 143, 232, 250, 231, 5, 25, 142, 55, 47, 184, 224, 142, 23, 84, 112, 210, 39, 197, 81, 225, 229, 125, 215, 202, 167, 80, 4, 12, 244, 77, 26, 116, 53, 13, 127, 171, 218, 229, 233, 14, 15, 179, 207, 13, 194, 27, 167, 125, 208, 79, 69, 241, 172, 198, 200, 93, 162, 85, 146, 214, 53, 47, 78, 104, 129, 203, 126, 111, 84, 120, 121, 230, 5, 23, 76, 225, 97, 22, 23, 186, 120, 65, 5, 73, 226, 5, 177, 88, 5, 61, 60, 138, 23, 124, 60, 138, 23, 84, 72, 170, 120, 193, 133, 102, 196, 11, 62, 218, 130, 1, 240, 8, 114, 108, 65, 6, 199, 211, 233, 183, 22, 100, 44, 199, 30, 34, 129, 98, 143, 133, 215, 130, 248, 145, 231, 164, 101, 66, 142, 173, 190, 181, 32, 131, 167, 95, 27, 169, 222, 69, 223, 90, 208, 225, 169, 124, 34, 135, 210, 69, 132, 6, 8, 58, 172, 253, 215, 248, 69, 236, 224, 216, 163, 133, 215, 99, 225, 181, 96, 3, 195, 172, 66, 146, 182, 107, 65, 199, 178, 253, 141, 19, 82, 234, 174, 107, 193, 7, 143, 168, 36, 215, 130, 139, 247, 93, 146, 148, 107, 193, 198, 90, 48, 0, 191, 11, 54, 210, 54, 102, 218, 24, 196, 178, 11, 105, 187, 99, 212, 150, 211, 239, 130, 15, 93, 74, 45, 229, 209, 239, 130, 143, 9, 38, 112, 187, 224, 2, 5, 36, 184, 93, 112, 33, 2, 9, 64, 224, 118, 65, 6, 151, 77, 89, 184, 106, 191, 99, 47, 210, 240, 166, 173, 82, 236, 188, 50, 20, 89, 24, 194, 97, 173, 68, 170, 237, 130, 140, 221, 228, 217, 118, 65, 198, 68, 226, 208, 208, 44, 211, 56, 161, 230, 238, 101, 20, 17, 234, 153, 208, 227, 233, 108, 187, 32, 67, 196, 163, 245, 215, 50, 200, 155, 92, 12, 154, 192, 4, 181, 93, 112, 66, 146, 210, 161, 182, 11, 50, 60, 2, 161, 217, 5, 33, 202, 246, 63, 27, 53, 187, 224, 162, 217, 5, 29, 141, 61, 130, 154, 93, 144, 209, 218, 232, 183, 69, 205, 46, 248, 240, 8, 90, 181, 11, 46, 244, 233, 155, 0, 113, 62, 221, 68, 115, 236, 248, 85, 47, 17, 115, 13, 194, 19, 43, 212, 250, 175, 11, 70, 184, 173, 120, 215, 5, 23, 75, 221, 117, 65, 6, 109, 90, 54, 146, 32, 129, 211, 5, 31, 223, 116, 65, 5, 73, 39, 115, 82, 211, 5, 27, 173, 191, 116, 65, 134, 86, 167, 186, 32, 131, 46, 216, 88, 118, 33, 180, 28, 66, 234, 185, 32, 4, 193, 4, 69, 0, 69, 192, 17, 66, 78, 66, 42, 73, 186, 160, 2, 34, 72, 112, 146, 46, 200, 208, 57, 65, 79, 69, 46, 164, 212, 130, 16, 143, 48, 60, 162, 138, 27, 106, 120, 247, 116, 90, 144, 193, 35, 170, 56, 45, 11, 50, 36, 112, 69, 206, 231, 130, 140, 198, 251, 235, 12, 209, 180, 85, 42, 221, 67, 219, 166, 147, 57, 252, 227, 39, 151, 218, 110, 144, 123, 114, 111, 94, 28, 90, 179, 43, 145, 123, 114, 79, 238, 185, 224, 194, 61, 211, 248, 151, 40, 173, 231, 130, 18, 11, 175, 6, 57, 158, 11, 54, 86, 191, 8, 38, 104, 168, 141, 96, 130, 8, 38, 136, 96, 2, 138, 134, 45, 138, 96, 130, 8, 38, 136, 48, 129, 58, 132, 70, 211, 8, 18, 42, 12, 18, 207, 215, 230, 119, 135, 55, 184, 254, 227, 78, 233, 92, 89, 54, 7, 247, 73, 83, 134, 68, 179, 76, 155, 80, 103, 199, 24, 242, 224, 174, 137, 219, 161, 93, 9, 169, 51, 38, 77, 103, 35, 130, 9, 144, 122, 46, 184, 72, 219, 223, 52, 61, 157, 11, 46, 236, 74, 40, 155, 174, 92, 208, 161, 169, 229, 202, 5, 29, 212, 173, 107, 114, 193, 133, 54, 217, 52, 185, 160, 195, 251, 46, 228, 170, 153, 162, 114, 193, 134, 182, 141, 202, 5, 25, 60, 226, 248, 29, 142, 231, 114, 73, 202, 5, 27, 30, 169, 52, 98, 24, 8, 47, 56, 151, 232, 153, 108, 165, 255, 218, 120, 59, 25, 132, 255, 245, 103, 201, 5, 194, 4, 171, 246, 26, 188, 162, 205, 21, 49, 208, 198, 139, 36, 229, 130, 12, 39, 229, 242, 44, 185, 96, 163, 241, 122, 150, 92, 112, 241, 48, 203, 144, 36, 117, 210, 90, 153, 220, 246, 4, 78, 250, 164, 60, 36, 43, 41, 234, 158, 71, 227, 149, 170, 229, 59, 68, 131, 195, 155, 188, 9, 3, 17, 32, 64, 218, 228, 59, 133, 115, 57, 65, 225, 229, 145, 133, 153, 52, 237, 126, 175, 174, 189, 150, 121, 22, 59, 120, 238, 202, 244, 214, 201, 182, 167, 150, 39, 136, 31, 73, 146, 58, 9, 41, 237, 92, 73, 85, 123, 15, 180, 190, 111, 163, 29, 65, 115, 107, 182, 162, 223, 56, 33, 237, 125, 19, 18, 144, 203, 105, 55, 64, 89, 54, 109, 213, 158, 2, 18, 224, 174, 162, 141, 118, 3, 180, 249, 81, 63, 167, 169, 31, 51, 75, 29, 85, 60, 242, 233, 24, 39, 3, 44, 128, 1, 147, 166, 72, 21, 183, 150, 186, 152, 151, 4, 52, 109, 215, 178, 14, 1, 2, 9, 174, 84, 34, 157, 236, 191, 164, 222, 56, 185, 237, 119, 68, 225, 197, 40, 96, 1, 16, 36, 60, 64, 130, 4, 170, 56, 109, 123, 12, 171, 123, 222, 1, 16, 168, 104, 163, 141, 30, 73, 218, 247, 6, 44, 160, 213, 61, 87, 76, 89, 54, 196, 48, 106, 102, 30, 149, 32, 253, 76, 187, 220, 83, 77, 219, 126, 170, 28, 160, 244, 159, 99, 12, 129, 171, 123, 174, 212, 180, 117, 128, 82, 199, 201, 145, 36, 241, 90, 34, 144, 0, 130, 8, 68, 112, 69, 8, 64, 0, 1, 20, 128, 90, 157, 203, 166, 32, 166, 239, 143, 35, 143, 36, 197, 239, 17, 104, 125, 215, 247, 100, 140, 83, 211, 118, 109, 246, 63, 192, 181, 19, 80, 241, 136, 106, 187, 32, 2, 80, 120, 49, 223, 8, 112, 188, 21, 117, 64, 1, 248, 1, 254, 244, 250, 189, 113, 66, 238, 185, 146, 163, 74, 126, 123, 12, 224, 146, 33, 10, 230, 118, 160, 189, 20, 109, 93, 236, 141, 83, 46, 109, 137, 102, 226, 186, 235, 219, 54, 109, 18, 43, 203, 134, 82, 177, 108, 137, 214, 172, 243, 115, 187, 231, 91, 29, 183, 139, 48, 223, 118, 20, 202, 178, 33, 73, 123, 78, 66, 206, 167, 107, 125, 101, 217, 233, 6, 160, 44, 219, 186, 178, 108, 72, 87, 211, 146, 13, 224, 249, 109, 203, 180, 85, 170, 58, 95, 211, 216, 183, 221, 46, 166, 241, 126, 182, 101, 187, 84, 165, 42, 6, 28, 192, 219, 254, 218, 183, 160, 135, 217, 182, 204, 153, 2, 28, 79, 197, 107, 98, 169, 98, 134, 38, 168, 226, 17, 181, 249, 169, 144, 78, 152, 105, 31, 192, 91, 151, 89, 197, 12, 85, 60, 210, 76, 220, 117, 45, 185, 157, 19, 244, 77, 89, 227, 222, 73, 83, 6, 76, 154, 62, 171, 111, 118, 108, 162, 162, 22, 66, 181, 29, 210, 182, 171, 45, 242, 206, 101, 177, 119, 154, 124, 228, 192, 35, 13, 172, 156, 68, 52, 222, 231, 92, 235, 24, 39, 180, 46, 91, 23, 166, 10, 104, 230, 160, 156, 168, 137, 42, 6, 154, 183, 232, 3, 111, 12, 210, 79, 181, 192, 221, 83, 211, 86, 45, 102, 208, 183, 100, 175, 41, 122, 111, 12, 180, 145, 178, 108, 79, 46, 231, 171, 10, 224, 74, 37, 119, 74, 214, 170, 146, 33, 239, 137, 248, 209, 202, 214, 223, 69, 241, 174, 17, 111, 112, 199, 237, 144, 54, 173, 12, 85, 60, 130, 244, 77, 6, 176, 28, 63, 154, 236, 155, 160, 200, 151, 129, 231, 183, 179, 113, 183, 139, 113, 192, 61, 87, 106, 188, 170, 120, 185, 74, 3, 242, 173, 156, 168, 75, 134, 180, 45, 163, 170, 129, 126, 54, 186, 84, 161, 181, 50, 45, 80, 241, 8, 250, 148, 218, 15, 120, 243, 103, 115, 82, 133, 30, 102, 85, 219, 5, 9, 224, 225, 219, 46, 87, 136, 182, 67, 21, 67, 236, 74, 168, 177, 116, 201, 5, 23, 150, 46, 207, 178, 228, 130, 140, 206, 37, 23, 92, 208, 223, 133, 94, 4, 19, 44, 216, 136, 96, 130, 5, 21, 52, 44, 207, 129, 252, 59, 232, 121, 39, 32, 212, 115, 65, 110, 2, 75, 244, 188, 72, 251, 85, 184, 227, 137, 170, 5, 141, 25, 227, 4, 97, 157, 72, 251, 85, 36, 74, 60, 173, 111, 2, 170, 36, 58, 252, 178, 93, 72, 63, 187, 178, 12, 122, 42, 220, 142, 173, 111, 14, 73, 98, 38, 209, 218, 52, 188, 32, 46, 97, 118, 30, 16, 13, 47, 212, 188, 69, 213, 67, 103, 68, 87, 194, 220, 96, 194, 121, 43, 137, 11, 173, 90, 209, 74, 34, 195, 121, 43, 137, 34, 112, 74, 162, 35, 2, 167, 52, 239, 236, 22, 172, 9, 254, 48, 119, 109, 87, 81, 10, 109, 78, 72, 162, 28, 61, 217, 21, 72, 107, 214, 37, 137, 25, 68, 146, 152, 73, 148, 35, 167, 36, 78, 104, 243, 59, 98, 217, 233, 144, 83, 18, 31, 36, 202, 145, 166, 157, 168, 66, 207, 18, 204, 180, 69, 78, 73, 100, 52, 127, 210, 214, 56, 33, 167, 36, 50, 240, 157, 144, 83, 18, 23, 143, 79, 169, 141, 156, 146, 24, 81, 217, 181, 148, 68, 6, 109, 236, 184, 137, 247, 92, 200, 117, 178, 216, 181, 209, 179, 26, 23, 96, 178, 159, 173, 142, 237, 2, 169, 61, 94, 84, 33, 101, 236, 74, 73, 116, 224, 84, 151, 107, 179, 227, 146, 169, 63, 188, 247, 50, 191, 73, 73, 124, 36, 159, 36, 42, 84, 242, 115, 146, 200, 224, 106, 201, 181, 12, 126, 219, 162, 156, 36, 50, 114, 146, 168, 224, 157, 102, 151, 211, 172, 131, 222, 181, 105, 222, 2, 173, 88, 127, 215, 230, 127, 137, 140, 137, 214, 202, 50, 218, 142, 255, 37, 66, 248, 95, 226, 163, 85, 210, 118, 57, 154, 70, 145, 82, 11, 250, 169, 237, 17, 8, 250, 186, 28, 227, 135, 198, 173, 101, 226, 127, 137, 142, 134, 151, 54, 45, 157, 228, 160, 218, 46, 136, 255, 37, 54, 92, 55, 237, 98, 135, 84, 51, 197, 61, 93, 131, 93, 9, 61, 188, 156, 42, 20, 1, 231, 95, 34, 132, 243, 47, 241, 177, 9, 253, 170, 151, 200, 240, 198, 235, 188, 234, 37, 66, 160, 254, 79, 124, 56, 213, 229, 144, 5, 165, 101, 252, 137, 14, 78, 209, 157, 160, 166, 14, 105, 74, 231, 136, 241, 39, 82, 232, 239, 66, 11, 127, 98, 99, 225, 79, 84, 72, 254, 68, 133, 117, 217, 212, 113, 196, 83, 34, 168, 229, 186, 231, 250, 196, 6, 110, 143, 44, 244, 115, 149, 50, 182, 175, 222, 128, 101, 167, 123, 215, 158, 240, 71, 37, 16, 214, 254, 131, 240, 251, 168, 68, 37, 187, 86, 34, 181, 199, 83, 251, 121, 251, 101, 187, 24, 118, 82, 42, 3, 39, 165, 62, 217, 157, 16, 214, 254, 163, 208, 167, 111, 2, 132, 199, 47, 219, 181, 116, 173, 236, 116, 16, 214, 126, 123, 232, 87, 223, 202, 201, 132, 190, 149, 19, 93, 255, 220, 206, 59, 40, 99, 95, 255, 234, 144, 166, 161, 167, 95, 251, 233, 215, 126, 248, 42, 109, 125, 250, 38, 160, 137, 138, 254, 99, 188, 28, 90, 127, 217, 174, 134, 21, 65, 18, 230, 182, 201, 88, 33, 9, 115, 132, 55, 72, 152, 29, 244, 91, 121, 104, 253, 95, 166, 223, 116, 34, 225, 164, 212, 198, 14, 117, 82, 38, 36, 241, 85, 16, 19, 79, 168, 145, 218, 227, 137, 11, 148, 247, 68, 5, 10, 47, 6, 185, 186, 199, 65, 189, 117, 2, 97, 205, 204, 123, 98, 131, 122, 235, 36, 251, 209, 163, 146, 54, 225, 235, 41, 134, 104, 109, 101, 218, 162, 252, 84, 206, 28, 190, 120, 97, 143, 163, 214, 172, 123, 162, 195, 2, 127, 117, 127, 208, 120, 191, 27, 239, 59, 118, 80, 197, 13, 77, 124, 171, 59, 131, 40, 116, 169, 150, 206, 131, 51, 72, 215, 194, 212, 61, 241, 209, 180, 109, 85, 77, 91, 219, 161, 215, 230, 60, 113, 34, 2, 19, 136, 32, 65, 98, 26, 121, 4, 2, 4, 205, 249, 221, 211, 137, 121, 34, 196, 19, 27, 118, 165, 221, 228, 203, 90, 153, 60, 209, 209, 233, 137, 10, 46, 61, 81, 33, 91, 122, 226, 130, 174, 37, 31, 121, 34, 195, 19, 27, 79, 118, 39, 242, 68, 134, 242, 207, 119, 212, 224, 105, 93, 107, 191, 19, 27, 223, 137, 16, 95, 57, 217, 238, 68, 198, 195, 108, 119, 34, 195, 164, 233, 78, 92, 248, 148, 142, 113, 66, 79, 191, 35, 102, 209, 195, 48, 235, 146, 77, 56, 41, 181, 185, 233, 187, 100, 159, 171, 65, 69, 85, 91, 213, 30, 64, 80, 247, 60, 63, 183, 131, 192, 96, 194, 182, 151, 154, 126, 83, 143, 120, 7, 77, 253, 248, 155, 221, 161, 105, 151, 47, 134, 121, 78, 131, 235, 182, 122, 122, 74, 91, 155, 150, 221, 169, 15, 218, 180, 236, 135, 78, 152, 185, 100, 141, 247, 92, 14, 253, 108, 253, 198, 251, 73, 189, 245, 37, 86, 238, 111, 91, 134, 43, 170, 218, 54, 253, 134, 207, 53, 81, 81, 213, 22, 65, 168, 182, 140, 163, 245, 215, 50, 14, 79, 235, 100, 229, 155, 160, 143, 86, 134, 89, 5, 145, 164, 92, 208, 147, 221, 137, 142, 198, 219, 94, 195, 37, 197, 245, 243, 185, 81, 119, 162, 131, 97, 86, 161, 238, 68, 70, 67, 207, 111, 39, 46, 158, 214, 55, 1, 229, 118, 162, 67, 169, 106, 250, 21, 69, 254, 77, 217, 107, 58, 81, 226, 201, 238, 244, 166, 19, 27, 222, 116, 162, 130, 122, 167, 107, 58, 145, 17, 161, 113, 211, 137, 12, 78, 211, 137, 10, 77, 39, 42, 80, 170, 147, 117, 79, 135, 180, 19, 27, 240, 181, 255, 144, 67, 51, 212, 61, 143, 116, 178, 78, 234, 68, 72, 46, 220, 46, 145, 193, 223, 105, 214, 219, 78, 56, 159, 14, 53, 203, 52, 78, 104, 57, 151, 216, 96, 31, 63, 14, 84, 113, 170, 64, 40, 172, 218, 126, 211, 38, 23, 165, 44, 104, 254, 100, 252, 47, 247, 45, 128, 154, 86, 236, 127, 179, 115, 207, 29, 90, 155, 230, 45, 170, 144, 62, 51, 109, 6, 17, 82, 50, 137, 148, 204, 153, 194, 57, 98, 81, 235, 144, 36, 35, 193, 238, 218, 206, 149, 129, 50, 110, 39, 77, 168, 231, 34, 209, 58, 217, 86, 11, 22, 149, 136, 189, 117, 46, 209, 161, 238, 121, 176, 102, 198, 91, 246, 67, 60, 173, 111, 2, 164, 149, 97, 222, 130, 84, 211, 6, 213, 212, 185, 196, 71, 195, 148, 115, 137, 12, 30, 241, 94, 229, 92, 98, 195, 145, 164, 237, 98, 160, 138, 155, 174, 101, 8, 224, 234, 120, 118, 196, 174, 212, 128, 154, 38, 231, 18, 27, 18, 229, 188, 56, 151, 232, 224, 239, 179, 211, 185, 196, 134, 243, 233, 26, 122, 21, 122, 230, 70, 206, 37, 66, 218, 46, 168, 85, 173, 125, 11, 114, 46, 241, 65, 130, 238, 239, 218, 127, 16, 77, 219, 148, 253, 147, 166, 77, 91, 95, 165, 221, 58, 105, 245, 7, 146, 182, 11, 181, 54, 13, 39, 83, 39, 185, 68, 115, 183, 106, 115, 66, 146, 182, 11, 194, 73, 159, 11, 146, 180, 93, 146, 182, 235, 225, 205, 221, 218, 192, 188, 133, 159, 219, 161, 166, 237, 55, 59, 109, 164, 109, 155, 166, 249, 169, 34, 212, 61, 63, 128, 39, 101, 163, 11, 81, 120, 49, 104, 129, 87, 215, 118, 232, 155, 238, 218, 213, 240, 190, 222, 234, 218, 46, 64, 20, 234, 164, 76, 42, 121, 185, 135, 38, 222, 153, 23, 8, 175, 197, 46, 209, 161, 185, 68, 5, 154, 94, 250, 186, 68, 70, 98, 181, 46, 145, 65, 157, 148, 105, 93, 34, 67, 127, 21, 183, 227, 18, 27, 21, 117, 137, 14, 9, 20, 115, 188, 123, 58, 81, 184, 59, 145, 58, 41, 93, 34, 196, 37, 6, 192, 223, 245, 209, 115, 226, 196, 55, 251, 211, 18, 23, 78, 250, 100, 79, 75, 100, 172, 165, 142, 163, 167, 37, 66, 168, 111, 75, 124, 248, 51, 34, 232, 245, 45, 145, 65, 215, 46, 204, 30, 142, 59, 161, 134, 109, 131, 71, 158, 84, 72, 125, 75, 124, 160, 190, 37, 42, 232, 155, 160, 214, 172, 171, 66, 223, 18, 29, 24, 131, 123, 21, 88, 111, 173, 170, 61, 135, 79, 169, 141, 248, 23, 123, 7, 241, 67, 88, 235, 235, 122, 222, 157, 230, 113, 59, 175, 146, 237, 119, 137, 87, 215, 118, 84, 180, 209, 214, 102, 248, 55, 101, 77, 54, 227, 174, 169, 233, 155, 160, 142, 212, 101, 114, 93, 192, 86, 49, 90, 62, 169, 225, 205, 139, 83, 243, 226, 228, 80, 139, 245, 173, 134, 36, 229, 162, 240, 90, 250, 52, 232, 175, 67, 81, 218, 142, 252, 166, 77, 50, 135, 166, 218, 13, 164, 229, 147, 244, 61, 36, 41, 215, 210, 44, 104, 189, 37, 66, 214, 91, 162, 66, 171, 183, 196, 5, 101, 217, 12, 106, 188, 14, 248, 145, 146, 112, 79, 16, 240, 209, 182, 225, 133, 86, 110, 98, 71, 149, 5, 170, 56, 245, 4, 84, 105, 73, 90, 247, 185, 24, 84, 145, 136, 224, 105, 223, 211, 254, 67, 237, 123, 40, 66, 67, 235, 123, 242, 163, 8, 18, 79, 134, 190, 162, 143, 34, 72, 168, 116, 218, 239, 179, 53, 235, 40, 66, 163, 176, 114, 220, 10, 125, 210, 165, 190, 191, 30, 67, 17, 28, 208, 165, 22, 181, 186, 106, 63, 59, 218, 247, 184, 209, 190, 8, 181, 221, 160, 125, 46, 251, 253, 153, 23, 180, 143, 226, 155, 54, 118, 140, 19, 82, 237, 31, 128, 235, 90, 6, 1, 250, 185, 188, 101, 71, 56, 233, 241, 55, 252, 46, 231, 107, 113, 39, 7, 173, 216, 223, 150, 14, 161, 255, 184, 181, 117, 45, 89, 177, 174, 237, 18, 74, 4, 57, 72, 106, 25, 69, 112, 254, 37, 79, 184, 36, 49, 115, 136, 149, 219, 250, 201, 22, 212, 180, 85, 201, 107, 93, 162, 69, 41, 232, 105, 102, 202, 80, 123, 32, 241, 100, 13, 109, 2, 16, 44, 100, 177, 119, 38, 156, 102, 157, 8, 173, 239, 106, 59, 194, 117, 53, 204, 77, 243, 80, 214, 31, 10, 202, 149, 220, 12, 131, 214, 73, 58, 210, 181, 140, 246, 187, 46, 72, 251, 158, 75, 117, 101, 226, 197, 64, 215, 146, 206, 113, 43, 212, 52, 217, 12, 184, 174, 37, 63, 63, 149, 132, 235, 74, 152, 31, 60, 2, 225, 59, 157, 78, 213, 116, 101, 130, 200, 109, 136, 126, 178, 109, 249, 128, 86, 38, 94, 40, 2, 106, 128, 11, 71, 8, 101, 205, 78, 106, 234, 160, 70, 97, 37, 233, 100, 136, 65, 179, 147, 90, 34, 131, 42, 110, 14, 142, 16, 203, 46, 55, 129, 37, 46, 220, 4, 150, 168, 224, 17, 164, 234, 61, 228, 249, 77, 188, 116, 34, 73, 204, 34, 214, 254, 251, 231, 214, 254, 99, 160, 177, 243, 143, 107, 188, 234, 241, 74, 78, 73, 212, 170, 118, 82, 0, 127, 199, 184, 221, 3, 3, 60, 162, 138, 219, 2, 20, 144, 147, 140, 36, 192, 93, 151, 74, 117, 22, 80, 247, 188, 0, 60, 177, 66, 107, 130, 227, 178, 155, 7, 16, 192, 141, 166, 100, 90, 191, 45, 34, 192, 187, 237, 228, 57, 201, 8, 3, 206, 75, 209, 250, 255, 22, 163, 150, 91, 181, 68, 170, 233, 55, 110, 198, 193, 162, 152, 101, 123, 22, 248, 92, 142, 233, 51, 160, 85, 237, 132, 219, 33, 101, 251, 237, 53, 122, 109, 207, 106, 1, 173, 109, 243, 27, 63, 208, 197, 222, 26, 28, 160, 105, 163, 138, 31, 90, 155, 134, 151, 132, 54, 39, 180, 11, 162, 43, 19, 171, 180, 93, 3, 222, 120, 63, 211, 50, 251, 220, 30, 104, 253, 182, 14, 52, 109, 223, 217, 113, 192, 218, 80, 52, 222, 79, 237, 49, 158, 246, 159, 149, 45, 209, 211, 220, 232, 103, 90, 160, 249, 115, 61, 182, 142, 82, 123, 252, 129, 115, 137, 30, 102, 151, 99, 137, 143, 230, 79, 181, 43, 39, 104, 177, 119, 28, 75, 140, 104, 188, 222, 58, 65, 170, 165, 183, 58, 150, 24, 161, 77, 186, 43, 67, 142, 37, 62, 28, 75, 84, 160, 109, 25, 85, 76, 177, 68, 135, 71, 208, 243, 251, 77, 213, 34, 254, 109, 13, 39, 212, 184, 34, 89, 226, 2, 79, 106, 170, 154, 58, 85, 40, 209, 34, 150, 24, 177, 54, 31, 249, 147, 148, 149, 248, 240, 136, 182, 117, 43, 145, 161, 46, 29, 127, 84, 116, 57, 198, 9, 165, 227, 86, 98, 195, 202, 55, 65, 209, 59, 179, 149, 8, 81, 141, 217, 74, 100, 240, 8, 132, 103, 173, 196, 133, 182, 93, 170, 37, 99, 156, 144, 246, 91, 43, 81, 226, 43, 250, 168, 53, 187, 18, 29, 238, 140, 118, 37, 46, 90, 221, 82, 7, 81, 56, 169, 83, 61, 119, 113, 179, 18, 27, 60, 242, 48, 251, 173, 43, 209, 161, 180, 211, 113, 164, 141, 43, 86, 166, 149, 8, 33, 73, 233, 24, 155, 76, 1, 8, 34, 16, 225, 153, 108, 133, 22, 248, 39, 107, 102, 208, 36, 146, 248, 240, 230, 110, 69, 147, 72, 162, 99, 87, 66, 147, 72, 226, 226, 93, 223, 4, 109, 84, 201, 72, 34, 68, 215, 146, 223, 155, 200, 240, 8, 132, 135, 157, 196, 133, 75, 152, 157, 68, 134, 166, 18, 126, 132, 178, 185, 73, 148, 208, 201, 174, 116, 170, 18, 7, 245, 92, 208, 55, 109, 18, 29, 169, 154, 54, 137, 12, 106, 187, 65, 77, 226, 226, 249, 109, 143, 49, 78, 200, 191, 211, 73, 168, 73, 156, 144, 96, 2, 8, 80, 107, 203, 36, 54, 214, 122, 14, 210, 182, 12, 147, 248, 240, 8, 114, 77, 100, 104, 125, 247, 116, 82, 133, 92, 19, 27, 82, 123, 156, 105, 226, 162, 249, 179, 181, 105, 131, 150, 93, 223, 116, 87, 66, 76, 19, 27, 184, 173, 64, 76, 37, 46, 34, 72, 64, 173, 75, 37, 50, 90, 85, 242, 66, 46, 153, 166, 126, 236, 232, 253, 69, 84, 98, 3, 119, 109, 165, 18, 27, 88, 106, 191, 35, 165, 18, 29, 186, 158, 119, 196, 143, 42, 14, 41, 149, 248, 224, 173, 78, 250, 100, 72, 169, 68, 136, 183, 46, 236, 53, 164, 109, 23, 82, 42, 17, 162, 181, 233, 251, 46, 244, 77, 39, 138, 24, 43, 164, 84, 34, 3, 73, 74, 183, 40, 5, 45, 246, 14, 122, 117, 79, 164, 84, 162, 3, 74, 37, 42, 232, 92, 175, 105, 137, 86, 170, 68, 136, 54, 217, 252, 222, 208, 252, 153, 252, 49, 11, 163, 202, 68, 235, 187, 84, 137, 150, 42, 102, 72, 39, 20, 191, 146, 197, 252, 205, 159, 218, 9, 249, 131, 174, 37, 83, 227, 253, 148, 248, 200, 79, 137, 10, 174, 253, 62, 149, 73, 251, 249, 206, 128, 4, 109, 242, 93, 177, 243, 202, 22, 248, 55, 101, 186, 84, 63, 39, 219, 174, 1, 149, 218, 206, 209, 39, 141, 44, 60, 209, 252, 217, 233, 212, 81, 218, 86, 246, 154, 42, 110, 142, 111, 202, 90, 179, 238, 137, 86, 166, 109, 120, 57, 144, 172, 164, 160, 138, 71, 28, 242, 149, 69, 120, 227, 253, 86, 247, 100, 219, 64, 165, 58, 173, 140, 165, 195, 184, 25, 228, 13, 125, 179, 171, 104, 219, 230, 45, 135, 36, 224, 10, 241, 205, 142, 45, 74, 203, 178, 61, 138, 194, 213, 210, 101, 144, 123, 174, 36, 241, 109, 155, 93, 80, 107, 78, 137, 16, 143, 160, 166, 237, 183, 199, 139, 249, 81, 171, 227, 165, 19, 85, 232, 249, 93, 187, 172, 3, 238, 154, 82, 98, 131, 47, 90, 189, 211, 33, 109, 242, 53, 45, 23, 98, 240, 78, 83, 74, 100, 104, 20, 86, 75, 39, 186, 208, 167, 236, 247, 37, 81, 194, 249, 116, 72, 255, 45, 246, 37, 177, 193, 151, 68, 5, 107, 45, 243, 44, 118, 168, 117, 45, 238, 111, 156, 190, 121, 73, 116, 176, 216, 17, 63, 218, 37, 209, 209, 170, 56, 169, 66, 187, 36, 62, 150, 92, 18, 21, 214, 74, 166, 245, 147, 130, 82, 123, 28, 37, 66, 232, 106, 90, 110, 63, 106, 118, 65, 137, 14, 136, 10, 120, 8, 235, 160, 227, 89, 144, 210, 86, 10, 59, 164, 106, 29, 124, 136, 32, 65, 61, 23, 180, 14, 54, 30, 117, 208, 241, 84, 212, 65, 5, 181, 92, 81, 7, 25, 214, 254, 107, 52, 188, 156, 89, 236, 74, 136, 43, 234, 32, 35, 151, 166, 35, 84, 212, 65, 70, 82, 21, 161, 162, 14, 46, 114, 105, 26, 241, 163, 138, 58, 248, 88, 154, 70, 21, 117, 112, 81, 81, 7, 31, 180, 162, 16, 223, 180, 97, 37, 244, 36, 220, 234, 112, 187, 5, 144, 43, 107, 117, 176, 65, 91, 29, 84, 80, 13, 124, 80, 134, 220, 82, 7, 23, 206, 29, 109, 147, 177, 114, 231, 78, 72, 226, 149, 45, 117, 144, 65, 162, 188, 129, 215, 82, 7, 37, 90, 155, 134, 87, 132, 71, 214, 74, 197, 86, 29, 132, 120, 90, 70, 72, 171, 14, 50, 158, 73, 170, 131, 11, 142, 61, 229, 82, 29, 100, 56, 5, 143, 64, 96, 204, 221, 208, 12, 212, 51, 33, 124, 168, 131, 1, 136, 44, 140, 92, 215, 58, 192, 239, 235, 160, 86, 14, 66, 60, 42, 81, 14, 46, 248, 226, 160, 2, 9, 37, 29, 84, 208, 182, 222, 58, 73, 7, 27, 159, 14, 42, 88, 253, 60, 157, 236, 231, 233, 160, 227, 61, 29, 116, 76, 188, 167, 98, 136, 127, 177, 119, 16, 127, 4, 37, 187, 65, 210, 118, 33, 9, 163, 71, 241, 130, 124, 31, 60, 159, 14, 3, 165, 74, 233, 194, 20, 121, 58, 40, 209, 180, 109, 199, 211, 65, 134, 75, 182, 112, 124, 155, 182, 143, 198, 203, 224, 119, 225, 84, 161, 102, 6, 57, 158, 14, 66, 218, 46, 158, 14, 50, 180, 206, 71, 223, 202, 73, 67, 21, 167, 109, 175, 201, 231, 175, 160, 38, 31, 241, 35, 79, 7, 39, 42, 200, 211, 65, 10, 167, 170, 80, 163, 48, 242, 116, 16, 242, 172, 198, 200, 39, 236, 32, 79, 7, 27, 143, 133, 87, 211, 236, 208, 228, 98, 60, 29, 148, 112, 79, 7, 31, 46, 97, 118, 80, 106, 143, 63, 172, 183, 68, 158, 14, 50, 60, 29, 84, 240, 73, 23, 163, 141, 158, 198, 172, 211, 193, 7, 138, 79, 71, 117, 58, 184, 208, 70, 170, 211, 65, 135, 116, 176, 161, 211, 65, 135, 36, 165, 123, 156, 75, 7, 27, 188, 16, 216, 185, 116, 144, 1, 89, 208, 84, 194, 143, 90, 59, 117, 89, 151, 14, 50, 88, 151, 14, 42, 120, 68, 21, 55, 228, 116, 45, 249, 141, 125, 237, 63, 136, 119, 141, 60, 184, 132, 178, 108, 230, 1, 239, 92, 28, 77, 91, 231, 17, 66, 252, 45, 87, 129, 103, 233, 96, 163, 105, 171, 58, 29, 71, 207, 210, 193, 6, 143, 180, 50, 150, 14, 50, 60, 178, 88, 58, 200, 224, 173, 77, 191, 133, 165, 131, 14, 143, 32, 9, 14, 46, 72, 112, 48, 0, 174, 238, 105, 40, 170, 68, 112, 16, 18, 129, 35, 56, 168, 208, 234, 220, 86, 52, 184, 216, 138, 6, 27, 186, 60, 201, 144, 219, 138, 246, 26, 132, 52, 188, 22, 206, 47, 115, 253, 109, 231, 16, 220, 86, 108, 82, 246, 159, 43, 114, 136, 192, 48, 76, 137, 192, 252, 35, 183, 158, 191, 190, 203, 103, 104, 243, 123, 51, 241, 102, 226, 223, 152, 105, 38, 30, 193, 27, 167, 93, 192, 252, 71, 104, 38, 148, 116, 90, 177, 222, 88, 75, 29, 255, 182, 11, 185, 167, 187, 167, 191, 126, 52, 207, 113, 115, 83, 199, 109, 89, 43, 99, 136, 135, 170, 140, 52, 168, 243, 104, 125, 102, 6, 162, 107, 153, 10, 131, 252, 134, 3, 183, 108, 238, 109, 153, 187, 123, 66, 159, 169, 241, 131, 54, 94, 134, 67, 75, 93, 234, 204, 17, 74, 155, 150, 14, 68, 45, 93, 114, 113, 56, 37, 145, 91, 175, 193, 7, 183, 94, 131, 10, 239, 182, 147, 218, 215, 224, 131, 187, 190, 6, 33, 77, 37, 252, 13, 50, 56, 227, 43, 250, 18, 109, 89, 51, 241, 111, 187, 116, 61, 255, 208, 40, 233, 124, 45, 117, 252, 209, 94, 55, 60, 204, 62, 67, 180, 105, 17, 173, 20, 109, 78, 98, 214, 171, 36, 108, 89, 6, 13, 47, 244, 164, 108, 116, 37, 235, 148, 60, 18, 43, 143, 36, 173, 168, 99, 210, 212, 73, 159, 148, 230, 185, 167, 183, 55, 97, 194, 93, 151, 71, 34, 190, 173, 227, 145, 182, 76, 155, 100, 187, 108, 177, 95, 224, 157, 139, 131, 182, 204, 253, 113, 156, 208, 103, 106, 20, 12, 90, 234, 74, 104, 217, 254, 137, 198, 105, 87, 106, 60, 204, 66, 44, 93, 114, 121, 72, 248, 183, 215, 13, 54, 88, 148, 226, 82, 195, 200, 79, 149, 175, 12, 37, 215, 13, 82, 36, 215, 13, 42, 60, 12, 139, 194, 221, 224, 130, 62, 125, 19, 144, 210, 6, 111, 58, 145, 123, 220, 13, 58, 156, 65, 18, 146, 196, 171, 169, 118, 131, 13, 109, 242, 155, 166, 86, 135, 158, 252, 156, 48, 42, 118, 194, 157, 146, 65, 104, 112, 10, 90, 19, 90, 155, 124, 120, 242, 160, 212, 129, 7, 109, 25, 85, 170, 161, 105, 188, 220, 163, 221, 170, 74, 25, 212, 128, 164, 153, 65, 190, 152, 223, 117, 127, 153, 31, 173, 9, 12, 36, 233, 45, 135, 154, 124, 180, 38, 52, 249, 143, 214, 111, 187, 38, 124, 211, 215, 79, 174, 134, 92, 8, 240, 198, 187, 60, 6, 90, 153, 105, 139, 212, 59, 221, 2, 190, 109, 89, 211, 214, 185, 100, 238, 251, 128, 0, 10, 224, 224, 81, 73, 131, 84, 28, 249, 141, 60, 244, 83, 33, 246, 133, 112, 255, 78, 101, 151, 58, 13, 174, 16, 174, 150, 46, 35, 65, 0, 157, 236, 39, 221, 236, 247, 198, 13, 180, 7, 28, 212, 215, 4, 237, 156, 104, 117, 254, 57, 208, 86, 135, 242, 180, 68, 16, 107, 194, 226, 105, 120, 177, 99, 217, 197, 88, 19, 214, 65, 186, 246, 161, 245, 127, 151, 115, 164, 76, 35, 22, 115, 114, 92, 118, 131, 11, 60, 226, 234, 178, 27, 100, 36, 75, 80, 227, 91, 118, 131, 11, 142, 223, 85, 118, 131, 140, 166, 173, 174, 202, 110, 240, 97, 61, 70, 83, 118, 131, 12, 95, 151, 175, 234, 56, 63, 183, 147, 104, 117, 217, 201, 209, 147, 203, 125, 74, 237, 136, 10, 47, 46, 217, 186, 68, 238, 146, 185, 100, 143, 101, 215, 130, 74, 54, 14, 255, 198, 204, 4, 3, 23, 64, 197, 153, 129, 202, 107, 187, 28, 240, 5, 114, 146, 17, 212, 64, 235, 90, 231, 188, 82, 131, 167, 179, 95, 34, 93, 205, 132, 86, 168, 190, 9, 222, 160, 139, 189, 113, 66, 138, 185, 65, 136, 98, 110, 80, 97, 57, 114, 80, 135, 92, 87, 86, 52, 110, 240, 209, 111, 53, 168, 208, 94, 163, 111, 53, 184, 112, 167, 10, 65, 30, 102, 151, 175, 6, 23, 77, 37, 252, 13, 24, 70, 255, 56, 66, 125, 185, 57, 92, 219, 50, 170, 208, 132, 250, 114, 67, 45, 183, 81, 184, 23, 180, 242, 83, 54, 131, 150, 175, 6, 25, 104, 26, 94, 13, 46, 248, 66, 69, 155, 23, 218, 114, 228, 89, 24, 90, 43, 158, 117, 222, 225, 137, 21, 242, 133, 86, 236, 202, 166, 161, 165, 173, 189, 159, 88, 233, 192, 88, 121, 4, 173, 244, 94, 133, 86, 246, 42, 180, 82, 61, 151, 8, 11, 175, 6, 27, 142, 231, 114, 180, 240, 106, 28, 144, 71, 196, 90, 137, 22, 94, 13, 50, 22, 94, 13, 42, 248, 227, 70, 51, 203, 213, 32, 3, 203, 213, 160, 66, 132, 164, 19, 180, 26, 92, 172, 253, 167, 253, 190, 162, 95, 209, 79, 201, 244, 243, 229, 61, 75, 237, 7, 253, 124, 134, 146, 160, 34, 184, 74, 214, 57, 90, 13, 62, 32, 42, 188, 160, 213, 96, 131, 146, 208, 250, 159, 201, 209, 106, 16, 242, 249, 38, 160, 213, 224, 66, 69, 80, 143, 87, 250, 182, 236, 208, 106, 240, 65, 73, 120, 94, 238, 121, 57, 199, 181, 178, 221, 136, 64, 66, 132, 79, 134, 86, 131, 139, 93, 17, 92, 178, 79, 117, 208, 106, 16, 210, 186, 214, 53, 232, 128, 23, 6, 173, 6, 25, 148, 132, 213, 160, 67, 69, 232, 199, 15, 81, 18, 180, 113, 66, 171, 193, 134, 146, 224, 90, 73, 180, 26, 108, 172, 6, 3, 176, 250, 253, 54, 200, 208, 240, 250, 109, 54, 33, 7, 100, 96, 166, 237, 111, 131, 139, 70, 8, 10, 118, 218, 200, 129, 223, 166, 159, 123, 66, 220, 204, 132, 90, 251, 22, 200, 186, 68, 14, 100, 104, 20, 86, 191, 13, 46, 152, 151, 223, 86, 127, 173, 254, 148, 54, 74, 58, 9, 8, 210, 97, 120, 147, 143, 214, 119, 194, 0, 132, 178, 108, 204, 180, 69, 236, 26, 86, 63, 212, 182, 217, 102, 164, 207, 108, 129, 182, 93, 232, 37, 14, 169, 212, 142, 240, 95, 198, 56, 33, 74, 182, 122, 55, 180, 145, 210, 109, 144, 226, 125, 151, 36, 37, 250, 109, 208, 65, 151, 223, 6, 33, 21, 12, 206, 167, 67, 191, 13, 62, 184, 108, 10, 179, 13, 46, 60, 130, 62, 61, 102, 27, 108, 232, 74, 235, 204, 54, 200, 96, 182, 193, 71, 67, 227, 253, 109, 205, 162, 119, 118, 26, 116, 248, 182, 11, 65, 218, 74, 90, 157, 6, 23, 206, 191, 116, 26, 100, 112, 109, 210, 33, 167, 65, 198, 115, 131, 156, 6, 25, 28, 244, 77, 208, 130, 102, 244, 21, 253, 215, 6, 35, 94, 27, 108, 56, 191, 54, 184, 144, 146, 189, 54, 200, 160, 22, 233, 242, 254, 241, 227, 175, 13, 78, 248, 107, 131, 14, 14, 90, 151, 109, 242, 116, 249, 91, 253, 182, 223, 194, 155, 78, 196, 212, 121, 244, 140, 155, 65, 139, 23, 246, 16, 160, 173, 250, 70, 106, 71, 175, 13, 46, 94, 27, 140, 168, 44, 163, 237, 28, 223, 236, 216, 105, 163, 70, 2, 241, 165, 149, 117, 150, 237, 96, 166, 45, 122, 109, 16, 194, 159, 111, 117, 173, 236, 53, 69, 141, 194, 232, 181, 65, 3, 176, 211, 230, 198, 12, 189, 54, 184, 64, 27, 100, 252, 50, 164, 245, 182, 253, 109, 157, 79, 135, 84, 123, 249, 169, 144, 54, 216, 144, 159, 10, 185, 67, 30, 95, 241, 156, 52, 137, 181, 50, 161, 215, 6, 31, 92, 27, 116, 192, 48, 251, 172, 13, 46, 92, 83, 50, 175, 140, 181, 193, 137, 101, 23, 107, 131, 12, 63, 113, 168, 182, 20, 109, 135, 246, 240, 252, 66, 164, 118, 34, 214, 6, 23, 250, 187, 144, 91, 214, 6, 29, 204, 91, 88, 27, 100, 168, 120, 196, 218, 32, 67, 106, 143, 55, 109, 112, 209, 180, 193, 71, 123, 76, 211, 6, 25, 22, 179, 131, 164, 109, 208, 207, 245, 185, 92, 235, 90, 94, 154, 23, 240, 240, 149, 247, 231, 133, 91, 66, 53, 83, 220, 211, 61, 239, 128, 61, 210, 0, 70, 108, 132, 153, 54, 200, 208, 58, 217, 86, 44, 73, 218, 224, 99, 73, 246, 92, 27, 121, 106, 144, 194, 53, 53, 232, 104, 185, 238, 47, 27, 100, 104, 243, 178, 193, 133, 8, 19, 180, 0, 9, 14, 241, 149, 71, 254, 188, 176, 131, 86, 73, 51, 69, 211, 78, 90, 221, 147, 54, 253, 28, 131, 7, 237, 142, 252, 155, 54, 94, 8, 112, 117, 60, 151, 103, 63, 210, 212, 204, 28, 128, 194, 39, 112, 69, 5, 240, 220, 149, 12, 168, 226, 54, 177, 43, 161, 103, 241, 207, 6, 29, 13, 54, 36, 99, 217, 224, 130, 191, 79, 185, 178, 65, 134, 182, 93, 234, 214, 161, 6, 1, 4, 13, 54, 248, 67, 134, 163, 69, 13, 46, 52, 8, 0, 4, 121, 42, 42, 30, 131, 11, 107, 229, 82, 81, 241, 24, 100, 248, 91, 14, 61, 180, 109, 181, 178, 162, 226, 49, 232, 96, 148, 196, 65, 109, 249, 31, 131, 15, 100, 216, 126, 12, 42, 60, 21, 110, 151, 172, 213, 181, 199, 96, 131, 79, 210, 65, 78, 161, 218, 143, 148, 54, 90, 249, 64, 89, 54, 8, 202, 178, 45, 112, 204, 75, 181, 93, 16, 54, 40, 203, 182, 214, 99, 16, 242, 210, 162, 181, 30, 131, 12, 119, 207, 160, 130, 123, 6, 39, 220, 51, 168, 160, 45, 197, 25, 92, 96, 206, 32, 164, 169, 118, 114, 6, 23, 17, 156, 65, 5, 206, 167, 91, 169, 13, 193, 25, 124, 64, 112, 6, 27, 217, 95, 81, 8, 206, 32, 67, 125, 153, 254, 54, 5, 57, 131, 20, 142, 233, 35, 103, 112, 225, 206, 96, 131, 65, 135, 191, 229, 22, 143, 74, 26, 187, 94, 37, 97, 200, 25, 132, 104, 109, 90, 25, 114, 6, 27, 146, 148, 238, 53, 130, 156, 65, 7, 68, 246, 51, 82, 123, 60, 101, 114, 20, 161, 107, 25, 244, 56, 228, 12, 66, 188, 98, 45, 238, 228, 72, 53, 53, 81, 77, 23, 208, 250, 159, 12, 125, 227, 102, 16, 242, 136, 192, 184, 25, 92, 96, 220, 12, 42, 60, 139, 111, 51, 200, 224, 184, 54, 147, 200, 225, 155, 157, 106, 51, 200, 208, 102, 208, 145, 90, 182, 164, 153, 242, 144, 218, 227, 13, 212, 13, 170, 243, 53, 202, 178, 25, 116, 120, 4, 66, 51, 248, 72, 217, 12, 42, 52, 248, 35, 199, 224, 66, 51, 82, 45, 145, 99, 176, 225, 250, 235, 16, 190, 54, 153, 70, 168, 246, 152, 193, 5, 165, 170, 147, 210, 204, 224, 131, 71, 152, 177, 15, 173, 220, 214, 79, 134, 36, 43, 33, 89, 93, 75, 170, 117, 228, 167, 82, 197, 13, 229, 167, 98, 205, 12, 54, 172, 253, 247, 104, 173, 255, 233, 208, 179, 32, 7, 79, 74, 150, 12, 106, 245, 123, 112, 88, 182, 60, 111, 192, 179, 191, 162, 19, 40, 63, 85, 196, 38, 118, 79, 196, 154, 25, 124, 240, 0, 55, 228, 175, 128, 102, 6, 31, 205, 191, 141, 217, 195, 55, 109, 18, 53, 180, 78, 22, 45, 153, 106, 143, 187, 209, 102, 6, 226, 164, 212, 102, 6, 23, 78, 85, 33, 6, 207, 183, 162, 102, 6, 35, 248, 121, 225, 70, 223, 152, 193, 136, 95, 201, 55, 102, 112, 129, 190, 49, 131, 16, 95, 204, 32, 132, 174, 124, 201, 98, 6, 25, 15, 179, 141, 86, 181, 152, 193, 135, 203, 126, 228, 47, 113, 219, 245, 111, 129, 55, 222, 119, 204, 192, 61, 238, 6, 249, 75, 204, 224, 3, 66, 99, 112, 161, 44, 27, 106, 12, 46, 42, 111, 49, 72, 81, 121, 139, 65, 5, 93, 75, 254, 54, 165, 65, 194, 29, 127, 139, 65, 7, 87, 251, 22, 131, 12, 74, 221, 243, 142, 119, 154, 93, 142, 29, 84, 203, 133, 32, 32, 174, 238, 121, 68, 225, 197, 60, 40, 218, 46, 136, 194, 139, 65, 198, 243, 98, 80, 225, 87, 178, 152, 31, 185, 93, 12, 66, 158, 95, 73, 218, 197, 32, 163, 149, 97, 158, 35, 130, 218, 110, 42, 188, 84, 116, 49, 8, 233, 214, 73, 46, 6, 23, 249, 169, 80, 69, 191, 117, 130, 38, 154, 210, 239, 247, 207, 197, 224, 194, 63, 23, 131, 15, 117, 82, 38, 71, 46, 6, 29, 62, 23, 131, 10, 222, 228, 98, 112, 193, 61, 33, 108, 88, 107, 37, 12, 46, 236, 67, 79, 69, 197, 50, 232, 16, 241, 48, 219, 239, 43, 203, 96, 35, 2, 146, 208, 181, 228, 163, 252, 84, 72, 105, 101, 25, 132, 120, 254, 151, 193, 133, 167, 213, 241, 101, 112, 241, 222, 203, 160, 4, 107, 166, 48, 124, 49, 127, 131, 182, 76, 105, 59, 190, 109, 25, 100, 68, 240, 8, 58, 40, 109, 203, 224, 66, 107, 91, 6, 185, 247, 136, 240, 187, 170, 45, 131, 12, 17, 158, 185, 37, 205, 20, 212, 58, 159, 7, 206, 47, 69, 223, 202, 137, 195, 61, 215, 181, 228, 166, 47, 224, 202, 178, 161, 119, 253, 103, 110, 120, 234, 197, 51, 55, 130, 52, 18, 70, 175, 66, 223, 180, 31, 26, 123, 4, 69, 60, 73, 65, 15, 83, 198, 14, 202, 73, 70, 28, 90, 61, 162, 162, 202, 225, 13, 174, 203, 150, 46, 80, 109, 25, 124, 168, 182, 12, 42, 56, 67, 169, 147, 30, 63, 122, 245, 6, 252, 37, 102, 32, 244, 115, 189, 180, 50, 81, 120, 4, 107, 102, 208, 202, 182, 12, 58, 34, 11, 59, 24, 43, 180, 14, 212, 161, 245, 215, 50, 8, 89, 107, 25, 180, 214, 50, 171, 237, 146, 9, 53, 109, 215, 50, 148, 79, 169, 253, 224, 17, 173, 88, 103, 188, 58, 69, 119, 162, 237, 144, 54, 201, 214, 1, 117, 207, 107, 197, 58, 82, 118, 186, 150, 193, 2, 172, 126, 200, 225, 97, 150, 101, 83, 58, 105, 245, 6, 186, 150, 193, 5, 222, 119, 49, 84, 123, 236, 120, 4, 66, 91, 78, 143, 213, 207, 249, 116, 136, 31, 109, 63, 8, 117, 207, 79, 124, 190, 86, 108, 227, 25, 78, 122, 71, 67, 30, 30, 89, 60, 157, 109, 23, 228, 219, 120, 189, 233, 59, 72, 154, 153, 230, 207, 182, 21, 169, 144, 191, 111, 229, 193, 211, 223, 20, 194, 191, 233, 90, 6, 27, 116, 45, 131, 10, 174, 253, 154, 101, 112, 241, 186, 154, 101, 144, 97, 2, 147, 10, 168, 226, 86, 1, 111, 93, 150, 65, 7, 247, 164, 146, 23, 106, 24, 116, 64, 52, 234, 24, 195, 32, 131, 126, 46, 134, 65, 134, 117, 217, 208, 50, 12, 50, 158, 126, 109, 10, 7, 253, 85, 220, 36, 36, 137, 153, 195, 53, 246, 200, 3, 31, 28, 63, 108, 103, 211, 148, 193, 197, 243, 207, 201, 145, 123, 72, 25, 82, 170, 12, 70, 40, 85, 6, 21, 210, 73, 202, 224, 194, 4, 174, 8, 37, 92, 194, 236, 32, 95, 208, 234, 124, 42, 131, 13, 189, 138, 65, 5, 197, 96, 0, 180, 241, 74, 12, 50, 252, 194, 160, 2, 135, 32, 143, 44, 12, 54, 120, 100, 97, 80, 97, 97, 176, 209, 146, 45, 12, 62, 22, 6, 3, 160, 79, 50, 232, 160, 79, 50, 168, 224, 141, 211, 78, 146, 193, 6, 19, 22, 212, 59, 221, 210, 181, 178, 211, 45, 74, 105, 218, 182, 78, 74, 211, 36, 197, 117, 45, 235, 77, 29, 61, 204, 62, 203, 105, 163, 135, 217, 135, 217, 167, 68, 148, 45, 117, 30, 197, 11, 107, 102, 90, 87, 194, 238, 218, 204, 250, 195, 236, 195, 90, 201, 244, 87, 244, 223, 117, 173, 100, 78, 128, 119, 141, 80, 7, 58, 33, 73, 187, 210, 51, 47, 207, 188, 48, 88, 133, 165, 246, 251, 231, 35, 151, 108, 229, 155, 160, 18, 233, 202, 164, 163, 247, 93, 238, 213, 145, 210, 247, 100, 40, 143, 180, 53, 245, 94, 160, 21, 203, 76, 25, 196, 29, 243, 122, 79, 102, 226, 97, 118, 45, 249, 190, 128, 147, 62, 146, 182, 149, 189, 230, 235, 176, 240, 106, 26, 204, 44, 227, 43, 223, 4, 125, 48, 204, 170, 135, 7, 19, 103, 164, 8, 18, 82, 167, 135, 36, 169, 147, 84, 219, 165, 241, 158, 12, 58, 28, 79, 135, 117, 50, 200, 208, 212, 201, 224, 66, 227, 180, 239, 249, 45, 25, 124, 188, 235, 59, 26, 94, 13, 207, 73, 203, 132, 158, 212, 146, 65, 200, 163, 190, 146, 65, 134, 165, 76, 174, 100, 112, 209, 42, 73, 6, 23, 154, 124, 198, 162, 148, 86, 36, 201, 160, 131, 63, 4, 199, 234, 109, 208, 211, 252, 41, 25, 132, 52, 164, 237, 37, 25, 100, 112, 125, 20, 21, 152, 111, 219, 206, 191, 162, 232, 80, 10, 225, 182, 226, 43, 250, 12, 72, 82, 190, 191, 99, 136, 235, 90, 166, 193, 29, 31, 11, 175, 230, 43, 138, 139, 230, 95, 229, 234, 15, 173, 140, 230, 110, 136, 8, 11, 100, 88, 57, 81, 212, 120, 31, 26, 191, 183, 165, 52, 71, 52, 222, 213, 79, 194, 93, 87, 123, 221, 192, 109, 69, 131, 210, 126, 190, 63, 204, 46, 119, 135, 135, 150, 186, 152, 151, 214, 127, 220, 200, 87, 238, 119, 186, 230, 7, 206, 178, 211, 33, 6, 52, 94, 119, 117, 180, 38, 248, 195, 22, 52, 109, 155, 134, 151, 127, 91, 118, 170, 41, 122, 223, 197, 224, 41, 145, 198, 251, 201, 17, 6, 173, 191, 150, 113, 11, 225, 254, 27, 144, 36, 117, 146, 243, 43, 213, 65, 238, 218, 203, 195, 59, 151, 7, 199, 115, 49, 154, 118, 162, 74, 255, 117, 131, 243, 47, 37, 22, 80, 224, 98, 229, 68, 81, 187, 138, 98, 227, 97, 150, 161, 238, 223, 19, 79, 136, 191, 193, 117, 45, 131, 16, 134, 97, 73, 202, 5, 173, 220, 138, 226, 132, 235, 167, 114, 15, 34, 81, 142, 90, 39, 173, 254, 72, 138, 115, 135, 198, 30, 121, 216, 149, 24, 253, 214, 210, 152, 44, 94, 221, 29, 187, 154, 182, 46, 17, 187, 138, 34, 132, 210, 5, 30, 129, 192, 43, 209, 170, 175, 206, 61, 136, 119, 154, 109, 202, 147, 203, 69, 104, 51, 123, 124, 66, 216, 232, 212, 231, 161, 106, 45, 4, 31, 176, 209, 204, 86, 20, 23, 60, 130, 152, 173, 40, 46, 124, 93, 27, 173, 40, 106, 188, 14, 142, 181, 210, 241, 5, 164, 149, 97, 222, 130, 146, 86, 20, 31, 8, 73, 70, 81, 84, 120, 84, 194, 21, 112, 19, 69, 135, 229, 181, 227, 168, 169, 118, 211, 58, 81, 124, 208, 212, 143, 31, 173, 77, 223, 119, 61, 188, 211, 228, 106, 23, 17, 248, 217, 58, 142, 94, 155, 206, 143, 88, 158, 47, 207, 65, 252, 243, 33, 28, 243, 146, 104, 114, 33, 199, 188, 248, 147, 58, 111, 139, 28, 51, 133, 254, 46, 199, 175, 164, 225, 128, 13, 75, 211, 113, 217, 72, 39, 138, 15, 157, 40, 42, 200, 137, 98, 3, 77, 20, 29, 107, 255, 183, 61, 135, 243, 138, 13, 103, 120, 93, 43, 41, 200, 35, 107, 255, 61, 36, 215, 239, 250, 223, 30, 167, 36, 177, 75, 34, 143, 56, 232, 98, 152, 164, 44, 78, 252, 220, 46, 130, 61, 109, 117, 94, 241, 161, 242, 107, 255, 161, 102, 29, 226, 188, 162, 131, 243, 138, 141, 101, 23, 114, 94, 113, 209, 192, 147, 107, 212, 216, 35, 200, 121, 197, 9, 207, 6, 57, 175, 8, 225, 164, 87, 84, 104, 242, 21, 21, 242, 21, 21, 180, 74, 86, 82, 144, 42, 226, 71, 250, 86, 78, 148, 101, 243, 125, 160, 226, 17, 164, 214, 190, 101, 129, 147, 242, 63, 209, 218, 127, 12, 44, 66, 137, 133, 65, 13, 174, 232, 96, 182, 239, 138, 12, 190, 114, 191, 169, 187, 162, 227, 117, 49, 169, 11, 109, 187, 34, 164, 117, 162, 237, 138, 11, 87, 108, 60, 173, 111, 130, 43, 46, 22, 198, 225, 32, 217, 182, 115, 231, 138, 12, 139, 194, 206, 21, 23, 12, 179, 205, 21, 25, 92, 81, 130, 185, 98, 131, 185, 162, 2, 85, 1, 134, 147, 62, 41, 19, 190, 246, 95, 3, 7, 255, 124, 117, 156, 156, 189, 7, 158, 88, 33, 93, 175, 181, 57, 121, 171, 106, 15, 41, 213, 134, 190, 177, 66, 143, 209, 98, 79, 132, 123, 133, 87, 81, 36, 30, 102, 95, 223, 68, 169, 191, 246, 56, 109, 123, 254, 168, 4, 125, 179, 163, 2, 36, 86, 62, 81, 177, 28, 98, 197, 79, 103, 47, 187, 80, 211, 246, 93, 223, 1, 101, 50, 189, 235, 75, 208, 95, 58, 89, 192, 64, 146, 212, 73, 107, 169, 243, 111, 246, 214, 133, 41, 67, 205, 62, 0, 143, 116, 54, 246, 215, 200, 35, 45, 147, 47, 224, 145, 74, 47, 208, 171, 92, 215, 235, 136, 246, 190, 9, 13, 158, 92, 77, 54, 233, 168, 242, 148, 131, 202, 83, 218, 58, 217, 207, 230, 18, 102, 231, 129, 190, 137, 74, 109, 231, 173, 140, 182, 43, 64, 197, 178, 125, 199, 173, 147, 130, 158, 213, 184, 242, 154, 42, 110, 74, 43, 246, 183, 165, 183, 135, 184, 249, 107, 39, 117, 196, 205, 129, 59, 230, 133, 184, 105, 219, 213, 22, 113, 123, 160, 210, 77, 115, 224, 89, 141, 17, 55, 148, 78, 98, 150, 78, 98, 6, 191, 235, 129, 0, 130, 68, 21, 143, 48, 72, 141, 61, 210, 180, 117, 141, 184, 70, 36, 36, 176, 140, 248, 242, 156, 223, 134, 129, 244, 232, 219, 46, 7, 62, 25, 72, 224, 234, 11, 212, 73, 217, 52, 90, 225, 87, 229, 158, 212, 181, 254, 235, 210, 114, 137, 168, 44, 195, 255, 82, 123, 76, 231, 122, 77, 75, 180, 44, 219, 26, 38, 42, 138, 53, 60, 64, 0, 85, 220, 222, 53, 194, 128, 1, 60, 119, 37, 234, 214, 127, 150, 106, 186, 205, 60, 157, 140, 61, 95, 114, 253, 54, 168, 245, 211, 171, 67, 83, 58, 71, 92, 225, 138, 99, 94, 77, 227, 126, 119, 224, 252, 82, 18, 240, 41, 181, 27, 168, 120, 4, 45, 192, 96, 153, 250, 2, 206, 101, 131, 79, 169, 45, 0, 6, 204, 174, 196, 19, 95, 209, 70, 225, 145, 133, 145, 104, 26, 141, 88, 128, 0, 212, 115, 65, 75, 91, 122, 19, 61, 240, 68, 8, 209, 94, 1, 116, 153, 85, 218, 222, 1, 218, 34, 117, 207, 51, 208, 169, 90, 190, 47, 96, 239, 32, 199, 119, 45, 207, 61, 104, 187, 34, 222, 245, 25, 120, 45, 25, 82, 7, 86, 182, 214, 175, 164, 179, 227, 118, 40, 89, 210, 1, 44, 80, 45, 123, 145, 104, 118, 215, 148, 18, 37, 86, 174, 184, 64, 29, 39, 87, 100, 120, 0, 85, 242, 219, 227, 3, 72, 219, 175, 12, 185, 162, 0, 158, 37, 215, 74, 10, 138, 104, 218, 168, 226, 228, 138, 141, 124, 50, 185, 34, 131, 42, 78, 219, 158, 131, 163, 168, 232, 231, 130, 44, 246, 206, 227, 147, 27, 164, 174, 201, 237, 206, 132, 240, 193, 73, 159, 108, 61, 84, 229, 202, 228, 138, 140, 8, 18, 144, 51, 79, 10, 36, 130, 9, 144, 115, 123, 222, 26, 193, 4, 77, 29, 75, 188, 54, 93, 17, 76, 144, 156, 211, 21, 193, 4, 238, 150, 49, 136, 96, 2, 214, 57, 193, 58, 35, 72, 64, 149, 215, 118, 65, 68, 48, 1, 82, 190, 168, 54, 35, 17, 193, 4, 172, 147, 34, 130, 9, 80, 91, 74, 167, 138, 136, 96, 2, 214, 137, 22, 168, 181, 111, 113, 197, 133, 251, 226, 133, 61, 14, 182, 142, 163, 9, 92, 145, 241, 234, 104, 2, 138, 9, 92, 241, 49, 129, 163, 9, 92, 113, 129, 38, 112, 69, 8, 154, 192, 21, 27, 216, 58, 142, 36, 112, 69, 134, 175, 101, 217, 34, 9, 92, 241, 193, 87, 20, 73, 224, 18, 92, 145, 225, 233, 156, 32, 87, 92, 232, 100, 127, 217, 182, 67, 252, 206, 214, 241, 214, 138, 46, 228, 138, 15, 142, 107, 51, 200, 21, 25, 207, 210, 10, 47, 72, 177, 243, 202, 92, 241, 129, 207, 70, 187, 105, 18, 185, 162, 132, 119, 43, 42, 184, 36, 229, 251, 67, 146, 242, 93, 34, 87, 235, 132, 27, 248, 164, 17, 132, 56, 94, 221, 138, 12, 221, 138, 10, 92, 50, 164, 43, 39, 251, 38, 40, 74, 52, 110, 210, 157, 226, 194, 35, 206, 138, 11, 173, 146, 180, 174, 165, 242, 108, 172, 72, 128, 198, 30, 65, 252, 14, 222, 15, 19, 64, 128, 26, 40, 123, 42, 154, 34, 3, 51, 109, 39, 77, 113, 241, 48, 59, 105, 58, 105, 138, 11, 166, 113, 154, 52, 197, 133, 218, 149, 139, 166, 109, 255, 164, 41, 54, 38, 77, 209, 177, 9, 77, 154, 34, 195, 195, 44, 123, 77, 113, 193, 94, 83, 84, 64, 198, 147, 221, 137, 16, 109, 126, 111, 138, 139, 102, 120, 4, 130, 246, 190, 9, 77, 209, 161, 79, 223, 132, 166, 184, 112, 201, 154, 226, 130, 242, 230, 95, 223, 9, 210, 212, 210, 225, 133, 0, 225, 107, 255, 61, 144, 193, 249, 165, 32, 87, 77, 27, 181, 92, 213, 20, 27, 190, 169, 106, 138, 12, 12, 35, 213, 20, 27, 250, 63, 145, 106, 138, 14, 173, 56, 53, 221, 231, 70, 219, 132, 186, 182, 116, 25, 137, 104, 20, 86, 168, 105, 171, 56, 53, 197, 134, 212, 20, 27, 106, 129, 12, 204, 181, 136, 94, 133, 26, 207, 59, 166, 184, 160, 205, 9, 65, 190, 213, 61, 41, 236, 152, 226, 66, 43, 214, 211, 113, 76, 177, 209, 180, 101, 234, 252, 67, 235, 164, 213, 29, 34, 26, 239, 51, 83, 92, 188, 239, 66, 254, 208, 198, 140, 101, 87, 98, 168, 104, 163, 237, 160, 158, 75, 99, 35, 204, 152, 195, 35, 140, 141, 48, 83, 132, 120, 24, 170, 147, 162, 239, 168, 245, 91, 223, 127, 153, 226, 194, 47, 83, 108, 120, 58, 221, 151, 41, 50, 150, 250, 227, 206, 132, 114, 45, 76, 209, 65, 23, 59, 172, 153, 34, 73, 204, 34, 92, 50, 73, 42, 197, 251, 121, 58, 175, 239, 232, 93, 223, 51, 105, 47, 200, 8, 106, 38, 222, 160, 235, 121, 95, 253, 144, 3, 77, 253, 216, 27, 183, 245, 8, 212, 250, 143, 251, 31, 247, 131, 252, 84, 104, 2, 9, 64, 144, 152, 110, 38, 123, 226, 183, 189, 9, 168, 149, 194, 174, 213, 57, 118, 144, 39, 85, 74, 214, 233, 250, 125, 164, 77, 58, 8, 118, 198, 202, 129, 82, 150, 141, 129, 166, 203, 147, 204, 91, 43, 86, 37, 175, 6, 141, 247, 83, 34, 149, 240, 164, 237, 250, 182, 76, 91, 138, 238, 4, 181, 213, 110, 128, 31, 49, 218, 206, 107, 227, 164, 127, 120, 147, 139, 65, 19, 44, 43, 234, 218, 182, 105, 218, 224, 141, 215, 87, 189, 58, 184, 67, 228, 167, 114, 142, 39, 53, 142, 96, 236, 158, 90, 149, 101, 67, 106, 87, 78, 152, 105, 223, 118, 33, 95, 9, 103, 235, 184, 195, 111, 123, 19, 208, 174, 244, 180, 182, 67, 187, 146, 3, 238, 233, 157, 29, 218, 149, 156, 79, 71, 177, 203, 95, 221, 217, 58, 142, 118, 37, 109, 178, 151, 161, 133, 216, 149, 10, 64, 225, 197, 72, 154, 41, 72, 130, 63, 80, 107, 223, 242, 240, 130, 104, 64, 27, 164, 138, 39, 34, 9, 173, 90, 251, 28, 240, 7, 208, 50, 104, 210, 161, 199, 65, 90, 247, 92, 169, 129, 0, 30, 210, 122, 46, 20, 252, 47, 162, 217, 5, 46, 145, 120, 210, 22, 189, 74, 82, 246, 130, 90, 23, 166, 168, 0, 9, 48, 255, 32, 46, 189, 4, 69, 178, 157, 64, 30, 113, 104, 198, 135, 92, 127, 124, 41, 46, 216, 82, 148, 120, 215, 71, 108, 41, 131, 103, 7, 177, 165, 184, 96, 75, 209, 145, 246, 25, 90, 177, 238, 118, 45, 197, 134, 71, 36, 75, 113, 129, 101, 66, 204, 82, 92, 168, 246, 63, 148, 254, 190, 212, 155, 208, 211, 89, 128, 125, 19, 165, 168, 88, 111, 224, 224, 111, 57, 136, 171, 147, 62, 217, 131, 3, 247, 92, 9, 97, 67, 107, 107, 235, 28, 125, 203, 70, 151, 226, 3, 101, 66, 63, 223, 17, 133, 85, 91, 10, 123, 203, 223, 17, 90, 177, 157, 207, 109, 162, 234, 97, 105, 74, 137, 188, 65, 203, 93, 84, 53, 102, 140, 19, 122, 224, 164, 87, 198, 33, 98, 61, 90, 215, 98, 224, 53, 101, 104, 65, 227, 254, 164, 75, 145, 225, 216, 83, 15, 85, 220, 32, 152, 75, 132, 13, 42, 188, 176, 68, 162, 216, 208, 170, 146, 29, 223, 118, 33, 143, 40, 50, 42, 218, 104, 35, 85, 111, 165, 182, 200, 35, 138, 17, 30, 81, 84, 240, 172, 144, 202, 119, 181, 52, 194, 168, 182, 147, 85, 156, 144, 64, 1, 8, 32, 112, 171, 8, 209, 234, 164, 79, 10, 106, 26, 69, 77, 163, 200, 248, 134, 180, 159, 239, 174, 235, 169, 70, 17, 210, 180, 117, 62, 93, 227, 239, 108, 144, 36, 102, 205, 159, 207, 237, 208, 52, 218, 52, 138, 15, 218, 140, 199, 38, 212, 52, 138, 12, 109, 23, 212, 52, 138, 139, 111, 220, 140, 34, 67, 243, 39, 101, 24, 69, 70, 195, 11, 169, 34, 195, 123, 47, 131, 84, 145, 209, 186, 255, 218, 14, 241, 35, 7, 8, 241, 198, 251, 171, 20, 25, 77, 91, 165, 248, 120, 223, 133, 158, 212, 52, 101, 68, 37, 226, 71, 174, 141, 82, 108, 208, 234, 164, 246, 114, 33, 109, 148, 98, 131, 78, 250, 165, 8, 74, 145, 161, 147, 126, 73, 145, 193, 117, 73, 146, 178, 147, 20, 25, 204, 32, 197, 69, 91, 60, 130, 82, 82, 100, 48, 109, 81, 124, 44, 182, 40, 58, 22, 91, 20, 21, 158, 138, 84, 124, 168, 98, 143, 167, 190, 67, 146, 242, 221, 37, 123, 196, 227, 169, 206, 209, 250, 120, 42, 54, 56, 175, 150, 210, 114, 61, 223, 83, 209, 193, 61, 33, 111, 218, 122, 42, 62, 190, 105, 227, 84, 116, 248, 151, 58, 21, 25, 218, 73, 169, 184, 224, 142, 219, 33, 39, 165, 162, 67, 157, 27, 21, 94, 22, 243, 67, 188, 179, 35, 177, 50, 241, 66, 139, 226, 6, 234, 158, 82, 133, 210, 178, 108, 143, 66, 7, 253, 93, 217, 30, 133, 140, 86, 198, 22, 229, 68, 97, 163, 173, 82, 73, 219, 245, 224, 200, 35, 239, 79, 161, 131, 55, 26, 239, 103, 63, 133, 140, 86, 73, 82, 39, 45, 224, 97, 86, 66, 132, 70, 43, 3, 85, 116, 185, 167, 144, 194, 61, 133, 10, 36, 233, 41, 84, 80, 247, 188, 194, 5, 228, 175, 176, 225, 213, 21, 42, 40, 100, 104, 227, 10, 199, 173, 144, 225, 17, 8, 216, 112, 215, 245, 204, 182, 194, 6, 210, 181, 150, 146, 173, 208, 193, 196, 17, 37, 91, 97, 131, 54, 45, 91, 33, 67, 171, 36, 101, 63, 106, 178, 21, 66, 26, 94, 12, 143, 60, 120, 4, 66, 171, 3, 57, 107, 192, 118, 177, 119, 208, 55, 187, 138, 82, 120, 4, 130, 201, 86, 216, 160, 36, 112, 202, 86, 184, 96, 202, 41, 84, 120, 102, 29, 111, 248, 231, 59, 82, 201, 235, 153, 27, 169, 202, 110, 26, 133, 21, 58, 60, 217, 157, 254, 187, 32, 93, 203, 99, 133, 15, 221, 127, 254, 93, 206, 159, 21, 62, 126, 155, 103, 133, 16, 101, 210, 31, 15, 170, 165, 171, 104, 195, 174, 132, 28, 200, 224, 19, 208, 179, 66, 6, 93, 75, 254, 99, 108, 145, 227, 150, 112, 220, 206, 191, 211, 53, 26, 123, 132, 21, 50, 158, 21, 42, 80, 198, 105, 41, 5, 45, 185, 152, 23, 102, 133, 17, 173, 191, 73, 97, 172, 84, 106, 51, 86, 200, 120, 152, 237, 231, 24, 43, 108, 112, 91, 198, 10, 25, 154, 177, 211, 84, 81, 198, 10, 33, 234, 158, 103, 172, 208, 65, 226, 249, 15, 116, 144, 128, 177, 66, 133, 8, 24, 43, 84, 240, 213, 15, 49, 86, 200, 208, 38, 25, 43, 132, 60, 90, 43, 118, 229, 182, 58, 98, 172, 208, 65, 91, 46, 215, 88, 118, 49, 86, 248, 224, 190, 96, 172, 176, 33, 57, 255, 131, 104, 205, 174, 68, 140, 21, 54, 212, 223, 178, 66, 134, 117, 217, 176, 66, 6, 95, 251, 207, 161, 205, 9, 85, 36, 86, 216, 168, 72, 172, 80, 161, 43, 137, 21, 54, 84, 18, 43, 84, 104, 205, 186, 162, 214, 172, 191, 196, 10, 29, 26, 239, 103, 195, 55, 101, 47, 177, 194, 7, 174, 238, 249, 196, 10, 25, 146, 102, 6, 61, 157, 205, 142, 233, 35, 109, 219, 159, 88, 97, 131, 196, 159, 88, 33, 195, 174, 132, 30, 102, 31, 30, 129, 224, 164, 78, 245, 196, 10, 33, 239, 56, 177, 66, 6, 85, 220, 96, 170, 152, 65, 214, 50, 18, 234, 172, 146, 196, 10, 29, 20, 50, 190, 242, 200, 155, 194, 197, 171, 36, 177, 35, 111, 10, 29, 78, 122, 101, 180, 29, 242, 166, 144, 162, 91, 39, 140, 188, 41, 100, 160, 154, 74, 82, 46, 104, 127, 61, 166, 154, 66, 134, 98, 10, 21, 76, 150, 66, 5, 173, 173, 89, 71, 108, 37, 10, 31, 147, 136, 66, 5, 169, 61, 174, 180, 105, 157, 172, 66, 198, 186, 68, 149, 237, 79, 134, 86, 225, 132, 175, 77, 166, 72, 215, 146, 232, 32, 95, 23, 228, 17, 8, 15, 235, 18, 169, 230, 228, 171, 48, 98, 211, 73, 232, 249, 94, 133, 142, 231, 129, 102, 100, 240, 163, 94, 133, 13, 189, 10, 31, 252, 232, 115, 105, 218, 42, 148, 240, 8, 4, 110, 109, 171, 176, 241, 174, 205, 42, 108, 72, 237, 49, 171, 94, 99, 217, 215, 197, 48, 171, 112, 209, 146, 173, 165, 14, 210, 101, 152, 85, 232, 176, 150, 100, 152, 85, 216, 176, 216, 59, 17, 24, 102, 21, 54, 156, 244, 233, 16, 195, 172, 66, 8, 134, 89, 133, 10, 45, 149, 61, 126, 212, 42, 116, 172, 90, 229, 104, 120, 229, 42, 124, 104, 218, 254, 42, 69, 159, 180, 87, 161, 7, 30, 65, 44, 187, 201, 85, 232, 240, 199, 210, 214, 210, 73, 8, 37, 92, 50, 228, 224, 142, 92, 133, 141, 85, 24, 0, 150, 221, 40, 92, 72, 70, 161, 2, 221, 138, 42, 92, 64, 134, 39, 117, 14, 241, 8, 210, 180, 19, 85, 40, 209, 40, 172, 40, 236, 76, 120, 218, 95, 176, 214, 190, 9, 72, 153, 246, 255, 183, 108, 208, 68, 21, 66, 168, 147, 50, 121, 68, 75, 71, 143, 111, 77, 19, 85, 184, 208, 183, 114, 162, 10, 23, 107, 189, 134, 38, 170, 144, 225, 22, 77, 84, 33, 67, 133, 95, 21, 46, 80, 76, 224, 138, 116, 178, 13, 78, 122, 252, 19, 191, 30, 190, 217, 45, 72, 203, 174, 71, 211, 182, 181, 74, 190, 161, 116, 173, 124, 111, 11, 241, 92, 227, 208, 181, 204, 131, 194, 139, 105, 157, 112, 131, 164, 175, 10, 29, 214, 230, 171, 66, 7, 75, 190, 42, 92, 232, 119, 85, 174, 220, 248, 192, 35, 16, 92, 21, 50, 168, 194, 198, 202, 55, 65, 21, 50, 124, 179, 35, 119, 238, 84, 161, 163, 241, 62, 40, 186, 147, 247, 93, 72, 39, 251, 217, 6, 192, 237, 16, 133, 210, 207, 164, 237, 84, 161, 67, 181, 255, 193, 113, 217, 205, 190, 150, 120, 16, 66, 57, 85, 78, 21, 50, 156, 42, 108, 52, 109, 209, 243, 235, 77, 21, 74, 60, 204, 170, 226, 166, 10, 27, 250, 240, 203, 118, 169, 66, 7, 111, 232, 103, 163, 75, 21, 50, 244, 115, 61, 164, 216, 149, 208, 82, 133, 139, 165, 10, 21, 44, 188, 26, 85, 200, 208, 252, 217, 218, 180, 81, 133, 143, 199, 168, 66, 5, 103, 84, 125, 46, 70, 21, 58, 30, 134, 81, 133, 11, 141, 194, 74, 105, 183, 106, 51, 248, 81, 43, 163, 10, 33, 190, 105, 147, 168, 213, 159, 218, 247, 22, 187, 182, 47, 240, 36, 69, 63, 155, 7, 181, 8, 37, 180, 105, 101, 13, 199, 83, 125, 218, 254, 136, 111, 246, 86, 127, 86, 182, 68, 234, 56, 249, 132, 63, 42, 65, 202, 178, 105, 67, 252, 81, 9, 114, 201, 26, 92, 50, 223, 197, 167, 237, 119, 36, 49, 129, 43, 82, 109, 70, 53, 253, 202, 163, 85, 53, 163, 167, 37, 106, 13, 32, 86, 62, 199, 154, 160, 12, 134, 89, 133, 156, 170, 194, 134, 219, 10, 7, 183, 21, 237, 85, 52, 16, 17, 42, 150, 136, 206, 119, 80, 133, 141, 237, 71, 193, 48, 251, 15, 85, 156, 84, 225, 0, 60, 2, 65, 209, 177, 26, 8, 146, 164, 10, 23, 239, 52, 187, 16, 132, 71, 32, 172, 100, 155, 84, 161, 195, 31, 149, 160, 7, 85, 170, 112, 209, 240, 98, 248, 227, 245, 150, 100, 144, 67, 243, 22, 85, 184, 128, 16, 169, 61, 158, 170, 112, 225, 82, 21, 42, 72, 218, 46, 149, 170, 144, 241, 77, 85, 91, 164, 10, 27, 205, 91, 20, 42, 40, 237, 116, 60, 162, 113, 13, 107, 130, 63, 12, 233, 162, 16, 194, 23, 133, 13, 165, 21, 79, 42, 100, 72, 255, 32, 60, 242, 164, 194, 5, 95, 251, 79, 105, 63, 228, 44, 241, 167, 66, 7, 60, 162, 159, 10, 25, 60, 2, 65, 63, 149, 67, 217, 126, 131, 194, 141, 225, 79, 170, 93, 236, 168, 119, 58, 111, 76, 132, 210, 214, 247, 212, 135, 186, 182, 117, 18, 68, 169, 239, 68, 27, 237, 202, 166, 233, 66, 145, 246, 149, 57, 191, 253, 160, 159, 10, 27, 182, 95, 126, 42, 92, 68, 224, 11, 250, 164, 75, 125, 65, 171, 106, 214, 166, 112, 63, 112, 143, 187, 161, 112, 171, 6, 34, 240, 5, 57, 160, 147, 125, 160, 85, 165, 58, 74, 43, 203, 188, 138, 120, 21, 193, 2, 190, 160, 7, 222, 248, 255, 49, 136, 64, 194, 23, 244, 218, 32, 68, 224, 11, 98, 96, 173, 101, 248, 95, 162, 6, 175, 13, 130, 131, 75, 150, 159, 10, 25, 158, 182, 95, 25, 106, 88, 121, 4, 97, 132, 175, 126, 13, 109, 126, 119, 172, 75, 148, 159, 10, 31, 246, 53, 16, 62, 21, 46, 158, 167, 66, 5, 143, 56, 158, 10, 25, 30, 102, 29, 79, 133, 11, 173, 216, 86, 199, 83, 97, 227, 61, 145, 227, 169, 144, 209, 169, 176, 225, 77, 75, 90, 42, 100, 180, 54, 45, 21, 50, 180, 213, 119, 188, 233, 68, 23, 122, 217, 202, 82, 225, 132, 71, 22, 18, 20, 98, 104, 55, 169, 112, 193, 37, 67, 77, 42, 92, 68, 48, 129, 66, 5, 203, 141, 155, 39, 72, 130, 66, 135, 99, 104, 134, 131, 178, 125, 151, 78, 218, 71, 18, 186, 50, 57, 146, 160, 144, 241, 168, 164, 165, 187, 190, 9, 142, 70, 27, 73, 80, 216, 208, 208, 167, 111, 130, 106, 191, 202, 55, 1, 73, 80, 248, 104, 220, 60, 139, 29, 146, 160, 208, 225, 124, 186, 207, 197, 78, 130, 114, 180, 93, 42, 234, 32, 9, 10, 27, 159, 172, 161, 169, 217, 73, 175, 12, 146, 160, 144, 161, 158, 138, 36, 40, 92, 76, 220, 249, 62, 217, 94, 46, 85, 72, 130, 194, 71, 63, 254, 230, 240, 198, 251, 73, 35, 220, 14, 233, 175, 179, 99, 14, 154, 23, 35, 9, 10, 27, 84, 179, 147, 144, 4, 133, 12, 223, 74, 34, 9, 10, 23, 186, 150, 68, 21, 9, 31, 42, 18, 62, 80, 151, 201, 249, 159, 74, 147, 15, 145, 164, 92, 222, 47, 105, 251, 154, 104, 126, 88, 242, 221, 129, 239, 175, 215, 192, 73, 220, 64, 191, 116, 94, 155, 44, 98, 101, 226, 229, 192, 187, 70, 158, 29, 119, 217, 28, 105, 147, 108, 25, 56, 237, 70, 169, 196, 123, 50, 104, 109, 50, 17, 186, 150, 81, 201, 171, 81, 40, 28, 28, 66, 43, 143, 95, 245, 18, 53, 224, 66, 87, 122, 18, 46, 64, 26, 57, 168, 47, 37, 225, 66, 219, 5, 185, 69, 41, 9, 27, 217, 9, 105, 197, 54, 52, 157, 124, 211, 9, 68, 83, 203, 247, 182, 136, 241, 251, 75, 184, 192, 35, 136, 2, 16, 72, 32, 65, 4, 157, 244, 75, 216, 160, 116, 169, 150, 78, 123, 232, 89, 19, 232, 183, 65, 47, 225, 17, 8, 173, 79, 225, 17, 8, 15, 79, 77, 187, 95, 66, 135, 111, 157, 4, 235, 32, 190, 121, 193, 46, 137, 84, 113, 67, 134, 42, 110, 168, 32, 73, 220, 80, 65, 157, 148, 137, 27, 46, 184, 97, 131, 27, 50, 212, 51, 33, 110, 184, 80, 237, 103, 13, 25, 60, 2, 193, 31, 149, 52, 100, 168, 111, 67, 133, 100, 108, 27, 46, 160, 99, 105, 179, 13, 23, 158, 126, 164, 105, 27, 50, 150, 109, 168, 160, 169, 132, 31, 65, 48, 88, 148, 210, 186, 242, 125, 239, 132, 194, 73, 191, 20, 127, 13, 238, 223, 65, 251, 235, 9, 224, 0, 253, 158, 252, 234, 182, 223, 81, 165, 137, 176, 75, 210, 46, 127, 93, 42, 241, 137, 181, 246, 77, 248, 182, 173, 110, 93, 195, 27, 175, 251, 178, 86, 151, 203, 39, 101, 90, 93, 227, 101, 68, 97, 183, 14, 181, 170, 102, 182, 143, 126, 129, 196, 25, 16, 221, 255, 181, 184, 147, 163, 54, 209, 176, 117, 142, 59, 161, 74, 211, 48, 194, 35, 239, 52, 187, 156, 102, 29, 84, 105, 26, 62, 48, 202, 161, 6, 144, 70, 97, 245, 237, 177, 132, 174, 132, 29, 205, 139, 33, 154, 23, 55, 184, 91, 167, 129, 42, 77, 195, 135, 191, 229, 42, 77, 67, 7, 173, 88, 231, 127, 137, 42, 77, 67, 72, 211, 176, 81, 233, 166, 97, 3, 9, 119, 211, 112, 225, 83, 106, 55, 13, 23, 77, 195, 71, 211, 240, 33, 65, 211, 208, 209, 74, 209, 157, 32, 143, 48, 202, 161, 8, 77, 219, 199, 13, 69, 104, 26, 58, 44, 200, 245, 154, 108, 37, 241, 100, 17, 174, 43, 225, 71, 235, 235, 114, 140, 27, 80, 132, 166, 161, 195, 155, 6, 93, 200, 104, 26, 62, 210, 73, 239, 50, 105, 163, 166, 33, 68, 146, 214, 161, 166, 33, 132, 75, 18, 51, 212, 52, 100, 104, 147, 236, 169, 200, 133, 154, 134, 17, 77, 67, 138, 166, 225, 195, 235, 90, 111, 65, 77, 67, 77, 195, 6, 148, 104, 120, 45, 72, 153, 58, 143, 178, 179, 191, 162, 13, 25, 188, 105, 227, 208, 250, 76, 58, 191, 20, 8, 95, 235, 24, 232, 231, 242, 150, 237, 224, 202, 212, 249, 135, 75, 166, 191, 174, 253, 146, 250, 132, 235, 63, 110, 9, 93, 75, 86, 158, 210, 78, 138, 0, 220, 117, 33, 245, 45, 145, 43, 173, 88, 182, 239, 120, 129, 182, 93, 12, 195, 21, 109, 15, 255, 198, 140, 195, 117, 37, 12, 113, 254, 53, 86, 63, 164, 255, 22, 251, 146, 232, 43, 218, 48, 226, 43, 218, 80, 193, 31, 169, 123, 158, 162, 13, 29, 217, 95, 209, 197, 222, 65, 15, 90, 50, 138, 54, 100, 88, 253, 144, 62, 247, 165, 120, 4, 169, 182, 12, 162, 104, 67, 20, 109, 200, 112, 215, 86, 42, 145, 164, 153, 242, 218, 240, 33, 245, 107, 195, 5, 137, 39, 123, 109, 184, 96, 160, 141, 90, 10, 114, 246, 192, 174, 132, 30, 102, 215, 107, 195, 199, 107, 67, 5, 172, 89, 221, 243, 13, 60, 210, 38, 0, 193, 34, 143, 232, 98, 127, 215, 134, 14, 207, 131, 210, 119, 109, 72, 209, 248, 189, 45, 5, 210, 250, 143, 31, 77, 39, 217, 232, 93, 27, 58, 190, 83, 33, 166, 181, 97, 35, 177, 98, 109, 17, 139, 23, 212, 64, 36, 2, 214, 134, 16, 214, 134, 15, 214, 134, 13, 116, 232, 82, 170, 13, 25, 86, 190, 9, 250, 169, 13, 27, 19, 79, 232, 83, 27, 50, 30, 93, 157, 218, 112, 145, 86, 241, 182, 58, 6, 239, 218, 169, 13, 27, 26, 123, 68, 53, 100, 112, 157, 148, 111, 118, 200, 2, 143, 227, 178, 27, 102, 236, 32, 137, 39, 187, 83, 53, 92, 184, 212, 80, 129, 178, 108, 169, 33, 3, 55, 59, 201, 134, 12, 250, 187, 16, 133, 246, 3, 46, 124, 177, 250, 181, 231, 112, 80, 189, 139, 190, 181, 160, 102, 9, 39, 189, 50, 8, 113, 60, 27, 42, 56, 119, 74, 134, 214, 101, 195, 135, 90, 251, 22, 180, 46, 219, 190, 163, 181, 181, 117, 222, 224, 216, 125, 50, 181, 220, 178, 33, 195, 98, 239, 48, 252, 155, 78, 212, 155, 23, 39, 135, 54, 94, 201, 223, 194, 73, 77, 23, 110, 217, 176, 241, 173, 238, 201, 45, 27, 58, 150, 231, 203, 115, 136, 91, 182, 212, 6, 238, 9, 113, 203, 134, 12, 110, 217, 80, 161, 101, 67, 5, 205, 44, 27, 46, 32, 140, 64, 74, 89, 54, 148, 88, 43, 145, 178, 108, 216, 160, 146, 145, 108, 184, 224, 218, 118, 169, 212, 70, 13, 31, 44, 187, 65, 13, 25, 26, 2, 160, 130, 97, 0, 34, 48, 172, 9, 254, 48, 92, 120, 152, 173, 232, 63, 134, 12, 182, 142, 163, 5, 15, 56, 240, 166, 237, 187, 254, 3, 182, 142, 183, 182, 136, 0, 143, 97, 196, 99, 8, 241, 254, 24, 42, 120, 68, 66, 131, 227, 233, 244, 99, 253, 24, 58, 90, 117, 9, 64, 221, 186, 79, 214, 112, 210, 39, 115, 201, 24, 218, 118, 121, 211, 114, 45, 208, 180, 149, 120, 36, 85, 156, 188, 41, 244, 158, 169, 65, 61, 151, 237, 135, 248, 81, 43, 149, 16, 173, 84, 238, 119, 58, 180, 191, 30, 67, 135, 4, 71, 173, 191, 30, 195, 134, 227, 118, 72, 242, 24, 50, 208, 62, 134, 14, 207, 176, 65, 113, 134, 10, 214, 4, 119, 134, 11, 252, 238, 233, 212, 206, 176, 209, 18, 48, 244, 119, 65, 60, 130, 36, 41, 93, 227, 12, 29, 239, 218, 200, 25, 46, 156, 97, 67, 217, 178, 102, 200, 160, 205, 9, 177, 102, 200, 216, 102, 168, 64, 178, 146, 130, 156, 42, 212, 12, 31, 255, 19, 24, 62, 252, 79, 96, 168, 48, 129, 33, 195, 155, 99, 168, 224, 24, 58, 210, 122, 46, 142, 225, 2, 46, 156, 183, 194, 12, 25, 254, 49, 67, 5, 109, 90, 58, 9, 169, 63, 102, 8, 249, 182, 236, 208, 183, 199, 12, 31, 251, 80, 227, 125, 102, 216, 112, 235, 120, 171, 243, 204, 208, 241, 206, 12, 21, 60, 2, 193, 183, 155, 25, 54, 24, 43, 199, 53, 179, 71, 203, 166, 153, 33, 131, 239, 202, 102, 134, 11, 21, 1, 105, 227, 231, 198, 12, 27, 60, 185, 84, 33, 199, 188, 16, 58, 136, 48, 65, 250, 217, 182, 73, 71, 209, 52, 110, 208, 138, 85, 231, 79, 94, 140, 131, 190, 46, 85, 232, 65, 157, 25, 30, 217, 126, 15, 109, 78, 104, 1, 180, 44, 106, 245, 67, 173, 177, 3, 141, 23, 125, 211, 93, 9, 61, 88, 22, 142, 167, 106, 112, 211, 152, 33, 228, 209, 198, 12, 23, 22, 203, 7, 113, 202, 198, 120, 80, 239, 116, 18, 219, 150, 61, 60, 34, 0, 6, 254, 164, 66, 20, 238, 218, 214, 223, 130, 30, 190, 41, 99, 134, 12, 173, 235, 37, 93, 204, 176, 177, 152, 225, 67, 123, 204, 160, 231, 198, 64, 177, 68, 238, 73, 152, 23, 69, 4, 131, 174, 76, 222, 185, 158, 98, 134, 16, 244, 48, 171, 152, 225, 67, 87, 108, 235, 6, 47, 85, 204, 144, 97, 177, 10, 114, 232, 82, 138, 25, 50, 248, 131, 150, 186, 146, 98, 134, 140, 69, 41, 40, 21, 51, 100, 224, 254, 61, 34, 73, 204, 144, 225, 105, 93, 76, 154, 34, 165, 250, 169, 218, 170, 119, 135, 107, 51, 36, 42, 218, 36, 46, 161, 68, 26, 11, 40, 36, 56, 114, 202, 3, 73, 18, 51, 148, 104, 110, 32, 66, 25, 187, 82, 36, 41, 93, 163, 193, 157, 190, 63, 156, 244, 73, 121, 167, 217, 6, 209, 250, 205, 110, 130, 194, 219, 74, 154, 70, 24, 164, 147, 152, 225, 2, 95, 251, 79, 181, 31, 85, 22, 102, 19, 149, 133, 25, 58, 42, 11, 51, 84, 104, 8, 252, 61, 164, 157, 80, 172, 93, 152, 97, 195, 59, 54, 208, 162, 24, 67, 134, 98, 12, 29, 207, 90, 12, 21, 218, 86, 146, 161, 39, 187, 19, 45, 134, 144, 94, 229, 216, 75, 24, 50, 28, 211, 151, 48, 100, 144, 48, 116, 68, 88, 52, 117, 254, 33, 129, 14, 141, 186, 8, 67, 136, 195, 87, 244, 117, 45, 249, 41, 157, 63, 86, 110, 98, 255, 148, 218, 148, 108, 180, 88, 132, 65, 44, 86, 65, 15, 157, 203, 36, 27, 68, 155, 100, 203, 221, 208, 245, 251, 186, 158, 247, 135, 8, 149, 234, 60, 248, 198, 12, 82, 169, 142, 74, 117, 40, 84, 170, 227, 30, 119, 227, 104, 85, 59, 89, 5, 209, 230, 196, 222, 226, 180, 171, 161, 241, 255, 123, 60, 138, 151, 70, 227, 85, 205, 41, 37, 90, 44, 194, 208, 97, 177, 8, 67, 5, 231, 151, 82, 89, 134, 11, 254, 202, 50, 92, 128, 88, 218, 210, 85, 150, 33, 67, 89, 101, 25, 46, 108, 101, 25, 58, 214, 185, 117, 95, 247, 101, 248, 240, 8, 50, 26, 74, 43, 214, 35, 28, 127, 203, 73, 175, 140, 3, 130, 112, 79, 167, 21, 203, 24, 74, 223, 151, 249, 66, 188, 47, 219, 182, 140, 53, 94, 155, 135, 217, 182, 12, 25, 182, 95, 51, 137, 208, 230, 135, 244, 90, 108, 91, 134, 14, 184, 105, 169, 45, 67, 134, 111, 170, 218, 162, 182, 12, 29, 108, 209, 150, 33, 196, 153, 45, 195, 133, 198, 160, 180, 108, 25, 50, 90, 217, 50, 101, 203, 176, 177, 236, 82, 182, 12, 23, 206, 150, 49, 135, 178, 101, 248, 80, 182, 12, 21, 118, 173, 101, 248, 104, 187, 100, 163, 214, 181, 150, 33, 4, 23, 143, 82, 203, 112, 65, 217, 126, 67, 43, 118, 229, 175, 203, 132, 158, 97, 119, 213, 56, 169, 67, 156, 244, 14, 87, 247, 60, 197, 242, 124, 251, 33, 180, 246, 223, 90, 137, 22, 104, 93, 6, 25, 64, 89, 54, 212, 154, 211, 3, 77, 23, 104, 163, 86, 246, 26, 82, 197, 73, 21, 4, 78, 128, 135, 89, 247, 92, 74, 37, 237, 49, 208, 245, 251, 13, 52, 165, 115, 93, 114, 53, 222, 207, 182, 239, 170, 80, 197, 35, 12, 20, 192, 249, 100, 76, 127, 37, 158, 128, 134, 0, 186, 150, 124, 7, 156, 230, 113, 59, 175, 18, 166, 65, 192, 0, 22, 146, 180, 93, 252, 47, 209, 2, 24, 211, 52, 104, 253, 79, 246, 141, 91, 0, 13, 72, 58, 89, 39, 123, 224, 15, 225, 155, 78, 84, 117, 177, 43, 49, 86, 39, 244, 240, 240, 166, 179, 209, 250, 73, 187, 57, 169, 115, 7, 220, 105, 25, 54, 108, 167, 101, 184, 192, 105, 25, 66, 92, 63, 211, 46, 94, 216, 19, 1, 161, 108, 191, 189, 134, 230, 254, 3, 8, 96, 226, 169, 112, 59, 212, 11, 180, 217, 241, 168, 4, 61, 168, 147, 50, 61, 36, 96, 128, 214, 6, 220, 175, 12, 41, 94, 83, 230, 251, 202, 176, 129, 15, 206, 43, 115, 94, 25, 50, 28, 124, 121, 223, 172, 175, 12, 35, 38, 116, 253, 190, 54, 201, 54, 162, 241, 54, 200, 87, 134, 15, 231, 151, 249, 202, 87, 134, 14, 164, 224, 86, 134, 11, 170, 253, 40, 55, 109, 127, 58, 138, 101, 23, 210, 37, 105, 101, 232, 112, 242, 217, 86, 134, 139, 111, 246, 8, 12, 250, 86, 78, 92, 181, 255, 225, 146, 33, 8, 103, 180, 29, 222, 216, 35, 11, 52, 13, 136, 63, 112, 221, 206, 198, 251, 105, 37, 220, 149, 101, 67, 238, 185, 82, 68, 211, 214, 249, 167, 37, 114, 208, 166, 149, 225, 2, 133, 149, 161, 66, 86, 176, 106, 202, 112, 161, 205, 239, 79, 187, 67, 107, 147, 14, 61, 237, 12, 122, 186, 145, 150, 217, 78, 237, 241, 132, 104, 227, 7, 70, 120, 132, 41, 195, 5, 173, 88, 166, 12, 25, 248, 145, 75, 134, 24, 57, 195, 148, 97, 1, 156, 97, 202, 152, 50, 92, 52, 56, 131, 152, 50, 100, 96, 204, 21, 136, 61, 246, 86, 41, 195, 134, 167, 245, 77, 112, 180, 186, 231, 31, 8, 249, 150, 202, 112, 161, 41, 134, 13, 174, 24, 54, 154, 98, 216, 224, 83, 106, 163, 85, 12, 27, 251, 16, 90, 197, 240, 33, 241, 83, 240, 51, 87, 228, 145, 138, 98, 20, 21, 143, 160, 138, 98, 21, 197, 30, 84, 20, 115, 62, 217, 67, 132, 174, 37, 159, 49, 13, 90, 251, 143, 49, 141, 3, 98, 220, 14, 144, 106, 137, 84, 91, 134, 1, 111, 188, 12, 62, 229, 254, 147, 112, 199, 101, 55, 217, 233, 144, 86, 168, 190, 9, 238, 128, 34, 63, 149, 239, 66, 74, 37, 122, 79, 197, 176, 65, 218, 79, 134, 24, 73, 160, 24, 62, 42, 234, 32, 9, 20, 195, 133, 174, 101, 144, 4, 138, 33, 195, 21, 73, 160, 24, 50, 48, 79, 10, 90, 137, 189, 87, 146, 33, 132, 90, 180, 101, 149, 100, 200, 224, 17, 231, 147, 65, 42, 25, 89, 13, 4, 231, 147, 225, 226, 65, 209, 252, 249, 156, 79, 134, 15, 220, 19, 210, 138, 221, 135, 246, 77, 236, 243, 198, 105, 29, 244, 119, 81, 124, 99, 166, 113, 90, 244, 128, 55, 78, 139, 90, 179, 174, 106, 193, 162, 20, 228, 13, 188, 121, 113, 122, 200, 85, 202, 32, 90, 23, 78, 149, 234, 76, 106, 45, 5, 173, 126, 18, 185, 74, 153, 227, 19, 25, 79, 55, 246, 100, 72, 226, 201, 176, 177, 210, 241, 78, 134, 139, 103, 225, 241, 183, 28, 106, 69, 173, 11, 148, 42, 149, 116, 50, 100, 208, 245, 250, 193, 174, 132, 32, 190, 237, 74, 144, 138, 71, 16, 255, 67, 3, 73, 219, 213, 128, 126, 41, 24, 70, 186, 150, 124, 7, 92, 210, 150, 1, 127, 42, 114, 57, 168, 232, 167, 68, 159, 219, 51, 51, 20, 191, 253, 159, 232, 183, 217, 73, 45, 145, 196, 239, 99, 194, 33, 60, 162, 81, 88, 73, 58, 25, 50, 60, 2, 65, 210, 201, 112, 177, 168, 220, 78, 86, 105, 218, 58, 169, 147, 33, 3, 231, 151, 121, 171, 115, 201, 240, 177, 26, 84, 225, 165, 241, 235, 59, 233, 92, 203, 214, 81, 59, 68, 22, 70, 46, 25, 46, 126, 217, 46, 228, 146, 185, 100, 232, 104, 43, 201, 150, 76, 155, 108, 201, 240, 225, 60, 51, 150, 12, 23, 220, 41, 89, 50, 92, 236, 74, 134, 10, 202, 164, 35, 151, 104, 112, 199, 237, 32, 122, 21, 82, 73, 50, 73, 50, 116, 112, 36, 25, 42, 252, 46, 231, 216, 240, 8, 106, 175, 89, 155, 12, 29, 16, 9, 19, 180, 46, 145, 99, 235, 164, 181, 201, 16, 194, 61, 199, 14, 165, 101, 182, 53, 201, 208, 97, 251, 161, 215, 214, 36, 67, 199, 174, 180, 77, 178, 180, 77, 50, 108, 60, 99, 146, 225, 2, 114, 78, 201, 176, 193, 87, 63, 36, 73, 233, 32, 52, 219, 58, 41, 217, 4, 158, 4, 134, 142, 9, 60, 9, 12, 31, 173, 223, 118, 161, 39, 129, 161, 99, 2, 204, 191, 138, 133, 12, 201, 42, 22, 42, 84, 44, 108, 84, 218, 179, 80, 33, 237, 231, 59, 210, 57, 114, 202, 194, 133, 254, 54, 69, 27, 57, 101, 225, 163, 162, 170, 45, 114, 10, 101, 33, 196, 41, 11, 21, 52, 174, 188, 133, 11, 153, 252, 45, 92, 232, 246, 22, 42, 72, 48, 113, 73, 98, 175, 0, 123, 11, 31, 254, 249, 142, 42, 192, 222, 194, 136, 10, 176, 183, 208, 81, 249, 133, 10, 190, 249, 133, 10, 46, 89, 5, 22, 250, 244, 77, 104, 244, 122, 33, 228, 245, 194, 198, 59, 205, 46, 10, 47, 100, 120, 38, 7, 8, 116, 44, 138, 194, 11, 23, 30, 47, 116, 64, 19, 159, 82, 27, 226, 188, 72, 247, 159, 23, 58, 92, 151, 59, 47, 108, 112, 188, 80, 129, 227, 28, 28, 226, 219, 178, 99, 109, 144, 186, 231, 243, 83, 173, 166, 121, 17, 244, 96, 81, 220, 52, 102, 11, 180, 196, 55, 59, 247, 116, 136, 129, 103, 94, 80, 131, 36, 229, 226, 152, 23, 50, 112, 129, 178, 92, 232, 104, 14, 71, 154, 198, 11, 25, 146, 119, 109, 26, 47, 116, 248, 199, 141, 23, 66, 154, 198, 11, 21, 42, 186, 120, 225, 130, 71, 86, 194, 11, 25, 86, 194, 11, 21, 24, 32, 165, 205, 139, 19, 114, 96, 233, 68, 87, 195, 11, 25, 79, 211, 240, 194, 133, 166, 225, 133, 15, 172, 153, 97, 76, 195, 171, 225, 133, 139, 231, 149, 13, 47, 92, 120, 36, 130, 134, 23, 50, 44, 104, 120, 73, 52, 188, 208, 209, 240, 66, 5, 206, 61, 231, 94, 189, 61, 231, 151, 50, 97, 219, 91, 125, 19, 182, 189, 9, 219, 94, 195, 132, 109, 207, 249, 165, 52, 222, 246, 32, 158, 165, 241, 182, 215, 120, 219, 123, 248, 206, 119, 182, 253, 202, 182, 223, 129, 109, 191, 115, 143, 219, 230, 114, 252, 20, 252, 14, 252, 252, 14, 174, 108, 127, 253, 115, 59, 191, 124, 179, 51, 118, 149, 100, 115, 173, 88, 127, 117, 245, 229, 88, 250, 122, 254, 174, 173, 78, 39, 204, 122, 211, 65, 190, 243, 93, 165, 107, 170, 210, 169, 116, 142, 103, 105, 85, 205, 169, 241, 179, 252, 50, 254, 101, 76, 225, 230, 112, 204, 77, 43, 150, 153, 50, 135, 103, 169, 36, 171, 36, 115, 184, 100, 16, 254, 168, 196, 37, 123, 239, 101, 90, 41, 188, 34, 212, 51, 181, 82, 120, 121, 174, 71, 37, 143, 103, 121, 84, 162, 158, 105, 201, 69, 37, 16, 237, 61, 172, 245, 218, 218, 6, 113, 210, 39, 107, 154, 46, 143, 208, 223, 182, 140, 47, 69, 98, 229, 155, 240, 188, 99, 234, 14, 250, 169, 220, 125, 93, 50, 149, 240, 164, 45, 196, 183, 78, 218, 58, 248, 171, 84, 231, 209, 214, 211, 241, 116, 28, 77, 255, 115, 49, 14, 239, 185, 84, 91, 70, 37, 170, 45, 227, 192, 60, 116, 162, 174, 162, 141, 118, 131, 243, 75, 113, 213, 212, 249, 165, 44, 169, 169, 247, 91, 84, 61, 60, 221, 47, 113, 122, 112, 245, 76, 75, 89, 38, 8, 16, 170, 237, 2, 225, 19, 130, 243, 75, 113, 126, 41, 109, 159, 78, 135, 131, 243, 233, 248, 95, 211, 174, 6, 127, 84, 194, 214, 113, 213, 118, 121, 117, 102, 213, 94, 3, 111, 85, 139, 29, 157, 236, 103, 211, 134, 120, 178, 59, 213, 83, 151, 182, 126, 46, 118, 173, 223, 86, 123, 193, 147, 221, 249, 218, 116, 58, 169, 211, 73, 139, 189, 243, 234, 173, 170, 61, 118, 140, 155, 129, 147, 50, 81, 72, 82, 46, 107, 101, 82, 109, 93, 223, 202, 137, 196, 132, 109, 207, 149, 194, 73, 159, 108, 229, 155, 160, 62, 241, 218, 52, 63, 168, 231, 82, 81, 213, 86, 181, 101, 212, 115, 129, 152, 112, 82, 234, 227, 56, 61, 217, 157, 21, 128, 16, 241, 80, 235, 138, 26, 142, 167, 226, 133, 12, 45, 73, 188, 36, 137, 23, 50, 36, 137, 23, 42, 252, 163, 105, 91, 177, 17, 218, 100, 51, 243, 216, 8, 51, 69, 186, 40, 5, 98, 185, 63, 52, 18, 135, 86, 38, 110, 247, 164, 134, 149, 137, 23, 66, 60, 194, 224, 158, 32, 120, 171, 71, 32, 52, 90, 91, 91, 123, 221, 224, 12, 106, 117, 60, 85, 242, 194, 133, 63, 232, 90, 135, 7, 196, 37, 158, 15, 209, 44, 19, 65, 209, 48, 9, 169, 228, 133, 140, 69, 177, 133, 14, 111, 218, 170, 182, 11, 98, 147, 181, 176, 65, 37, 47, 109, 157, 236, 66, 7, 197, 255, 46, 108, 104, 149, 164, 117, 250, 187, 208, 209, 250, 187, 240, 177, 11, 25, 11, 21, 232, 167, 114, 175, 181, 85, 53, 109, 244, 77, 215, 250, 130, 127, 174, 45, 122, 244, 194, 195, 108, 83, 39, 2, 225, 125, 23, 46, 220, 119, 33, 4, 211, 95, 244, 174, 246, 77, 216, 133, 15, 102, 218, 34, 214, 204, 124, 46, 135, 42, 175, 237, 194, 9, 165, 77, 190, 163, 111, 15, 179, 146, 182, 11, 29, 72, 210, 118, 97, 132, 191, 239, 107, 218, 46, 148, 168, 88, 144, 164, 246, 210, 252, 73, 39, 168, 83, 219, 46, 164, 208, 182, 109, 87, 99, 111, 113, 130, 208, 182, 11, 61, 11, 210, 182, 11, 33, 173, 139, 70, 73, 231, 143, 95, 244, 203, 118, 33, 99, 237, 194, 134, 218, 247, 208, 218, 133, 140, 125, 13, 90, 187, 112, 33, 225, 214, 241, 70, 107, 211, 240, 66, 234, 143, 29, 245, 199, 142, 227, 105, 93, 43, 27, 72, 107, 68, 132, 10, 47, 141, 135, 161, 119, 154, 93, 8, 225, 222, 51, 187, 144, 129, 97, 248, 153, 93, 184, 208, 93, 168, 128, 129, 122, 211, 180, 11, 31, 34, 52, 60, 178, 88, 101, 217, 133, 12, 151, 191, 236, 66, 6, 151, 96, 111, 21, 251, 178, 11, 27, 19, 220, 178, 171, 129, 71, 16, 70, 52, 48, 215, 150, 93, 8, 89, 118, 97, 67, 29, 39, 71, 43, 211, 86, 116, 97, 67, 235, 66, 71, 69, 23, 42, 104, 19, 93, 168, 128, 126, 149, 162, 7, 109, 245, 29, 111, 79, 103, 99, 52, 247, 22, 141, 194, 74, 194, 29, 222, 89, 162, 234, 104, 7, 151, 77, 65, 141, 247, 29, 71, 48, 101, 141, 202, 50, 15, 159, 169, 45, 72, 170, 56, 161, 199, 210, 137, 46, 92, 88, 192, 64, 130, 125, 77, 29, 67, 116, 225, 195, 93, 23, 42, 100, 107, 93, 184, 208, 94, 58, 73, 219, 233, 66, 135, 74, 135, 158, 209, 133, 12, 137, 234, 66, 133, 214, 247, 183, 82, 171, 164, 147, 45, 248, 150, 255, 24, 132, 214, 39, 151, 218, 110, 32, 60, 192, 218, 68, 80, 178, 21, 66, 136, 74, 93, 168, 224, 17, 151, 106, 33, 131, 75, 181, 210, 66, 135, 245, 92, 91, 98, 194, 105, 161, 67, 109, 90, 168, 224, 90, 177, 222, 112, 215, 230, 17, 8, 139, 149, 147, 73, 211, 103, 133, 22, 76, 80, 103, 84, 228, 66, 199, 83, 145, 11, 21, 26, 104, 204, 152, 68, 57, 138, 44, 240, 44, 73, 167, 66, 7, 90, 177, 109, 63, 23, 50, 90, 63, 23, 46, 180, 215, 12, 109, 187, 32, 214, 202, 132, 222, 115, 161, 3, 135, 38, 127, 121, 142, 208, 129, 55, 45, 23, 46, 56, 195, 104, 120, 161, 227, 145, 32, 228, 145, 96, 0, 54, 194, 140, 251, 73, 144, 209, 186, 158, 4, 23, 244, 73, 80, 129, 235, 107, 107, 93, 158, 4, 35, 42, 47, 193, 134, 218, 231, 18, 92, 112, 151, 160, 130, 182, 250, 238, 181, 4, 25, 57, 105, 44, 193, 133, 150, 141, 37, 184, 240, 190, 205, 139, 37, 200, 240, 92, 201, 18, 100, 248, 108, 7, 111, 78, 40, 66, 178, 4, 27, 15, 167, 232, 78, 156, 148, 9, 65, 60, 84, 83, 111, 135, 254, 227, 110, 104, 211, 178, 39, 48, 52, 207, 169, 218, 110, 157, 48, 74, 150, 32, 36, 147, 191, 6, 37, 178, 104, 236, 17, 143, 32, 223, 71, 155, 0, 4, 203, 180, 39, 134, 55, 167, 111, 157, 188, 54, 171, 218, 132, 58, 179, 4, 31, 143, 226, 71, 49, 99, 65, 178, 4, 29, 146, 37, 168, 192, 169, 46, 71, 44, 65, 134, 82, 165, 234, 72, 23, 195, 60, 199, 145, 243, 175, 73, 144, 162, 194, 77, 130, 10, 174, 219, 36, 72, 241, 143, 37, 137, 155, 4, 25, 217, 120, 73, 112, 161, 159, 46, 9, 46, 104, 91, 134, 73, 164, 150, 4, 29, 169, 61, 142, 40, 185, 36, 216, 96, 24, 169, 182, 18, 180, 214, 74, 176, 145, 140, 219, 145, 32, 3, 210, 38, 155, 223, 245, 49, 101, 104, 242, 168, 4, 27, 38, 143, 74, 80, 193, 123, 211, 61, 233, 22, 205, 221, 251, 168, 4, 27, 110, 187, 121, 84, 130, 11, 143, 32, 85, 156, 30, 149, 160, 67, 146, 188, 210, 163, 18, 132, 64, 140, 155, 81, 157, 188, 60, 42, 65, 5, 232, 164, 95, 82, 164, 158, 203, 163, 18, 116, 160, 168, 4, 21, 56, 183, 46, 173, 18, 100, 244, 50, 42, 113, 170, 18, 157, 236, 74, 228, 84, 37, 8, 129, 154, 170, 4, 31, 19, 72, 16, 161, 33, 201, 148, 84, 130, 12, 232, 240, 230, 36, 193, 5, 215, 184, 69, 130, 11, 21, 253, 148, 224, 130, 131, 243, 210, 58, 81, 164, 203, 155, 208, 217, 216, 185, 173, 55, 110, 251, 88, 144, 94, 58, 197, 118, 50, 233, 11, 220, 91, 139, 251, 183, 189, 9, 143, 166, 57, 144, 78, 98, 246, 104, 216, 8, 93, 203, 52, 240, 72, 132, 5, 38, 38, 77, 25, 248, 0, 30, 236, 106, 40, 227, 94, 176, 233, 36, 7, 3, 15, 179, 16, 205, 75, 151, 92, 80, 178, 78, 9, 58, 96, 170, 157, 18, 100, 208, 245, 220, 165, 4, 23, 173, 239, 171, 108, 45, 117, 41, 193, 6, 143, 164, 132, 73, 201, 91, 144, 4, 25, 149, 8, 50, 116, 57, 182, 174, 79, 137, 160, 131, 169, 67, 252, 72, 66, 137, 160, 227, 213, 95, 27, 164, 76, 122, 131, 122, 38, 180, 228, 162, 146, 6, 143, 103, 57, 151, 232, 129, 97, 182, 241, 11, 241, 139, 158, 238, 151, 208, 251, 139, 96, 67, 191, 8, 46, 60, 220, 86, 120, 4, 23, 154, 182, 142, 42, 30, 193, 134, 207, 137, 71, 112, 97, 226, 17, 84, 176, 253, 60, 130, 11, 21, 239, 17, 84, 112, 201, 26, 170, 253, 13, 30, 193, 199, 98, 21, 126, 143, 224, 194, 35, 8, 241, 249, 30, 193, 5, 247, 8, 66, 186, 89, 53, 157, 44, 48, 161, 107, 201, 1, 172, 215, 15, 124, 179, 35, 119, 220, 78, 233, 187, 182, 8, 9, 253, 136, 136, 6, 18, 11, 244, 115, 177, 175, 190, 123, 4, 29, 191, 237, 33, 247, 8, 66, 60, 148, 101, 66, 238, 17, 116, 112, 143, 160, 2, 165, 233, 41, 109, 20, 209, 154, 245, 244, 246, 8, 54, 26, 152, 107, 12, 230, 60, 130, 15, 70, 57, 143, 224, 130, 243, 233, 60, 178, 40, 229, 119, 161, 228, 122, 211, 105, 59, 30, 206, 171, 119, 58, 215, 216, 35, 184, 160, 152, 181, 93, 232, 219, 46, 135, 111, 187, 180, 109, 67, 173, 180, 141, 61, 130, 12, 14, 39, 125, 58, 134, 89, 5, 73, 139, 229, 211, 88, 204, 87, 37, 2, 227, 193, 57, 46, 194, 196, 83, 4, 198, 195, 236, 55, 59, 132, 197, 242, 65, 15, 147, 174, 105, 91, 218, 247, 85, 133, 26, 120, 120, 149, 36, 166, 120, 183, 157, 252, 249, 93, 157, 79, 48, 188, 86, 54, 88, 208, 42, 73, 134, 97, 150, 209, 86, 245, 252, 174, 93, 246, 31, 104, 167, 99, 156, 214, 139, 80, 155, 92, 55, 246, 182, 12, 241, 127, 93, 80, 211, 137, 58, 224, 164, 79, 7, 33, 241, 100, 30, 65, 105, 27, 110, 88, 168, 113, 69, 23, 83, 250, 208, 172, 18, 228, 158, 98, 160, 43, 61, 169, 242, 152, 42, 36, 209, 202, 48, 143, 189, 246, 232, 117, 137, 26, 123, 4, 39, 38, 158, 80, 4, 212, 216, 35, 168, 160, 140, 61, 130, 11, 17, 24, 218, 50, 143, 224, 194, 183, 93, 30, 65, 6, 73, 178, 212, 254, 200, 127, 117, 134, 72, 146, 165, 116, 104, 215, 35, 248, 216, 245, 8, 42, 124, 91, 199, 35, 200, 224, 234, 120, 58, 30, 65, 134, 218, 110, 60, 130, 12, 238, 25, 143, 224, 130, 166, 102, 198, 35, 184, 72, 174, 30, 193, 5, 167, 30, 65, 133, 166, 30, 65, 5, 8, 91, 208, 55, 249, 108, 135, 212, 61, 13, 248, 35, 42, 218, 104, 171, 119, 186, 165, 75, 46, 143, 117, 137, 26, 137, 149, 71, 112, 33, 63, 21, 106, 42, 161, 158, 236, 82, 229, 17, 140, 200, 85, 202, 86, 178, 20, 244, 234, 218, 110, 65, 98, 229, 17, 228, 201, 35, 232, 80, 46, 121, 4, 23, 158, 89, 199, 85, 113, 242, 8, 62, 94, 85, 167, 147, 60, 130, 141, 182, 120, 4, 21, 118, 241, 8, 42, 180, 244, 8, 42, 44, 86, 137, 224, 17, 132, 56, 44, 150, 15, 242, 8, 46, 30, 102, 33, 234, 50, 185, 66, 68, 128, 64, 2, 9, 19, 72, 16, 33, 29, 8, 210, 89, 124, 210, 229, 17, 108, 120, 4, 25, 238, 17, 132, 120, 4, 39, 60, 130, 14, 9, 20, 67, 30, 65, 6, 244, 116, 246, 178, 11, 121, 4, 39, 82, 113, 4, 121, 4, 23, 206, 156, 223, 230, 102, 37, 194, 137, 8, 66, 120, 218, 230, 207, 182, 11, 227, 132, 60, 130, 16, 17, 108, 128, 60, 130, 143, 8, 54, 86, 182, 101, 173, 207, 15, 225, 155, 157, 183, 236, 111, 208, 180, 245, 84, 93, 9, 115, 130, 208, 240, 218, 153, 32, 232, 100, 253, 245, 47, 220, 30, 114, 160, 241, 58, 169, 61, 183, 111, 129, 46, 213, 222, 130, 246, 237, 107, 172, 181, 204, 87, 244, 181, 237, 146, 116, 58, 8, 182, 203, 159, 214, 55, 129, 101, 167, 131, 44, 85, 135, 162, 254, 152, 69, 232, 103, 55, 203, 222, 105, 86, 29, 228, 164, 159, 88, 154, 46, 89, 3, 107, 102, 30, 44, 59, 157, 131, 210, 110, 101, 84, 61, 248, 146, 143, 154, 182, 107, 113, 39, 23, 0, 50, 176, 237, 71, 19, 34, 184, 104, 187, 160, 150, 253, 141, 186, 8, 66, 60, 130, 26, 117, 17, 92, 108, 62, 71, 112, 65, 157, 35, 168, 144, 205, 17, 84, 96, 199, 161, 229, 8, 66, 44, 71, 240, 177, 28, 65, 5, 191, 138, 35, 184, 64, 1, 8, 36, 144, 32, 130, 90, 197, 17, 118, 110, 73, 4, 31, 223, 94, 55, 232, 55, 130, 141, 198, 25, 250, 101, 233, 180, 93, 131, 102, 135, 236, 141, 224, 195, 177, 141, 160, 194, 98, 21, 109, 34, 200, 176, 42, 26, 65, 5, 181, 8, 29, 173, 146, 230, 135, 59, 233, 147, 210, 180, 201, 86, 127, 146, 196, 12, 241, 191, 68, 30, 177, 88, 62, 238, 9, 73, 252, 38, 150, 250, 205, 132, 194, 191, 105, 83, 186, 158, 215, 206, 119, 164, 101, 54, 169, 115, 6, 13, 174, 143, 40, 188, 26, 44, 246, 14, 106, 101, 251, 16, 119, 143, 187, 145, 104, 109, 237, 245, 3, 157, 44, 118, 109, 7, 205, 221, 234, 62, 165, 107, 184, 127, 7, 231, 173, 36, 146, 36, 102, 185, 74, 153, 147, 62, 89, 235, 119, 123, 145, 137, 223, 246, 34, 17, 212, 51, 161, 182, 222, 250, 205, 78, 223, 211, 105, 64, 146, 152, 233, 98, 71, 107, 147, 81, 154, 212, 85, 38, 22, 80, 197, 109, 65, 83, 253, 202, 186, 3, 77, 245, 251, 177, 0, 154, 234, 51, 203, 160, 7, 152, 178, 198, 189, 147, 198, 0, 194, 88, 77, 244, 65, 146, 152, 33, 253, 84, 14, 13, 174, 141, 202, 5, 105, 147, 173, 19, 138, 102, 153, 198, 143, 93, 201, 95, 234, 77, 109, 211, 73, 14, 173, 48, 180, 223, 90, 137, 222, 53, 130, 143, 119, 141, 160, 66, 227, 180, 223, 84, 69, 176, 193, 77, 34, 101, 251, 19, 20, 218, 214, 73, 201, 28, 52, 127, 38, 127, 204, 194, 11, 190, 217, 177, 193, 36, 35, 248, 136, 160, 40, 254, 142, 164, 206, 23, 168, 226, 230, 186, 150, 78, 246, 208, 74, 225, 110, 24, 124, 82, 87, 113, 96, 152, 85, 218, 156, 42, 25, 73, 4, 209, 182, 204, 51, 130, 11, 199, 9, 143, 160, 93, 153, 43, 35, 232, 80, 73, 70, 80, 97, 109, 70, 240, 209, 218, 104, 70, 176, 65, 146, 234, 92, 146, 50, 130, 141, 103, 39, 73, 25, 193, 197, 123, 242, 111, 197, 54, 56, 52, 35, 125, 136, 181, 22, 252, 191, 40, 241, 139, 14, 103, 250, 139, 11, 205, 160, 146, 124, 244, 139, 139, 86, 108, 232, 90, 82, 162, 234, 208, 163, 95, 100, 120, 207, 133, 126, 113, 177, 184, 120, 111, 198, 47, 54, 218, 102, 43, 244, 139, 140, 207, 197, 198, 47, 50, 214, 74, 244, 139, 12, 171, 95, 182, 93, 154, 191, 162, 239, 139, 14, 173, 106, 177, 227, 218, 206, 47, 224, 16, 218, 180, 50, 135, 9, 9, 179, 19, 177, 236, 90, 192, 94, 191, 183, 133, 60, 158, 251, 250, 34, 227, 31, 63, 185, 144, 58, 126, 246, 69, 7, 95, 108, 252, 54, 14, 20, 78, 122, 101, 32, 210, 58, 174, 153, 177, 47, 70, 64, 16, 129, 9, 38, 192, 190, 8, 225, 223, 146, 125, 177, 65, 66, 195, 169, 64, 16, 32, 10, 72, 152, 0, 177, 47, 66, 34, 32, 8, 208, 4, 19, 64, 32, 1, 177, 47, 74, 164, 109, 109, 248, 34, 195, 35, 186, 118, 97, 214, 173, 190, 184, 240, 197, 198, 243, 226, 139, 11, 186, 150, 241, 245, 197, 69, 4, 95, 84, 224, 182, 194, 25, 84, 51, 5, 249, 98, 68, 131, 79, 103, 241, 234, 46, 153, 36, 149, 130, 124, 157, 111, 204, 28, 52, 181, 124, 111, 17, 19, 11, 175, 166, 1, 45, 62, 44, 173, 238, 57, 90, 253, 26, 182, 159, 115, 15, 249, 98, 195, 34, 133, 243, 233, 80, 106, 175, 193, 129, 97, 228, 216, 175, 232, 231, 51, 44, 94, 216, 243, 233, 80, 51, 113, 228, 139, 143, 38, 23, 131, 156, 131, 94, 181, 60, 73, 203, 181, 60, 55, 164, 90, 162, 212, 254, 134, 227, 207, 208, 180, 117, 94, 9, 49, 235, 225, 181, 147, 122, 163, 105, 219, 218, 107, 10, 175, 149, 232, 233, 215, 94, 210, 215, 249, 116, 8, 34, 215, 123, 80, 218, 250, 190, 13, 174, 162, 77, 67, 27, 249, 58, 139, 144, 134, 231, 91, 221, 195, 23, 29, 186, 150, 116, 154, 29, 242, 182, 185, 32, 170, 214, 29, 20, 37, 161, 182, 200, 249, 116, 42, 178, 48, 242, 69, 6, 149, 236, 66, 139, 14, 204, 53, 228, 187, 220, 90, 129, 116, 178, 16, 159, 141, 54, 228, 139, 15, 43, 251, 69, 100, 67, 190, 200, 160, 118, 229, 228, 129, 208, 245, 148, 174, 93, 152, 33, 95, 108, 172, 37, 23, 39, 92, 50, 228, 139, 12, 20, 94, 138, 19, 242, 69, 136, 198, 139, 8, 242, 69, 71, 100, 225, 8, 242, 197, 134, 198, 69, 144, 47, 50, 56, 227, 22, 110, 145, 47, 46, 232, 100, 63, 101, 235, 59, 60, 107, 65, 131, 54, 201, 182, 121, 185, 138, 46, 242, 69, 200, 98, 239, 32, 95, 92, 60, 42, 121, 118, 144, 47, 54, 210, 65, 85, 212, 65, 190, 248, 176, 184, 88, 253, 28, 79, 243, 175, 179, 211, 142, 120, 190, 87, 253, 50, 219, 32, 95, 100, 80, 71, 255, 0, 105, 12, 106, 218, 240, 126, 106, 239, 241, 109, 217, 33, 85, 156, 144, 243, 106, 41, 107, 189, 198, 32, 95, 92, 120, 186, 241, 126, 86, 236, 202, 214, 128, 185, 122, 67, 211, 137, 34, 95, 92, 168, 102, 202, 163, 18, 52, 1, 4, 17, 136, 224, 17, 205, 221, 190, 8, 241, 188, 99, 202, 88, 155, 76, 37, 137, 21, 114, 72, 47, 131, 210, 182, 12, 242, 69, 71, 179, 66, 139, 18, 142, 223, 125, 177, 193, 61, 23, 163, 115, 189, 212, 219, 106, 19, 242, 197, 133, 174, 37, 215, 202, 132, 124, 241, 209, 246, 215, 190, 5, 249, 98, 132, 47, 82, 168, 222, 69, 223, 67, 210, 114, 45, 200, 23, 25, 157, 205, 225, 219, 54, 27, 193, 4, 234, 185, 32, 95, 108, 52, 6, 165, 246, 248, 195, 241, 125, 178, 123, 145, 209, 74, 241, 134, 210, 79, 182, 45, 145, 47, 62, 86, 70, 172, 76, 251, 186, 164, 227, 86, 34, 95, 124, 240, 197, 0, 184, 118, 47, 70, 44, 58, 26, 247, 162, 194, 4, 19, 183, 232, 64, 201, 102, 44, 238, 209, 188, 36, 212, 164, 106, 88, 110, 209, 225, 107, 255, 57, 190, 233, 46, 8, 95, 251, 143, 113, 139, 15, 173, 84, 78, 224, 22, 23, 19, 184, 69, 5, 237, 22, 27, 21, 109, 180, 145, 91, 100, 184, 69, 7, 183, 24, 0, 182, 142, 156, 23, 23, 105, 27, 47, 46, 180, 170, 93, 222, 120, 241, 161, 117, 45, 238, 8, 132, 86, 9, 247, 194, 139, 12, 188, 105, 251, 175, 14, 129, 189, 117, 46, 33, 240, 162, 132, 171, 123, 254, 225, 143, 120, 241, 161, 193, 195, 172, 183, 78, 114, 59, 39, 109, 177, 225, 252, 75, 70, 191, 239, 219, 34, 196, 35, 16, 184, 191, 45, 50, 88, 106, 91, 124, 252, 115, 109, 209, 210, 71, 235, 91, 175, 236, 183, 28, 196, 3, 9, 165, 190, 190, 45, 42, 232, 36, 149, 226, 96, 160, 213, 23, 188, 182, 115, 201, 26, 207, 203, 81, 195, 202, 198, 208, 148, 204, 195, 63, 86, 239, 232, 157, 38, 136, 125, 168, 245, 27, 218, 197, 96, 233, 183, 197, 133, 214, 70, 191, 45, 46, 36, 72, 240, 109, 113, 193, 61, 65, 248, 22, 129, 24, 55, 131, 62, 37, 179, 223, 137, 214, 106, 96, 93, 190, 183, 197, 5, 205, 15, 170, 173, 4, 35, 222, 105, 214, 219, 226, 194, 61, 161, 35, 66, 3, 61, 112, 62, 221, 196, 59, 166, 203, 49, 78, 252, 47, 81, 3, 173, 189, 111, 66, 91, 100, 104, 115, 66, 14, 18, 79, 214, 248, 124, 174, 45, 66, 22, 184, 59, 240, 225, 145, 180, 69, 5, 73, 91, 124, 184, 236, 247, 196, 10, 73, 218, 34, 164, 194, 11, 146, 180, 197, 133, 164, 53, 94, 200, 171, 58, 24, 129, 140, 109, 139, 10, 156, 241, 219, 234, 180, 197, 5, 51, 109, 241, 209, 120, 209, 193, 180, 197, 198, 55, 109, 18, 161, 131, 55, 185, 38, 19, 74, 59, 29, 255, 108, 245, 56, 15, 158, 253, 21, 101, 224, 158, 43, 81, 124, 58, 198, 14, 170, 184, 77, 208, 4, 183, 69, 107, 163, 48, 106, 101, 218, 226, 227, 91, 219, 226, 66, 69, 181, 69, 133, 149, 79, 237, 100, 85, 91, 116, 84, 28, 12, 35, 215, 10, 82, 90, 81, 213, 22, 29, 120, 177, 200, 240, 172, 73, 171, 47, 140, 22, 232, 239, 162, 99, 173, 231, 160, 138, 78, 26, 39, 132, 13, 90, 157, 79, 183, 160, 85, 45, 102, 218, 162, 3, 106, 139, 142, 228, 108, 81, 225, 87, 189, 212, 9, 183, 99, 139, 19, 238, 186, 158, 98, 135, 124, 101, 19, 21, 143, 56, 143, 218, 82, 52, 48, 126, 56, 174, 205, 64, 20, 37, 33, 7, 50, 232, 114, 239, 31, 124, 49, 255, 68, 21, 146, 208, 213, 120, 126, 215, 226, 132, 126, 174, 82, 198, 22, 27, 206, 22, 27, 173, 108, 209, 225, 17, 196, 48, 171, 80, 195, 22, 31, 186, 28, 91, 71, 46, 217, 226, 195, 37, 91, 84, 240, 72, 107, 202, 254, 6, 165, 42, 121, 121, 131, 101, 13, 220, 76, 28, 181, 101, 223, 242, 77, 104, 154, 139, 104, 154, 219, 119, 140, 218, 50, 136, 70, 93, 164, 130, 25, 106, 203, 118, 37, 4, 105, 203, 24, 20, 234, 158, 103, 235, 21, 235, 14, 253, 215, 149, 174, 98, 217, 182, 125, 32, 95, 153, 3, 66, 251, 189, 203, 132, 180, 73, 182, 216, 176, 52, 255, 90, 100, 112, 7, 103, 24, 13, 203, 116, 1, 244, 44, 40, 66, 155, 91, 179, 200, 64, 209, 90, 177, 222, 204, 162, 67, 183, 50, 139, 11, 147, 166, 136, 89, 100, 104, 234, 152, 155, 46, 50, 34, 144, 64, 2, 170, 186, 184, 168, 168, 69, 5, 174, 22, 21, 120, 4, 233, 82, 139, 139, 149, 147, 71, 37, 104, 81, 139, 142, 69, 45, 42, 240, 180, 232, 240, 180, 168, 64, 127, 23, 114, 76, 26, 167, 197, 5, 73, 90, 167, 105, 113, 1, 81, 154, 22, 29, 46, 19, 210, 180, 184, 240, 8, 132, 149, 105, 113, 209, 138, 86, 166, 197, 134, 102, 182, 44, 46, 80, 143, 87, 66, 108, 89, 148, 240, 197, 252, 45, 151, 197, 70, 203, 101, 81, 193, 65, 21, 183, 6, 21, 155, 120, 49, 104, 224, 165, 125, 184, 127, 71, 53, 149, 36, 10, 103, 36, 156, 212, 160, 185, 162, 109, 2, 16, 44, 14, 192, 49, 253, 134, 67, 34, 160, 54, 1, 8, 22, 25, 218, 4, 32, 88, 84, 80, 150, 13, 125, 82, 52, 117, 220, 227, 32, 195, 243, 173, 142, 0, 239, 250, 38, 56, 90, 37, 109, 215, 67, 237, 162, 213, 61, 14, 66, 154, 54, 143, 131, 11, 143, 196, 159, 131, 11, 173, 237, 57, 184, 96, 245, 131, 248, 91, 238, 193, 25, 210, 138, 213, 138, 245, 71, 20, 72, 43, 54, 66, 43, 86, 217, 190, 195, 87, 182, 102, 189, 97, 229, 164, 245, 155, 131, 90, 212, 146, 61, 7, 25, 109, 23, 196, 205, 115, 144, 241, 236, 124, 33, 73, 185, 252, 215, 173, 227, 144, 166, 234, 222, 224, 186, 94, 183, 205, 94, 148, 53, 207, 57, 244, 115, 121, 203, 126, 6, 62, 225, 40, 226, 121, 121, 14, 46, 124, 211, 38, 221, 33, 220, 253, 59, 184, 160, 27, 33, 130, 132, 42, 78, 232, 209, 40, 172, 254, 57, 206, 63, 241, 84, 184, 23, 188, 179, 243, 8, 114, 104, 218, 114, 243, 143, 37, 109, 23, 68, 211, 150, 113, 106, 11, 113, 247, 147, 213, 164, 170, 97, 173, 76, 158, 246, 91, 50, 117, 164, 78, 202, 68, 145, 214, 115, 113, 184, 34, 167, 68, 56, 255, 26, 223, 255, 14, 62, 220, 191, 131, 10, 143, 157, 95, 10, 138, 240, 112, 112, 203, 246, 109, 23, 67, 21, 167, 10, 64, 168, 69, 17, 68, 32, 48, 202, 69, 120, 120, 78, 90, 166, 8, 174, 44, 27, 106, 242, 145, 78, 246, 13, 224, 110, 37, 46, 128, 137, 126, 76, 0, 137, 175, 82, 157, 78, 3, 174, 150, 39, 205, 14, 218, 240, 21, 125, 196, 175, 146, 100, 140, 114, 136, 223, 27, 77, 62, 195, 117, 61, 255, 73, 151, 250, 131, 129, 136, 8, 15, 179, 20, 173, 203, 108, 91, 246, 174, 17, 212, 234, 50, 121, 67, 43, 195, 108, 243, 5, 46, 25, 98, 186, 20, 194, 88, 73, 184, 254, 91, 182, 255, 19, 45, 246, 14, 62, 44, 246, 14, 42, 76, 222, 114, 7, 23, 210, 29, 116, 44, 119, 176, 241, 141, 209, 118, 16, 50, 193, 57, 168, 192, 57, 7, 21, 56, 137, 147, 164, 116, 14, 50, 90, 23, 133, 29, 100, 240, 8, 242, 71, 37, 207, 14, 58, 252, 217, 113, 244, 236, 96, 35, 215, 99, 7, 37, 116, 237, 59, 59, 184, 120, 28, 179, 131, 11, 74, 43, 203, 160, 135, 47, 232, 90, 82, 189, 35, 9, 179, 131, 12, 110, 236, 160, 130, 71, 80, 107, 163, 114, 121, 180, 177, 131, 14, 16, 189, 74, 25, 59, 184, 168, 160, 125, 12, 180, 81, 219, 139, 50, 118, 208, 225, 124, 58, 164, 140, 29, 108, 56, 246, 168, 25, 41, 99, 71, 45, 118, 144, 225, 220, 208, 251, 178, 131, 13, 60, 2, 161, 101, 195, 14, 50, 36, 202, 14, 42, 64, 144, 142, 167, 100, 14, 50, 154, 197, 193, 134, 71, 32, 248, 114, 144, 161, 177, 71, 28, 92, 88, 10, 146, 192, 133, 175, 210, 94, 7, 23, 173, 155, 78, 114, 235, 32, 196, 243, 171, 118, 177, 35, 143, 68, 32, 48, 176, 38, 76, 104, 115, 66, 174, 154, 41, 20, 174, 232, 157, 102, 23, 68, 181, 92, 78, 179, 14, 50, 244, 77, 28, 28, 72, 248, 119, 58, 201, 105, 2, 234, 216, 224, 147, 46, 117, 100, 80, 109, 85, 75, 29, 25, 188, 8, 241, 235, 37, 211, 168, 35, 196, 63, 150, 168, 58, 46, 220, 86, 44, 72, 162, 234, 216, 80, 170, 142, 14, 165, 234, 248, 104, 240, 213, 232, 151, 212, 161, 217, 17, 2, 2, 201, 4, 18, 68, 112, 73, 29, 27, 206, 178, 211, 53, 248, 59, 205, 122, 91, 132, 15, 14, 220, 117, 177, 84, 71, 9, 167, 28, 21, 168, 231, 130, 36, 202, 145, 209, 90, 177, 238, 201, 209, 225, 113, 134, 71, 26, 238, 233, 228, 8, 129, 164, 109, 146, 61, 156, 87, 75, 65, 157, 75, 131, 82, 165, 218, 16, 179, 104, 1, 138, 238, 4, 241, 183, 117, 208, 188, 147, 116, 116, 65, 15, 77, 91, 100, 104, 168, 40, 194, 7, 220, 45, 28, 191, 196, 85, 161, 103, 199, 37, 214, 122, 12, 58, 28, 39, 71, 135, 235, 194, 117, 127, 211, 62, 133, 175, 253, 135, 144, 70, 70, 114, 124, 180, 126, 114, 132, 44, 109, 45, 157, 132, 146, 163, 227, 97, 214, 17, 178, 56, 6, 192, 155, 86, 210, 113, 161, 146, 142, 10, 30, 19, 85, 72, 39, 233, 200, 208, 73, 58, 42, 32, 77, 47, 29, 25, 124, 219, 213, 248, 228, 233, 8, 113, 79, 71, 133, 86, 231, 210, 145, 193, 73, 159, 238, 113, 79, 16, 32, 19, 139, 189, 211, 128, 17, 141, 61, 194, 142, 31, 105, 75, 199, 134, 86, 213, 210, 145, 193, 91, 151, 89, 247, 252, 2, 20, 118, 28, 61, 157, 239, 83, 75, 71, 7, 150, 206, 210, 145, 225, 97, 118, 177, 116, 92, 176, 116, 124, 188, 175, 66, 30, 129, 192, 11, 65, 215, 50, 16, 172, 25, 73, 152, 29, 228, 32, 241, 85, 200, 215, 166, 227, 194, 202, 137, 162, 118, 52, 196, 23, 232, 100, 177, 71, 168, 104, 163, 93, 209, 70, 123, 66, 189, 31, 218, 114, 228, 115, 49, 13, 136, 50, 233, 248, 104, 117, 82, 123, 185, 30, 42, 203, 160, 69, 45, 138, 0, 2, 180, 157, 76, 58, 70, 168, 74, 71, 5, 137, 114, 148, 46, 193, 145, 65, 105, 107, 214, 37, 56, 50, 90, 39, 45, 193, 145, 65, 130, 35, 196, 195, 203, 169, 66, 18, 28, 27, 17, 28, 31, 17, 223, 118, 249, 63, 156, 95, 10, 114, 201, 222, 95, 58, 21, 7, 210, 43, 242, 72, 165, 145, 225, 145, 74, 163, 130, 75, 232, 239, 66, 149, 198, 69, 165, 49, 0, 148, 198, 0, 184, 186, 231, 219, 107, 100, 180, 215, 216, 104, 218, 180, 215, 200, 224, 218, 94, 227, 66, 123, 237, 53, 62, 144, 64, 237, 53, 66, 94, 35, 163, 113, 66, 237, 53, 46, 82, 123, 60, 81, 123, 141, 13, 247, 180, 190, 145, 97, 125, 163, 195, 77, 188, 81, 65, 215, 146, 143, 32, 250, 251, 188, 145, 193, 189, 81, 129, 3, 87, 247, 124, 131, 174, 37, 41, 188, 152, 70, 200, 4, 230, 141, 143, 9, 204, 27, 21, 92, 69, 145, 98, 198, 212, 161, 244, 244, 70, 135, 174, 215, 141, 11, 158, 92, 163, 131, 71, 32, 44, 157, 112, 35, 195, 221, 162, 110, 134, 214, 138, 109, 13, 39, 109, 8, 136, 42, 110, 14, 253, 199, 141, 15, 126, 164, 218, 227, 70, 134, 58, 110, 108, 112, 62, 221, 51, 55, 50, 158, 185, 209, 225, 18, 230, 198, 5, 95, 251, 79, 66, 223, 228, 249, 78, 28, 60, 204, 174, 230, 69, 120, 117, 79, 157, 180, 250, 132, 123, 114, 85, 220, 144, 55, 224, 170, 184, 185, 42, 110, 141, 61, 34, 225, 124, 186, 5, 180, 98, 93, 215, 50, 106, 237, 91, 92, 253, 35, 40, 158, 213, 24, 185, 123, 196, 189, 150, 186, 210, 2, 173, 88, 71, 186, 84, 123, 15, 150, 46, 185, 76, 240, 63, 6, 90, 43, 158, 149, 45, 145, 193, 0, 58, 151, 181, 88, 23, 47, 44, 19, 55, 62, 124, 82, 119, 224, 250, 153, 86, 105, 187, 8, 157, 44, 246, 137, 71, 207, 223, 178, 45, 107, 125, 85, 18, 238, 218, 111, 225, 198, 7, 132, 13, 221, 201, 141, 11, 76, 181, 70, 133, 119, 118, 80, 107, 116, 88, 120, 45, 173, 177, 161, 25, 214, 168, 144, 88, 227, 131, 31, 173, 245, 28, 74, 172, 113, 2, 37, 214, 24, 145, 88, 35, 4, 107, 116, 36, 214, 8, 113, 171, 81, 65, 91, 134, 26, 34, 48, 1, 4, 138, 169, 219, 198, 134, 74, 71, 225, 214, 120, 167, 217, 198, 7, 99, 182, 83, 157, 70, 72, 170, 211, 168, 208, 188, 56, 45, 77, 35, 163, 162, 78, 132, 165, 105, 92, 84, 180, 209, 70, 75, 211, 216, 168, 168, 131, 150, 166, 113, 177, 52, 141, 10, 146, 98, 26, 21, 34, 68, 128, 2, 19, 36, 166, 113, 49, 129, 8, 38, 136, 32, 49, 141, 139, 95, 223, 9, 132, 129, 164, 153, 162, 141, 12, 146, 196, 204, 161, 189, 20, 109, 100, 104, 126, 104, 163, 137, 54, 50, 30, 102, 253, 105, 39, 122, 250, 181, 113, 65, 123, 159, 237, 107, 227, 130, 194, 237, 188, 54, 46, 22, 37, 105, 235, 188, 54, 54, 32, 252, 91, 186, 231, 59, 153, 75, 180, 253, 92, 16, 135, 175, 232, 55, 42, 104, 101, 47, 226, 205, 221, 234, 224, 15, 15, 179, 239, 218, 184, 80, 149, 41, 25, 244, 174, 141, 143, 119, 109, 84, 152, 108, 132, 74, 118, 65, 188, 177, 115, 109, 108, 240, 111, 118, 21, 133, 176, 250, 73, 172, 126, 174, 158, 187, 18, 249, 75, 48, 111, 225, 231, 118, 202, 178, 57, 15, 49, 89, 252, 192, 184, 93, 215, 50, 144, 94, 149, 154, 170, 166, 78, 85, 3, 69, 73, 143, 230, 86, 34, 132, 36, 108, 56, 40, 157, 244, 187, 82, 154, 65, 87, 69, 133, 86, 108, 67, 123, 23, 84, 84, 181, 109, 24, 43, 27, 239, 59, 174, 128, 147, 50, 181, 7, 161, 218, 175, 147, 197, 142, 180, 87, 233, 90, 167, 44, 27, 133, 178, 108, 201, 84, 178, 171, 25, 238, 85, 15, 238, 148, 12, 194, 130, 119, 120, 243, 187, 166, 150, 8, 35, 158, 126, 237, 124, 127, 120, 201, 13, 77, 190, 34, 200, 187, 62, 110, 134, 161, 40, 105, 173, 68, 19, 180, 113, 193, 124, 219, 229, 242, 205, 78, 27, 29, 13, 107, 165, 227, 1, 93, 203, 160, 182, 15, 72, 83, 46, 135, 30, 184, 104, 72, 117, 218, 232, 160, 86, 130, 13, 253, 109, 74, 235, 132, 31, 190, 86, 38, 196, 178, 105, 227, 2, 215, 148, 206, 115, 101, 167, 83, 71, 77, 219, 181, 217, 255, 224, 129, 241, 130, 116, 130, 12, 19, 85, 19, 171, 31, 106, 219, 108, 51, 210, 103, 246, 204, 180, 209, 161, 113, 218, 202, 50, 109, 108, 164, 82, 166, 141, 12, 149, 237, 79, 182, 164, 47, 72, 252, 250, 185, 28, 73, 58, 217, 227, 164, 182, 82, 165, 173, 106, 95, 227, 157, 46, 194, 249, 100, 143, 246, 88, 107, 118, 37, 82, 183, 174, 105, 171, 84, 58, 180, 150, 166, 7, 154, 198, 253, 254, 64, 215, 107, 6, 250, 86, 78, 124, 23, 2, 92, 169, 63, 2, 184, 106, 207, 0, 62, 161, 218, 34, 93, 75, 254, 0, 36, 109, 87, 2, 180, 73, 182, 232, 95, 250, 102, 5, 120, 231, 90, 172, 16, 55, 244, 109, 87, 3, 139, 189, 195, 152, 198, 33, 225, 250, 220, 158, 153, 129, 112, 73, 219, 181, 96, 35, 204, 20, 82, 145, 88, 61, 92, 146, 218, 75, 3, 58, 112, 201, 180, 209, 129, 155, 149, 21, 8, 29, 16, 143, 75, 152, 157, 199, 83, 128, 39, 151, 42, 173, 228, 210, 70, 136, 178, 77, 45, 219, 178, 183, 36, 244, 83, 97, 195, 202, 73, 235, 183, 213, 198, 5, 103, 160, 255, 150, 109, 110, 224, 65, 210, 201, 32, 148, 108, 71, 69, 98, 245, 240, 166, 173, 74, 117, 212, 61, 142, 54, 58, 96, 188, 156, 67, 69, 104, 253, 207, 228, 14, 42, 130, 182, 93, 15, 21, 161, 185, 91, 209, 106, 180, 17, 178, 26, 109, 84, 240, 72, 163, 141, 143, 166, 18, 254, 167, 39, 176, 129, 54, 39, 4, 121, 206, 85, 22, 44, 59, 93, 197, 155, 92, 12, 4, 8, 255, 84, 251, 145, 171, 60, 124, 253, 89, 217, 18, 189, 39, 114, 149, 166, 13, 163, 213, 59, 93, 69, 27, 109, 132, 44, 152, 104, 126, 184, 238, 183, 42, 78, 219, 30, 114, 64, 181, 209, 177, 246, 95, 195, 239, 115, 134, 4, 71, 142, 239, 90, 158, 91, 240, 52, 218, 232, 96, 27, 212, 180, 121, 84, 130, 26, 109, 92, 192, 23, 243, 51, 218, 200, 120, 84, 222, 98, 180, 145, 161, 194, 75, 165, 225, 143, 74, 26, 133, 31, 24, 126, 109, 32, 48, 72, 186, 24, 109, 132, 120, 210, 46, 118, 168, 241, 33, 25, 109, 84, 88, 133, 26, 24, 109, 116, 172, 203, 134, 24, 109, 100, 48, 218, 168, 64, 211, 75, 175, 60, 213, 94, 127, 83, 111, 185, 92, 54, 233, 174, 109, 155, 244, 108, 210, 29, 149, 167, 214, 99, 143, 202, 83, 206, 237, 98, 80, 197, 93, 153, 58, 191, 160, 225, 181, 128, 131, 230, 223, 198, 12, 73, 18, 43, 52, 81, 89, 204, 201, 209, 56, 165, 66, 116, 105, 160, 212, 73, 159, 203, 2, 231, 159, 196, 186, 68, 149, 79, 137, 26, 149, 167, 180, 113, 161, 217, 27, 162, 161, 178, 114, 211, 46, 199, 214, 31, 172, 149, 9, 81, 52, 253, 207, 197, 56, 164, 149, 9, 185, 39, 124, 232, 124, 87, 218, 184, 216, 149, 80, 35, 177, 210, 198, 5, 73, 226, 165, 180, 113, 33, 73, 204, 36, 137, 23, 51, 109, 29, 190, 14, 253, 254, 86, 66, 190, 171, 180, 113, 65, 233, 163, 74, 27, 23, 159, 82, 27, 85, 120, 81, 218, 8, 241, 215, 78, 234, 232, 83, 42, 109, 116, 160, 232, 78, 222, 119, 117, 35, 132, 147, 62, 41, 15, 169, 61, 142, 24, 32, 140, 72, 237, 113, 180, 40, 217, 73, 27, 33, 77, 211, 70, 6, 107, 57, 105, 35, 67, 47, 59, 73, 27, 23, 186, 82, 162, 67, 194, 4, 61, 94, 180, 113, 225, 158, 139, 54, 50, 180, 78, 82, 27, 25, 94, 213, 113, 196, 248, 159, 23, 132, 13, 156, 79, 183, 82, 27, 31, 216, 90, 104, 218, 182, 78, 10, 250, 149, 64, 126, 37, 251, 251, 144, 182, 93, 218, 118, 169, 182, 107, 33, 11, 175, 6, 245, 42, 149, 218, 8, 113, 217, 13, 252, 104, 81, 74, 106, 255, 3, 203, 199, 225, 209, 72, 220, 106, 172, 212, 210, 84, 209, 73, 83, 164, 82, 27, 66, 210, 158, 163, 78, 202, 228, 112, 15, 165, 94, 186, 228, 178, 86, 34, 165, 224, 178, 223, 43, 79, 77, 246, 179, 237, 106, 220, 207, 158, 150, 93, 18, 87, 213, 180, 162, 65, 151, 247, 143, 31, 231, 151, 226, 252, 82, 188, 169, 163, 9, 59, 191, 239, 157, 80, 116, 39, 251, 30, 163, 173, 159, 239, 234, 47, 98, 81, 202, 132, 191, 8, 245, 71, 161, 254, 246, 215, 123, 109, 212, 82, 208, 2, 7, 213, 169, 139, 106, 51, 7, 73, 184, 253, 197, 252, 139, 31, 15, 179, 239, 201, 255, 180, 253, 6, 108, 63, 130, 173, 50, 117, 38, 42, 250, 174, 63, 209, 216, 113, 186, 212, 155, 252, 135, 38, 127, 201, 255, 252, 246, 248, 218, 127, 218, 156, 16, 69, 119, 130, 214, 146, 234, 150, 226, 150, 178, 43, 161, 137, 55, 39, 212, 76, 188, 153, 120, 227, 125, 213, 190, 70, 215, 243, 174, 235, 121, 222, 31, 183, 237, 151, 48, 59, 72, 155, 108, 158, 80, 197, 109, 41, 47, 8, 226, 145, 164, 125, 175, 88, 10, 114, 250, 105, 63, 223, 59, 223, 219, 58, 215, 182, 75, 210, 233, 60, 162, 154, 66, 16, 72, 163, 176, 82, 181, 203, 153, 86, 64, 152, 46, 199, 84, 113, 202, 73, 203, 132, 180, 223, 103, 107, 214, 115, 81, 181, 222, 208, 204, 16, 133, 29, 167, 208, 78, 199, 25, 80, 88, 165, 195, 88, 161, 247, 93, 237, 241, 100, 224, 147, 46, 117, 71, 157, 75, 131, 191, 231, 66, 146, 182, 11, 57, 158, 14, 99, 245, 143, 187, 161, 222, 58, 161, 88, 169, 147, 125, 43, 21, 51, 6, 15, 204, 34, 165, 189, 111, 130, 54, 90, 139, 153, 53, 120, 114, 105, 51, 218, 217, 76, 69, 23, 163, 253, 158, 252, 18, 149, 167, 180, 215, 166, 198, 73, 91, 251, 179, 221, 227, 110, 40, 122, 130, 174, 166, 225, 71, 142, 91, 157, 29, 43, 191, 249, 193, 35, 16, 158, 245, 188, 28, 68, 210, 118, 33, 181, 185, 92, 196, 174, 213, 38, 157, 187, 111, 218, 182, 170, 102, 135, 166, 14, 5, 61, 171, 113, 235, 194, 222, 132, 42, 118, 71, 220, 124, 201, 111, 176, 40, 229, 217, 113, 68, 209, 157, 48, 96, 85, 59, 225, 79, 58, 121, 160, 246, 189, 198, 219, 180, 117, 207, 59, 240, 164, 166, 157, 174, 173, 36, 101, 127, 1, 26, 104, 117, 75, 113, 75, 105, 38, 238, 205, 196, 153, 151, 167, 249, 29, 232, 92, 84, 123, 44, 225, 178, 45, 208, 250, 159, 15, 180, 211, 241, 37, 31, 45, 254, 166, 172, 209, 2, 56, 69, 119, 146, 218, 137, 148, 73, 255, 206, 119, 10, 157, 236, 98, 239, 56, 112, 60, 149, 182, 210, 108, 253, 103, 105, 38, 168, 153, 193, 107, 202, 144, 123, 142, 25, 229, 92, 58, 109, 210, 241, 66, 77, 183, 185, 129, 98, 182, 82, 49, 147, 248, 138, 62, 210, 5, 11, 218, 166, 147, 30, 149, 80, 116, 39, 72, 59, 41, 137, 20, 160, 146, 164, 36, 114, 170, 146, 230, 207, 180, 170, 109, 107, 94, 180, 145, 115, 217, 22, 57, 151, 168, 237, 2, 140, 185, 130, 49, 87, 160, 150, 14, 105, 147, 140, 1, 199, 157, 92, 46, 69, 119, 178, 216, 59, 41, 23, 165, 202, 160, 180, 239, 210, 105, 224, 211, 73, 72, 233, 51, 219, 160, 215, 230, 1, 77, 59, 105, 117, 196, 139, 181, 113, 199, 115, 49, 219, 74, 209, 93, 151, 200, 73, 175, 204, 87, 180, 33, 229, 11, 35, 33, 105, 187, 208, 218, 100, 148, 236, 73, 211, 231, 9, 102, 218, 34, 77, 59, 81, 7, 159, 170, 129, 71, 16, 191, 123, 250, 83, 190, 42, 78, 214, 7, 104, 150, 105, 19, 105, 219, 99, 140, 19, 3, 138, 81, 75, 93, 105, 129, 95, 9, 250, 78, 39, 165, 150, 189, 76, 56, 158, 203, 249, 51, 47, 207, 98, 92, 57, 122, 120, 113, 254, 37, 114, 206, 95, 68, 169, 58, 14, 152, 253, 245, 34, 38, 60, 97, 86, 181, 147, 136, 149, 138, 217, 86, 150, 53, 101, 92, 209, 32, 87, 41, 235, 231, 169, 172, 65, 21, 27, 192, 62, 79, 74, 37, 158, 108, 53, 79, 46, 135, 116, 255, 121, 241, 126, 86, 236, 202, 196, 171, 241, 235, 82, 137, 51, 88, 154, 151, 35, 9, 38, 168, 177, 82, 137, 218, 29, 233, 90, 82, 37, 27, 64, 37, 59, 30, 102, 37, 109, 215, 186, 219, 181, 20, 185, 182, 93, 174, 43, 61, 73, 153, 93, 12, 188, 46, 38, 181, 113, 120, 42, 114, 65, 228, 164, 177, 196, 35, 238, 17, 214, 204, 52, 246, 8, 106, 236, 17, 110, 236, 17, 214, 145, 68, 205, 191, 18, 102, 7, 41, 253, 246, 152, 33, 223, 5, 74, 63, 147, 182, 83, 133, 124, 151, 177, 190, 173, 132, 217, 65, 12, 48, 78, 173, 223, 246, 185, 214, 76, 92, 194, 236, 160, 5, 154, 108, 133, 178, 229, 170, 246, 42, 219, 60, 36, 222, 180, 117, 6, 174, 77, 178, 10, 47, 239, 52, 187, 90, 215, 202, 166, 181, 73, 182, 142, 59, 33, 109, 146, 65, 104, 147, 12, 194, 108, 47, 181, 171, 158, 11, 106, 156, 246, 225, 43, 218, 38, 0, 193, 74, 152, 29, 212, 240, 158, 252, 232, 217, 89, 151, 232, 217, 145, 48, 59, 173, 174, 154, 41, 232, 193, 105, 214, 121, 101, 75, 29, 8, 75, 135, 189, 218, 110, 248, 201, 133, 212, 118, 35, 97, 130, 180, 25, 184, 54, 205, 115, 214, 6, 34, 130, 108, 178, 97, 60, 21, 21, 143, 105, 170, 157, 28, 173, 245, 34, 24, 43, 196, 184, 43, 84, 155, 129, 176, 108, 214, 204, 52, 70, 254, 18, 59, 72, 18, 47, 228, 47, 241, 226, 118, 73, 232, 132, 25, 114, 187, 212, 118, 131, 42, 188, 84, 116, 73, 252, 74, 80, 147, 235, 151, 105, 236, 83, 207, 69, 123, 25, 103, 167, 107, 25, 7, 93, 203, 56, 159, 202, 232, 155, 208, 201, 208, 123, 50, 18, 239, 18, 75, 43, 235, 154, 54, 157, 60, 185, 90, 39, 60, 241, 116, 170, 246, 120, 65, 205, 221, 218, 52, 143, 32, 126, 244, 120, 42, 132, 227, 78, 232, 241, 212, 6, 218, 184, 194, 113, 171, 181, 100, 211, 100, 187, 110, 243, 167, 100, 16, 99, 198, 76, 146, 88, 57, 30, 104, 224, 234, 158, 119, 220, 78, 1, 221, 58, 223, 167, 68, 77, 155, 196, 170, 105, 147, 24, 226, 164, 199, 13, 222, 245, 155, 98, 160, 141, 43, 40, 36, 88, 236, 29, 164, 154, 106, 160, 154, 114, 38, 17, 136, 0, 4, 104, 178, 15, 154, 114, 57, 95, 102, 39, 74, 241, 44, 80, 182, 175, 159, 74, 63, 213, 167, 202, 79, 181, 128, 218, 110, 80, 126, 170, 8, 168, 115, 105, 224, 171, 252, 53, 123, 191, 137, 39, 136, 137, 167, 6, 87, 157, 9, 253, 42, 109, 70, 27, 233, 167, 54, 132, 123, 223, 94, 115, 227, 109, 180, 29, 104, 114, 49, 232, 233, 111, 143, 41, 220, 208, 68, 163, 176, 250, 246, 156, 153, 79, 56, 51, 231, 71, 143, 227, 212, 64, 213, 250, 63, 150, 164, 93, 169, 49, 90, 204, 201, 191, 169, 55, 78, 104, 37, 12, 121, 77, 217, 87, 244, 91, 133, 151, 197, 252, 232, 27, 167, 135, 166, 223, 188, 241, 122, 83, 182, 10, 181, 182, 205, 111, 156, 22, 96, 189, 76, 155, 216, 127, 101, 218, 163, 104, 117, 118, 204, 27, 57, 88, 143, 105, 94, 220, 236, 46, 215, 138, 160, 138, 147, 242, 8, 132, 79, 202, 48, 138, 84, 173, 127, 211, 93, 13, 92, 219, 46, 228, 88, 174, 212, 185, 160, 166, 173, 214, 58, 136, 128, 60, 242, 157, 142, 219, 197, 32, 213, 15, 207, 210, 182, 75, 217, 62, 106, 224, 240, 154, 50, 212, 218, 244, 91, 154, 35, 12, 224, 43, 218, 144, 174, 37, 255, 91, 87, 190, 42, 197, 189, 113, 218, 166, 101, 235, 167, 106, 86, 37, 175, 246, 180, 153, 209, 69, 162, 105, 187, 158, 119, 52, 1, 4, 234, 185, 168, 226, 212, 185, 52, 104, 165, 85, 173, 125, 11, 3, 157, 159, 19, 72, 106, 231, 87, 244, 145, 86, 172, 55, 120, 144, 218, 227, 143, 239, 255, 183, 188, 166, 12, 229, 246, 130, 220, 86, 218, 75, 209, 142, 112, 78, 194, 27, 47, 132, 126, 178, 165, 112, 158, 153, 57, 146, 180, 93, 2, 248, 214, 245, 152, 104, 160, 109, 101, 25, 106, 85, 77, 145, 55, 86, 234, 1, 77, 105, 129, 7, 2, 8, 18, 29, 159, 82, 219, 73, 169, 141, 141, 8, 218, 168, 64, 215, 146, 218, 8, 105, 116, 120, 4, 49, 170, 145, 65, 43, 182, 113, 203, 132, 24, 213, 8, 105, 203, 164, 70, 198, 175, 210, 212, 200, 240, 190, 43, 53, 62, 164, 198, 134, 106, 171, 54, 82, 182, 143, 82, 163, 131, 47, 249, 40, 53, 46, 254, 177, 186, 165, 56, 74, 141, 15, 119, 250, 142, 82, 35, 35, 53, 54, 144, 86, 172, 107, 163, 212, 40, 209, 120, 81, 106, 108, 72, 141, 143, 212, 248, 240, 154, 50, 148, 26, 23, 218, 239, 93, 27, 148, 26, 29, 172, 153, 65, 169, 83, 83, 178, 21, 74, 141, 141, 102, 153, 6, 161, 238, 114, 45, 86, 149, 201, 59, 85, 211, 149, 9, 165, 198, 135, 126, 178, 109, 137, 82, 163, 35, 53, 6, 192, 241, 183, 52, 46, 80, 178, 209, 241, 40, 94, 16, 37, 27, 25, 30, 65, 77, 39, 217, 200, 104, 197, 135, 174, 101, 43, 186, 24, 212, 186, 64, 63, 27, 33, 146, 78, 208, 103, 227, 34, 29, 207, 198, 133, 165, 233, 184, 108, 92, 56, 233, 241, 59, 190, 217, 29, 127, 238, 161, 77, 43, 123, 150, 115, 217, 77, 203, 70, 8, 164, 162, 206, 90, 203, 48, 118, 164, 253, 100, 236, 95, 1, 125, 126, 19, 42, 240, 224, 170, 153, 2, 209, 224, 145, 6, 211, 223, 7, 132, 177, 106, 217, 200, 224, 42, 170, 90, 54, 46, 84, 203, 70, 71, 54, 62, 52, 189, 116, 199, 167, 246, 34, 42, 81, 67, 42, 150, 141, 11, 169, 22, 150, 141, 12, 30, 121, 141, 165, 27, 33, 92, 37, 247, 218, 108, 140, 168, 96, 178, 81, 97, 49, 217, 168, 160, 156, 228, 139, 217, 33, 38, 27, 25, 76, 54, 42, 224, 85, 217, 8, 97, 158, 20, 212, 118, 201, 70, 71, 132, 198, 0, 52, 246, 8, 106, 116, 64, 134, 124, 101, 170, 107, 73, 5, 161, 207, 111, 66, 123, 13, 252, 38, 32, 228, 77, 192, 134, 71, 22, 191, 237, 77, 192, 133, 252, 165, 106, 130, 215, 130, 40, 214, 218, 55, 1, 23, 30, 175, 23, 146, 164, 125, 19, 176, 33, 73, 251, 14, 137, 231, 115, 167, 101, 72, 223, 131, 54, 191, 171, 147, 210, 245, 77, 64, 135, 167, 245, 77, 128, 48, 86, 136, 194, 42, 29, 71, 173, 111, 2, 62, 232, 244, 124, 19, 144, 193, 125, 2, 42, 120, 152, 245, 9, 8, 209, 55, 129, 224, 120, 232, 9, 200, 224, 145, 9, 19, 80, 161, 117, 89, 120, 77, 192, 133, 47, 28, 153, 128, 11, 145, 9, 24, 0, 94, 52, 1, 21, 22, 77, 64, 5, 19, 16, 0, 159, 94, 127, 195, 90, 234, 56, 106, 236, 252, 227, 16, 226, 171, 226, 80, 193, 215, 254, 155, 184, 127, 14, 25, 30, 65, 173, 142, 63, 135, 141, 182, 156, 126, 23, 148, 159, 202, 241, 231, 16, 194, 35, 16, 28, 127, 14, 23, 254, 232, 97, 182, 159, 67, 71, 131, 197, 222, 65, 140, 155, 65, 18, 200, 120, 215, 126, 14, 25, 250, 53, 210, 126, 14, 27, 206, 175, 212, 119, 148, 253, 21, 125, 64, 155, 19, 114, 192, 70, 186, 231, 80, 65, 21, 167, 167, 61, 135, 12, 10, 171, 182, 148, 135, 174, 37, 29, 127, 14, 173, 245, 26, 75, 39, 186, 90, 25, 85, 142, 207, 132, 214, 122, 14, 25, 41, 121, 14, 21, 36, 43, 41, 110, 251, 29, 53, 207, 109, 46, 8, 135, 74, 126, 70, 171, 164, 237, 66, 205, 115, 232, 240, 71, 115, 183, 54, 109, 154, 231, 16, 226, 253, 159, 168, 121, 14, 27, 205, 115, 168, 192, 35, 8, 27, 203, 107, 203, 115, 8, 121, 215, 71, 74, 29, 39, 111, 175, 1, 183, 141, 180, 107, 121, 14, 29, 30, 166, 13, 65, 181, 223, 29, 62, 92, 178, 134, 174, 76, 188, 16, 162, 218, 143, 220, 29, 46, 222, 119, 33, 119, 184, 232, 118, 168, 64, 123, 223, 4, 71, 211, 22, 98, 210, 28, 26, 218, 166, 147, 30, 79, 191, 54, 4, 207, 142, 55, 213, 78, 174, 0, 20, 129, 0, 42, 201, 197, 64, 160, 3, 222, 104, 224, 190, 56, 45, 224, 17, 230, 45, 252, 252, 220, 14, 29, 20, 221, 9, 132, 239, 106, 224, 96, 169, 226, 8, 151, 236, 81, 201, 122, 253, 207, 181, 125, 154, 223, 215, 153, 200, 102, 65, 179, 247, 75, 142, 91, 49, 112, 213, 146, 49, 138, 37, 215, 226, 132, 154, 187, 151, 169, 75, 56, 110, 231, 156, 29, 183, 195, 69, 187, 138, 54, 120, 243, 35, 17, 129, 240, 1, 53, 109, 41, 244, 179, 73, 199, 237, 16, 4, 58, 84, 103, 5, 195, 223, 61, 203, 37, 122, 247, 142, 113, 59, 100, 120, 152, 93, 43, 19, 122, 152, 117, 120, 90, 162, 135, 89, 103, 193, 139, 84, 231, 162, 36, 41, 23, 8, 16, 30, 64, 112, 60, 29, 8, 234, 251, 180, 132, 160, 190, 136, 127, 226, 31, 43, 219, 95, 255, 234, 43, 247, 37, 158, 254, 167, 95, 123, 129, 175, 210, 126, 250, 38, 52, 232, 100, 189, 95, 210, 70, 238, 184, 93, 243, 191, 164, 21, 69, 139, 23, 60, 204, 170, 226, 38, 241, 78, 179, 139, 105, 235, 164, 84, 136, 66, 234, 203, 218, 166, 227, 224, 146, 148, 75, 196, 90, 153, 36, 90, 37, 169, 189, 60, 232, 231, 66, 107, 37, 106, 128, 11, 255, 124, 71, 169, 65, 254, 212, 121, 101, 220, 14, 39, 24, 183, 195, 71, 211, 8, 183, 67, 6, 101, 217, 208, 39, 141, 112, 187, 135, 206, 5, 49, 176, 32, 77, 79, 113, 59, 124, 112, 208, 24, 194, 155, 78, 36, 73, 251, 21, 109, 20, 254, 190, 21, 135, 9, 92, 209, 3, 23, 13, 47, 148, 184, 29, 50, 158, 23, 110, 135, 12, 171, 129, 160, 11, 183, 67, 134, 126, 78, 22, 30, 249, 148, 218, 57, 201, 8, 74, 251, 192, 88, 161, 180, 143, 100, 234, 36, 71, 18, 204, 183, 29, 66, 60, 162, 79, 223, 132, 231, 183, 121, 219, 225, 67, 132, 193, 41, 116, 45, 217, 240, 117, 30, 125, 219, 102, 124, 74, 237, 166, 45, 188, 113, 90, 71, 69, 23, 163, 108, 219, 97, 131, 59, 37, 131, 176, 114, 162, 21, 235, 142, 93, 233, 33, 73, 251, 38, 56, 67, 143, 178, 253, 118, 26, 154, 187, 53, 63, 213, 163, 194, 203, 243, 240, 64, 42, 13, 137, 8, 253, 165, 19, 103, 224, 21, 219, 178, 105, 30, 64, 78, 50, 210, 236, 136, 129, 138, 186, 164, 248, 182, 203, 245, 65, 117, 170, 150, 239, 168, 89, 166, 177, 3, 73, 82, 39, 185, 254, 179, 160, 214, 253, 215, 118, 232, 240, 77, 93, 219, 225, 66, 21, 55, 109, 135, 14, 72, 53, 117, 218, 14, 33, 42, 121, 105, 59, 100, 176, 232, 192, 28, 82, 218, 8, 209, 118, 237, 144, 225, 83, 219, 164, 237, 144, 225, 52, 105, 59, 116, 80, 8, 225, 30, 119, 131, 90, 246, 55, 248, 138, 126, 115, 104, 248, 148, 218, 14, 25, 28, 127, 14, 105, 59, 100, 120, 164, 105, 83, 121, 231, 176, 241, 116, 246, 178, 171, 223, 57, 164, 96, 184, 157, 195, 5, 95, 170, 152, 237, 226, 160, 107, 25, 150, 221, 228, 42, 7, 26, 251, 170, 231, 34, 0, 6, 43, 61, 81, 15, 224, 43, 15, 104, 115, 66, 15, 218, 180, 50, 9, 20, 123, 52, 104, 236, 17, 136, 106, 203, 56, 233, 149, 105, 112, 208, 134, 120, 227, 253, 164, 19, 250, 185, 22, 63, 248, 218, 127, 11, 214, 4, 95, 148, 130, 84, 113, 99, 128, 1, 106, 125, 151, 170, 1, 151, 108, 129, 69, 57, 233, 177, 195, 133, 166, 236, 103, 135, 11, 73, 74, 247, 236, 112, 161, 203, 118, 114, 73, 39, 123, 103, 205, 12, 111, 75, 166, 214, 190, 229, 157, 221, 98, 239, 44, 88, 236, 29, 212, 176, 227, 17, 212, 176, 227, 72, 253, 103, 209, 110, 180, 155, 119, 199, 101, 55, 144, 138, 170, 182, 21, 107, 45, 101, 162, 45, 155, 172, 156, 80, 172, 126, 149, 252, 246, 56, 112, 51, 105, 218, 126, 179, 63, 124, 39, 243, 206, 9, 210, 229, 216, 62, 123, 186, 50, 233, 19, 235, 219, 31, 164, 167, 180, 153, 54, 127, 197, 61, 72, 218, 46, 244, 180, 68, 238, 185, 18, 98, 245, 212, 221, 211, 96, 210, 20, 189, 186, 118, 101, 25, 109, 215, 64, 83, 46, 199, 64, 146, 218, 11, 210, 38, 157, 106, 233, 124, 179, 211, 58, 225, 5, 24, 60, 191, 41, 29, 55, 176, 250, 45, 80, 197, 105, 219, 243, 166, 45, 219, 47, 0, 3, 79, 46, 231, 171, 144, 86, 108, 123, 32, 213, 218, 79, 237, 113, 138, 149, 137, 215, 0, 92, 0, 44, 59, 221, 2, 7, 141, 25, 164, 235, 117, 58, 77, 227, 245, 77, 213, 58, 168, 228, 228, 53, 177, 228, 242, 136, 163, 153, 180, 237, 102, 183, 192, 171, 167, 85, 150, 205, 60, 42, 65, 238, 105, 25, 44, 246, 78, 46, 77, 87, 212, 121, 240, 86, 183, 212, 201, 134, 65, 51, 179, 15, 49, 125, 127, 28, 125, 115, 160, 173, 243, 75, 161, 208, 181, 172, 239, 4, 249, 75, 204, 84, 150, 65, 222, 188, 165, 162, 203, 25, 232, 122, 141, 84, 211, 175, 56, 76, 154, 62, 158, 58, 225, 8, 233, 90, 30, 19, 64, 169, 191, 246, 84, 61, 239, 152, 126, 166, 93, 238, 169, 5, 28, 168, 206, 228, 171, 246, 65, 174, 82, 134, 24, 191, 63, 10, 118, 79, 8, 242, 21, 109, 238, 9, 185, 167, 5, 173, 147, 198, 160, 45, 131, 88, 154, 214, 229, 250, 185, 76, 73, 23, 109, 6, 20, 179, 5, 22, 202, 242, 136, 116, 220, 74, 84, 81, 167, 193, 147, 221, 160, 230, 197, 105, 87, 122, 56, 96, 186, 72, 60, 115, 191, 191, 186, 59, 60, 203, 185, 134, 212, 114, 162, 18, 45, 224, 158, 222, 121, 229, 59, 59, 124, 104, 218, 54, 222, 95, 103, 167, 206, 14, 27, 206, 14, 21, 180, 182, 150, 233, 225, 223, 236, 112, 161, 85, 181, 101, 190, 217, 161, 67, 223, 4, 173, 252, 102, 101, 144, 67, 7, 165, 254, 208, 55, 59, 108, 180, 250, 155, 104, 167, 130, 24, 60, 60, 253, 218, 14, 20, 77, 91, 197, 15, 116, 165, 117, 199, 14, 25, 173, 203, 172, 98, 134, 180, 98, 29, 85, 146, 161, 86, 231, 216, 161, 3, 117, 118, 104, 159, 153, 99, 135, 13, 101, 167, 142, 255, 89, 236, 144, 1, 91, 199, 159, 197, 14, 25, 174, 109, 215, 47, 67, 56, 209, 180, 117, 110, 87, 66, 8, 161, 212, 241, 93, 236, 144, 161, 107, 25, 116, 180, 82, 116, 39, 136, 225, 198, 205, 66, 56, 124, 91, 118, 216, 160, 107, 25, 118, 200, 16, 137, 192, 206, 53, 135, 18, 109, 23, 132, 144, 101, 87, 5, 55, 200, 195, 35, 77, 115, 184, 208, 28, 6, 160, 194, 28, 42, 248, 109, 204, 252, 113, 20, 129, 41, 139, 192, 28, 58, 232, 231, 115, 55, 188, 80, 4, 230, 176, 33, 2, 115, 232, 104, 92, 73, 20, 129, 57, 100, 96, 163, 225, 229, 104, 238, 86, 132, 56, 94, 14, 21, 222, 119, 57, 92, 104, 173, 232, 114, 200, 80, 97, 70, 123, 25, 9, 109, 126, 96, 111, 25, 183, 147, 208, 4, 58, 24, 115, 63, 185, 28, 50, 154, 189, 111, 185, 28, 66, 104, 219, 245, 44, 118, 136, 31, 117, 182, 92, 14, 29, 168, 205, 229, 154, 114, 57, 108, 120, 100, 37, 14, 23, 152, 105, 219, 72, 28, 46, 220, 67, 141, 196, 33, 67, 35, 113, 216, 104, 214, 193, 52, 78, 168, 145, 56, 100, 72, 192, 147, 196, 225, 130, 71, 32, 128, 192, 147, 196, 33, 131, 105, 87, 214, 33, 131, 71, 32, 236, 194, 249, 101, 206, 48, 171, 208, 210, 202, 58, 116, 100, 219, 228, 235, 112, 225, 250, 217, 235, 112, 209, 79, 255, 213, 173, 195, 6, 47, 82, 183, 14, 23, 239, 109, 29, 46, 184, 122, 167, 216, 95, 143, 69, 184, 127, 167, 145, 42, 23, 167, 199, 55, 187, 79, 217, 239, 75, 34, 110, 235, 176, 1, 183, 117, 168, 224, 160, 43, 105, 235, 144, 33, 183, 173, 195, 133, 166, 173, 67, 5, 143, 48, 91, 209, 117, 200, 208, 38, 253, 169, 117, 200, 80, 237, 87, 235, 112, 177, 214, 50, 218, 239, 211, 58, 198, 105, 29, 54, 56, 173, 67, 199, 179, 32, 73, 90, 135, 13, 153, 214, 161, 130, 227, 208, 209, 250, 159, 10, 57, 199, 161, 68, 179, 227, 156, 29, 135, 14, 218, 216, 113, 184, 80, 217, 166, 236, 56, 92, 252, 218, 183, 104, 59, 36, 225, 17, 198, 223, 210, 113, 216, 112, 79, 215, 56, 100, 112, 141, 195, 70, 132, 53, 193, 81, 227, 112, 177, 56, 53, 14, 29, 168, 113, 8, 209, 56, 116, 160, 198, 97, 3, 53, 14, 27, 19, 248, 182, 168, 113, 184, 104, 28, 54, 28, 54, 220, 67, 227, 144, 162, 113, 24, 128, 10, 117, 168, 64, 210, 178, 33, 158, 223, 78, 247, 79, 63, 23, 163, 10, 73, 164, 117, 156, 124, 35, 16, 148, 61, 10, 55, 164, 169, 37, 107, 102, 90, 29, 62, 116, 46, 17, 170, 165, 163, 218, 12, 250, 164, 16, 46, 97, 118, 42, 224, 146, 78, 134, 152, 86, 135, 142, 39, 181, 58, 92, 240, 136, 83, 135, 11, 234, 143, 157, 111, 234, 176, 209, 218, 154, 58, 100, 80, 77, 29, 42, 48, 117, 168, 192, 35, 141, 58, 92, 80, 139, 90, 213, 225, 66, 213, 225, 131, 81, 14, 27, 239, 171, 144, 195, 35, 140, 114, 184, 240, 158, 140, 114, 200, 176, 236, 66, 140, 114, 184, 248, 228, 208, 193, 88, 161, 8, 183, 171, 44, 14, 31, 223, 16, 129, 81, 146, 197, 33, 131, 68, 57, 122, 215, 70, 43, 221, 147, 238, 73, 135, 11, 127, 233, 16, 178, 114, 226, 188, 51, 17, 156, 79, 135, 11, 30, 129, 176, 240, 106, 16, 63, 133, 166, 126, 236, 21, 110, 71, 101, 157, 27, 218, 121, 70, 246, 87, 84, 89, 182, 175, 40, 90, 160, 158, 169, 225, 124, 58, 116, 56, 159, 14, 21, 156, 244, 233, 176, 65, 53, 83, 30, 122, 156, 144, 123, 58, 156, 104, 253, 95, 202, 67, 52, 149, 240, 63, 141, 126, 246, 187, 0, 34, 172, 76, 188, 28, 156, 127, 233, 82, 173, 167, 68, 58, 117, 65, 238, 223, 161, 136, 64, 131, 8, 16, 48, 112, 254, 37, 47, 136, 0, 33, 97, 94, 52, 37, 19, 193, 248, 253, 37, 132, 15, 234, 153, 86, 38, 95, 153, 60, 29, 62, 60, 242, 232, 98, 108, 27, 107, 251, 49, 150, 93, 45, 89, 204, 143, 186, 245, 63, 25, 234, 9, 139, 71, 23, 163, 177, 71, 220, 249, 165, 32, 9, 210, 145, 4, 17, 170, 253, 40, 130, 0, 154, 182, 13, 72, 192, 208, 169, 207, 111, 123, 218, 205, 159, 246, 243, 41, 94, 61, 117, 235, 187, 84, 137, 156, 65, 13, 188, 105, 14, 69, 113, 79, 167, 44, 27, 106, 236, 17, 6, 202, 178, 161, 180, 173, 236, 53, 103, 140, 136, 182, 159, 235, 81, 73, 163, 177, 71, 190, 53, 32, 110, 169, 179, 240, 114, 172, 126, 104, 121, 206, 234, 135, 216, 105, 47, 80, 150, 13, 173, 245, 152, 7, 7, 199, 119, 53, 77, 29, 218, 38, 99, 197, 48, 235, 216, 126, 40, 63, 149, 67, 218, 197, 52, 110, 94, 143, 175, 168, 226, 180, 88, 5, 98, 226, 27, 51, 108, 145, 104, 118, 254, 65, 176, 193, 23, 190, 174, 206, 227, 155, 58, 252, 34, 151, 234, 153, 16, 243, 136, 3, 2, 37, 86, 65, 189, 211, 165, 75, 135, 141, 215, 180, 116, 184, 192, 146, 116, 168, 240, 63, 129, 33, 118, 26, 205, 159, 232, 160, 154, 182, 218, 164, 195, 6, 135, 142, 119, 154, 109, 164, 210, 97, 67, 165, 67, 5, 234, 17, 180, 250, 65, 120, 152, 109, 224, 124, 70, 56, 158, 14, 130, 224, 194, 35, 72, 83, 58, 92, 164, 116, 8, 73, 233, 240, 65, 43, 9, 49, 177, 9, 61, 16, 64, 144, 14, 25, 107, 37, 211, 250, 73, 65, 14, 31, 205, 12, 250, 77, 10, 114, 232, 120, 250, 145, 195, 5, 214, 204, 224, 163, 31, 200, 161, 67, 25, 251, 107, 35, 135, 11, 135, 11, 135, 11, 117, 235, 144, 67, 6, 151, 12, 57, 135, 11, 79, 69, 46, 228, 144, 225, 23, 57, 228, 16, 242, 172, 149, 109, 25, 228, 176, 193, 204, 50, 200, 33, 195, 211, 14, 23, 174, 219, 234, 200, 73, 169, 200, 97, 67, 43, 163, 10, 57, 92, 32, 183, 52, 181, 76, 200, 165, 246, 120, 34, 135, 13, 79, 75, 228, 112, 1, 33, 90, 39, 140, 10, 169, 61, 142, 158, 251, 199, 8, 209, 250, 228, 250, 199, 200, 248, 166, 234, 31, 227, 226, 253, 49, 42, 56, 233, 49, 42, 44, 187, 220, 51, 50, 84, 156, 241, 225, 124, 58, 103, 100, 112, 217, 156, 113, 129, 113, 161, 206, 216, 120, 214, 178, 100, 144, 51, 54, 156, 49, 0, 43, 219, 54, 219, 140, 140, 138, 54, 218, 168, 105, 198, 198, 202, 182, 170, 25, 23, 158, 218, 238, 184, 221, 2, 164, 180, 85, 53, 35, 69, 182, 178, 76, 232, 119, 105, 198, 6, 139, 210, 149, 178, 25, 25, 217, 140, 10, 252, 29, 163, 130, 71, 208, 74, 8, 50, 20, 128, 57, 50, 90, 223, 49, 46, 60, 238, 28, 227, 66, 235, 246, 107, 71, 172, 126, 30, 129, 160, 238, 249, 71, 211, 54, 101, 191, 132, 31, 33, 9, 255, 3, 9, 191, 187, 107, 92, 83, 199, 184, 80, 171, 182, 169, 99, 100, 208, 201, 54, 117, 140, 14, 254, 72, 194, 67, 59, 41, 205, 13, 52, 109, 84, 113, 66, 11, 184, 186, 231, 215, 4, 126, 180, 46, 251, 249, 237, 151, 212, 129, 39, 83, 39, 57, 104, 188, 203, 177, 244, 135, 5, 30, 180, 166, 86, 78, 168, 193, 174, 132, 180, 105, 101, 218, 180, 178, 134, 198, 30, 113, 64, 210, 76, 81, 150, 205, 68, 48, 204, 66, 90, 255, 213, 17, 3, 124, 104, 234, 24, 37, 154, 58, 70, 133, 149, 142, 17, 162, 218, 143, 118, 147, 39, 98, 198, 134, 125, 77, 189, 49, 46, 184, 49, 42, 248, 246, 152, 53, 198, 197, 106, 140, 142, 103, 53, 70, 5, 101, 251, 109, 151, 54, 198, 133, 178, 125, 164, 141, 145, 161, 141, 25, 29, 141, 145, 161, 169, 49, 42, 52, 125, 223, 133, 94, 27, 106, 140, 13, 141, 209, 161, 218, 12, 146, 164, 46, 244, 91, 81, 212, 24, 35, 60, 2, 225, 151, 49, 46, 158, 119, 76, 29, 142, 167, 226, 133, 32, 156, 170, 66, 191, 140, 177, 193, 108, 211, 48, 70, 6, 253, 215, 165, 140, 145, 81, 225, 197, 37, 67, 139, 241, 97, 49, 6, 32, 169, 101, 124, 56, 233, 149, 121, 152, 195, 216, 96, 160, 205, 9, 165, 237, 37, 25, 180, 111, 129, 82, 137, 52, 45, 195, 48, 66, 180, 190, 50, 86, 140, 140, 167, 245, 77, 120, 124, 42, 70, 136, 163, 198, 187, 192, 175, 132, 63, 49, 46, 86, 126, 98, 92, 96, 118, 37, 198, 133, 196, 232, 96, 222, 194, 168, 224, 141, 65, 232, 160, 188, 48, 42, 76, 60, 33, 126, 228, 14, 79, 118, 103, 51, 111, 163, 161, 81, 216, 211, 241, 102, 213, 40, 252, 218, 12, 128, 113, 51, 18, 13, 20, 2, 132, 95, 95, 136, 86, 168, 54, 211, 222, 195, 195, 172, 106, 191, 55, 157, 136, 159, 130, 97, 173, 88, 247, 71, 37, 14, 46, 25, 122, 126, 194, 241, 116, 34, 24, 52, 40, 125, 120, 220, 3, 33, 220, 113, 59, 20, 89, 24, 27, 234, 153, 80, 100, 97, 100, 64, 176, 48, 42, 208, 138, 109, 142, 240, 112, 254, 37, 227, 130, 100, 37, 5, 121, 50, 70, 180, 78, 60, 25, 33, 158, 140, 13, 158, 140, 142, 198, 43, 65, 158, 140, 14, 158, 140, 10, 38, 77, 39, 227, 66, 122, 26, 42, 168, 52, 12, 192, 186, 116, 74, 67, 134, 166, 104, 211, 175, 65, 67, 155, 0, 4, 139, 190, 242, 26, 54, 190, 242, 26, 42, 172, 108, 101, 175, 225, 130, 123, 97, 175, 33, 131, 82, 70, 91, 16, 127, 67, 136, 83, 184, 157, 127, 172, 245, 26, 58, 82, 242, 26, 54, 44, 175, 161, 130, 38, 41, 222, 112, 193, 27, 50, 156, 55, 84, 160, 157, 43, 169, 242, 134, 141, 158, 208, 80, 129, 187, 134, 141, 134, 13, 92, 56, 105, 29, 10, 98, 110, 173, 68, 237, 245, 163, 189, 118, 231, 211, 53, 156, 79, 247, 109, 145, 106, 63, 90, 201, 92, 67, 8, 230, 26, 62, 188, 85, 153, 107, 56, 225, 141, 247, 95, 106, 102, 16, 115, 13, 23, 48, 141, 25, 109, 27, 94, 104, 87, 131, 235, 167, 114, 15, 69, 48, 215, 176, 241, 171, 94, 34, 230, 152, 107, 184, 96, 174, 161, 2, 215, 48, 0, 173, 159, 11, 169, 150, 136, 194, 13, 27, 208, 241, 60, 55, 84, 112, 159, 239, 251, 220, 176, 193, 11, 65, 146, 210, 233, 115, 195, 7, 50, 60, 2, 193, 169, 46, 231, 134, 14, 95, 116, 195, 61, 65, 88, 170, 14, 165, 153, 36, 119, 120, 70, 23, 122, 104, 36, 14, 27, 30, 102, 223, 113, 195, 133, 54, 233, 15, 189, 227, 134, 142, 9, 34, 56, 230, 134, 11, 143, 198, 32, 167, 43, 97, 110, 184, 112, 198, 13, 21, 24, 55, 198, 13, 25, 184, 33, 227, 91, 123, 104, 204, 26, 133, 155, 100, 45, 165, 80, 44, 239, 31, 44, 102, 135, 220, 51, 165, 157, 142, 127, 179, 83, 119, 160, 182, 27, 213, 212, 29, 104, 224, 155, 29, 3, 173, 107, 147, 57, 41, 117, 151, 42, 110, 248, 96, 81, 10, 242, 8, 68, 46, 186, 145, 223, 102, 65, 225, 197, 64, 104, 250, 21, 133, 224, 84, 37, 204, 21, 110, 43, 24, 139, 229, 163, 191, 11, 45, 86, 105, 168, 248, 170, 44, 102, 135, 92, 165, 182, 243, 168, 85, 210, 236, 32, 130, 9, 42, 168, 45, 229, 181, 161, 180, 236, 101, 17, 197, 123, 17, 32, 157, 24, 125, 202, 86, 119, 253, 117, 137, 158, 23, 196, 178, 27, 93, 250, 11, 156, 244, 202, 180, 186, 231, 182, 2, 185, 42, 78, 40, 194, 159, 242, 207, 127, 56, 238, 146, 148, 203, 1, 65, 58, 173, 72, 213, 218, 119, 128, 220, 211, 221, 211, 27, 233, 17, 8, 127, 22, 212, 96, 130, 182, 63, 171, 58, 121, 113, 60, 149, 68, 91, 166, 18, 41, 109, 135, 148, 48, 41, 81, 253, 188, 99, 60, 175, 230, 89, 236, 26, 167, 138, 29, 8, 156, 127, 201, 77, 91, 255, 108, 19, 146, 196, 78, 250, 215, 200, 90, 136, 90, 164, 109, 157, 148, 236, 65, 178, 222, 130, 158, 213, 52, 188, 34, 152, 160, 130, 42, 175, 237, 114, 80, 231, 72, 114, 140, 8, 38, 248, 182, 202, 64, 211, 78, 84, 109, 4, 247, 239, 56, 212, 58, 110, 43, 26, 238, 105, 32, 76, 5, 227, 139, 167, 95, 59, 130, 227, 164, 87, 198, 241, 233, 42, 254, 176, 114, 162, 222, 228, 98, 24, 232, 90, 6, 77, 154, 62, 203, 105, 163, 181, 201, 20, 169, 226, 230, 52, 85, 148, 69, 40, 255, 124, 111, 216, 161, 55, 251, 93, 18, 89, 213, 48, 81, 213, 13, 197, 146, 67, 226, 1, 167, 13, 168, 228, 138, 136, 3, 132, 68, 242, 76, 162, 70, 73, 142, 41, 197, 148, 162, 162, 218, 0, 51, 18, 200, 97, 35, 113, 56, 26, 11, 3, 73, 22, 237, 1, 20, 128, 2, 11, 10, 197, 57, 237, 74, 18, 131, 36, 133, 138, 4, 4, 32, 3, 32, 1, 160, 0, 202, 5, 25, 88, 80, 108, 229, 116, 212, 199, 83, 154, 70, 218, 47, 23, 43, 66, 24, 212, 49, 246, 133, 246, 114, 219, 107, 207, 51, 13, 240, 61, 228, 153, 1, 201, 127, 238, 54, 60, 224, 38, 190, 105, 108, 181, 160, 198, 73, 159, 69, 4, 184, 13, 22, 57, 183, 4, 88, 110, 186, 46, 161, 202, 138, 254, 93, 79, 10, 7, 232, 252, 70, 80, 41, 74, 232, 241, 175, 54, 129, 81, 18, 103, 140, 64, 127, 208, 134, 126, 79, 65, 178, 6, 37, 173, 21, 60, 246, 46, 57, 234, 16, 109, 117, 139, 26, 251, 201, 9, 76, 180, 223, 14, 158, 143, 253, 103, 209, 7, 81, 21, 74, 161, 112, 245, 40, 202, 206, 142, 201, 43, 183, 186, 247, 75, 203, 227, 214, 192, 173, 26, 16, 118, 125, 130, 107, 130, 20, 210, 59, 137, 204, 5, 134, 71, 170, 34, 28, 77, 187, 65, 134, 153, 221, 102, 22, 137, 19, 146, 89, 121, 160, 123, 167, 193, 172, 104, 92, 112, 141, 195, 191, 248, 131, 125, 114, 117, 97, 15, 10, 79, 84, 50, 156, 242, 96, 129, 63, 17, 224, 192, 61, 90, 16, 74, 207, 236, 187, 120, 3, 89, 243, 53, 36, 135, 46, 160, 156, 126, 167, 238, 51, 156, 104, 60, 170, 181, 187, 24, 28, 99, 112, 9, 69, 163, 207, 157, 149, 60, 15, 177, 126, 109, 103, 59, 22, 163, 85, 122, 34, 169, 85, 146, 246, 67, 135, 73, 2, 13, 28, 166, 225, 80, 19, 172, 193, 210, 143, 66, 250, 129, 197, 103, 45, 249, 137, 180, 225, 3, 152, 208, 23, 7, 94, 198, 29, 226, 233, 10, 128, 67, 233, 213, 88, 106, 214, 76, 124, 235, 88, 80, 66, 124, 175, 72, 184, 233, 113, 232, 161, 22, 166, 134, 14, 92, 19, 152, 227, 22, 37, 49, 139, 110, 207, 254, 74, 86, 195, 129, 49, 58, 106, 71, 67, 137, 213, 67, 168, 111, 132, 253, 62, 134, 220, 185, 86, 83, 76, 215, 64, 164, 171, 42, 10, 217, 20, 211, 129, 219, 133, 126, 63, 37, 216, 182, 5, 184, 214, 178, 138, 69, 61, 180, 112, 181, 248, 172, 153, 181, 66, 159, 193, 83, 250, 231, 17, 80, 138, 142, 161, 163, 200, 220, 62, 178, 111, 182, 188, 43, 208, 174, 87, 60, 136, 95, 236, 46, 37, 2, 153, 30, 49, 107, 33, 69, 182, 88, 138, 67, 125, 179, 61, 23, 126, 27, 246, 111, 181, 94, 31, 241, 173, 1, 245, 32, 177, 247, 218, 85, 17, 6, 15, 158, 121, 150, 149, 55, 134, 141, 26, 93, 32, 101, 97, 62, 148, 237, 148, 191, 204, 8, 79, 6, 45, 246, 134, 59, 78, 188, 81, 109, 30, 102, 185, 92, 26, 31, 100, 85, 33, 89, 183, 64, 40, 72, 159, 102, 187, 225, 197, 209, 137, 183, 207, 71, 196, 252, 18, 8, 181, 171, 62, 2, 230, 27, 49, 241, 129, 160, 217, 204, 236, 134, 131, 184, 141, 132, 58, 34, 132, 5, 153, 234, 166, 4, 95, 196, 151, 115, 221, 72, 80, 4, 100, 212, 127, 158, 47, 26, 48, 129, 232, 9, 237, 71, 2, 139, 56, 0, 198, 96, 194, 110, 99, 56, 209, 203, 16, 178, 201, 192, 203, 206, 54, 199, 254, 135, 43, 83, 153, 187, 135, 218, 167, 74, 8, 214, 95, 44, 163, 211, 150, 81, 32, 238, 28, 240, 177, 82, 154, 0, 243, 129, 85, 224, 157, 187, 187, 216, 7, 197, 95, 21, 29, 92, 126, 75, 82, 65, 114, 98, 241, 2, 110, 25, 12, 137, 96, 156, 174, 102, 155, 41, 170, 190, 97, 59, 239, 0, 225, 22, 9, 32, 235, 26, 146, 190, 35, 45, 113, 0, 94, 132, 34, 170, 175, 22, 24, 136, 202, 193, 17, 93, 157, 170, 209, 233, 71, 153, 209, 45, 6, 217, 116, 35, 162, 52, 42, 232, 179, 232, 32, 47, 36, 227, 159, 99, 113, 95, 118, 159, 216, 203, 141, 136, 179, 248, 111, 187, 69, 198, 104, 127, 228, 217, 83, 14, 164, 121, 190, 182, 191, 114, 70, 71, 236, 180, 244, 240, 239, 87, 235, 243, 38, 163, 91, 216, 182, 157, 207, 79, 63, 27, 87, 133, 95, 64, 113, 150, 70, 195, 180, 117, 236, 242, 187, 74, 27, 236, 165, 241, 124, 175, 221, 214, 115, 133, 249, 148, 67, 4, 174, 218, 7, 207, 142, 13, 67, 43, 100, 48, 136, 206, 127, 23, 137, 1, 133, 165, 77, 75, 153, 102, 71, 127, 208, 78, 30, 248, 61, 23, 51, 235, 173, 25, 38, 129, 160, 178, 48, 249, 75, 175, 134, 45, 245, 200, 11, 218, 89, 243, 248, 86, 198, 99, 69, 122, 244, 41, 148, 71, 143, 210, 25, 68, 135, 149, 44, 48, 195, 90, 26, 65, 158, 226, 40, 56, 143, 59, 250, 64, 38, 79, 59, 93, 218, 84, 183, 57, 93, 243, 176, 187, 163, 8, 144, 147, 106, 112, 171, 37, 129, 151, 85, 49, 140, 95, 28, 185, 160, 118, 174, 241, 179, 238, 12, 84, 33, 135, 17, 187, 168, 197, 234, 35, 12, 133, 224, 157, 60, 237, 115, 84, 62, 162, 91, 157, 130, 71, 129, 122, 179, 72, 208, 176, 247, 77, 115, 169, 71, 37, 243, 26, 250, 178, 50, 106, 193, 219, 159, 80, 35, 88, 19, 137, 20, 18, 230, 78, 219, 10, 127, 197, 51, 127, 132, 30, 33, 13, 210, 194, 71, 231, 181, 118, 137, 136, 86, 252, 183, 57, 26, 108, 95, 140, 120, 1, 70, 232, 242, 26, 105, 70, 34, 65, 40, 210, 111, 74, 188, 210, 225, 81, 222, 64, 240, 126, 148, 147, 198, 11, 254, 49, 42, 14, 80, 226, 24, 33, 114, 33, 26, 130, 8, 29, 133, 98, 83, 183, 148, 90, 156, 121, 98, 182, 172, 147, 66, 126, 76, 56, 39, 181, 102, 227, 163, 225, 127, 164, 118, 233, 53, 202, 183, 252, 122, 77, 85, 179, 252, 24, 202, 28, 64, 64, 162, 244, 117, 202, 57, 181, 104, 17, 247, 167, 91, 240, 188, 26, 27, 109, 37, 113, 54, 205, 48, 83, 146, 89, 82, 244, 46, 244, 56, 133, 52, 246, 226, 28, 72, 57, 213, 180, 6, 232, 196, 27, 146, 252, 144, 215, 87, 149, 15, 31, 182, 155, 81, 96, 173, 162, 16, 207, 103, 152, 83, 8, 233, 188, 92, 117, 180, 129, 158, 136, 65, 111, 196, 11, 80, 8, 217, 142, 33, 244, 123, 234, 131, 226, 153, 34, 201, 99, 86, 101, 73, 219, 41, 171, 82, 110, 30, 24, 80, 218, 161, 57, 118, 132, 254, 161, 205, 70, 139, 114, 145, 181, 138, 36, 166, 229, 216, 124, 113, 67, 139, 139, 42, 210, 34, 28, 19, 83, 60, 115, 97, 48, 152, 99, 213, 85, 59, 66, 54, 146, 189, 194, 100, 65, 112, 186, 5, 45, 119, 128, 213, 130, 141, 187, 211, 80, 175, 146, 192, 168, 137, 11, 83, 90, 85, 97, 156, 129, 116, 247, 246, 62, 67, 246, 149, 75, 183, 134, 114, 209, 200, 156, 85, 27, 196, 163, 250, 151, 177, 75, 204, 11, 133, 187, 48, 183, 244, 239, 178, 85, 91, 207, 160, 35, 185, 112, 156, 174, 113, 139, 215, 50, 175, 84, 58, 145, 185, 31, 70, 1, 242, 22, 7, 232, 63, 31, 208, 117, 3, 231, 100, 131, 120, 64, 108, 184, 216, 120, 76, 153, 248, 0, 140, 4, 81, 23, 178, 109, 89, 188, 128, 104, 182, 190, 237, 240, 63, 102, 247, 62, 0, 77, 100, 61, 72, 130, 145, 111, 222, 236, 16, 105, 203, 133, 160, 255, 96, 45, 113, 170, 201, 43, 31, 229, 26, 148, 168, 201, 251, 176, 247, 164, 178, 181, 245, 152, 62, 37, 14, 156, 99, 234, 30, 136, 232, 249, 179, 51, 67, 140, 150, 134, 21, 156, 120, 201, 89, 141, 254, 62, 105, 243, 216, 231, 225, 190, 14, 40, 198, 229, 47, 100, 217, 228, 239, 142, 211, 234, 235, 199, 110, 76, 154, 105, 132, 76, 35, 180, 162, 147, 151, 203, 238, 50, 61, 97, 249, 205, 87, 217, 39, 42, 148, 88, 155, 6, 52, 248, 130, 238, 214, 57, 24, 127, 153, 16, 233, 94, 172, 42, 232, 209, 2, 172, 201, 181, 110, 11, 208, 108, 72, 150, 122, 13, 55, 95, 179, 245, 154, 250, 196, 59, 101, 67, 236, 179, 214, 62, 110, 80, 55, 7, 94, 8, 65, 200, 140, 180, 189, 17, 25, 80, 74, 177, 183, 142, 51, 171, 61, 236, 108, 124, 193, 137, 74, 41, 252, 255, 224, 0, 143, 238, 14, 143, 62, 124, 16, 185, 20, 22, 119, 13, 61, 4, 18, 245, 123, 141, 197, 35, 224, 233, 132, 38, 64, 50, 254, 201, 114, 99, 174, 35, 173, 227, 238, 158, 66, 161, 113, 222, 159, 0, 164, 69, 27, 136, 28, 142, 204, 215, 137, 32, 115, 54, 66, 41, 62, 108, 200, 15, 221, 73, 229, 119, 83, 27, 238, 110, 251, 107, 6, 112, 156, 22, 0, 164, 239, 236, 148, 88, 1, 125, 246, 48, 156, 103, 16, 97, 88, 221, 93, 133, 133, 204, 50, 191, 86, 234, 111, 172, 110, 55, 53, 56, 154, 29, 150, 175, 174, 200, 142, 104, 85, 246, 208, 238, 46, 210, 55, 118, 49, 188, 243, 131, 90, 252, 120, 156, 234, 136, 0, 49, 22, 193, 107, 106, 226, 169, 246, 33, 74, 182, 200, 25, 223, 69, 142, 221, 148, 177, 144, 17, 171, 49, 158, 220, 255, 66, 156, 252, 56, 41, 64, 40, 156, 75, 84, 67, 50, 226, 97, 246, 189, 4, 133, 173, 21, 26, 240, 155, 19, 48, 56, 93, 82, 133, 233, 49, 86, 82, 73, 3, 30, 108, 163, 177, 173, 195, 106, 124, 149, 249, 75, 107, 107, 144, 43, 91, 205, 78, 102, 156, 58, 167, 78, 246, 233, 68, 79, 152, 254, 129, 203, 232, 139, 227, 59, 84, 159, 110, 92, 245, 23, 87, 29, 201, 215, 233, 161, 84, 210, 16, 58, 35, 123, 166, 209, 32, 79, 3, 168, 243, 195, 112, 152, 178, 26, 118, 1, 115, 76, 222, 8, 225, 161, 178, 123, 249, 95, 104, 229, 115, 155, 52, 68, 234, 1, 229, 144, 201, 119, 179, 94, 18, 180, 151, 5, 80, 162, 22, 199, 5, 96, 30, 197, 247, 27, 238, 59, 171, 145, 11, 240, 6, 248, 254, 150, 236, 8, 223, 178, 159, 1, 164, 233, 240, 118, 55, 35, 88, 89, 114, 124, 112, 245, 38, 155, 74, 57, 132, 201, 69, 227, 170, 233, 28, 232, 227, 19, 231, 217, 252, 205, 5, 85, 206, 18, 188, 175, 57, 85, 81, 224, 186, 112, 146, 16, 48, 72, 197, 245, 124, 9, 131, 197, 240, 75, 227, 235, 242, 225, 184, 10, 151, 128, 124, 182, 65, 96, 101, 109, 102, 103, 47, 79, 46, 130, 203, 190, 205, 114, 228, 131, 170, 182, 175, 178, 196, 195, 199, 188, 195, 151, 130, 106, 98, 14, 165, 6, 82, 116, 164, 152, 156, 24, 3, 49, 85, 136, 12, 68, 95, 35, 212, 168, 35, 52, 71, 19, 91, 142, 184, 95, 195, 252, 224, 182, 173, 198, 204, 137, 13, 254, 34, 70, 140, 14, 16, 48, 160, 251, 148, 53, 73, 13, 152, 82, 226, 194, 44, 137, 60, 15, 71, 208, 199, 67, 75, 55, 58, 55, 9, 247, 179, 48, 56, 42, 209, 127, 6, 61, 192, 59, 8, 170, 64, 219, 250, 7, 173, 219, 68, 161, 113, 244, 101, 80, 39, 170, 175, 58, 175, 86, 129, 145, 40, 164, 234, 20, 66, 39, 102, 111, 16, 123, 10, 192, 27, 28, 80, 26, 87, 184, 186, 202, 126, 124, 141, 7, 35, 21, 235, 3, 81, 129, 79, 146, 19, 154, 190, 2, 175, 177, 0, 231, 28, 151, 73, 147, 239, 144, 128, 220, 180, 167, 167, 82, 221, 99, 57, 168, 246, 251, 35, 203, 180, 84, 102, 68, 249, 138, 37, 17, 229, 65, 217, 99, 21, 82, 37, 161, 253, 12, 34, 106, 17, 229, 1, 213, 70, 84, 105, 154, 252, 102, 128, 24, 19, 132, 116, 214, 240, 6, 110, 7, 59, 51, 83, 32, 133, 222, 175, 69, 134, 191, 64, 62, 176, 195, 3, 64, 113, 58, 188, 63, 68, 60, 35, 189, 198, 58, 75, 114, 132, 252, 179, 192, 181, 128, 93, 189, 255, 233, 78, 219, 176, 108, 60, 143, 48, 53, 63, 213, 167, 98, 75, 141, 73, 189, 59, 190, 147, 106, 69, 125, 206, 230, 251, 49, 147, 171, 252, 26, 47, 159, 230, 72, 26, 26, 145, 40, 64, 33, 172, 124, 166, 119, 90, 122, 137, 104, 254, 60, 25, 69, 224, 149, 111, 138, 191, 244, 81, 108, 205, 168, 48, 97, 15, 4, 98, 39, 156, 188, 162, 45, 29, 176, 254, 62, 121, 81, 106, 76, 238, 248, 113, 3, 13, 152, 253, 160, 145, 156, 86, 173, 8, 197, 252, 140, 86, 45, 39, 67, 54, 97, 56, 191, 161, 220, 69, 216, 215, 84, 171, 128, 2, 95, 181, 207, 238, 45, 221, 53, 147, 208, 68, 110, 18, 58, 255, 57, 143, 78, 52, 207, 148, 174, 10, 18, 196, 40, 213, 253, 101, 4, 7, 3, 223, 92, 125, 36, 183, 229, 71, 248, 120, 154, 33, 58, 211, 231, 17, 232, 151, 216, 255, 74, 201, 61, 253, 156, 209, 255, 167, 172, 202, 161, 56, 77, 180, 117, 5, 180, 52, 24, 8, 33, 72, 74, 30, 119, 13, 179, 187, 181, 115, 68, 197, 239, 10, 69, 79, 81, 200, 145, 209, 198, 237, 12, 152, 124, 200, 203, 170, 99, 151, 22, 62, 89, 198, 68, 116, 237, 139, 217, 107, 209, 109, 9, 96, 35, 250, 54, 149, 111, 53, 192, 225, 79, 26, 97, 60, 243, 162, 104, 147, 24, 175, 84, 2, 49, 174, 202, 38, 53, 34, 160, 82, 158, 101, 180, 144, 18, 238, 65, 63, 165, 108, 15, 108, 140, 170, 32, 122, 73, 76, 64, 188, 103, 225, 239, 100, 240, 12, 25, 39, 9, 187, 228, 112, 162, 100, 185, 27, 72, 122, 218, 28, 2, 20, 247, 7, 190, 131, 66, 116, 242, 180, 95, 189, 79, 158, 86, 246, 22, 14, 0, 104, 154, 105, 100, 39, 227, 139, 56, 221, 153, 88, 164, 163, 19, 248, 164, 72, 149, 49, 161, 247, 6, 100, 233, 26, 245, 44, 43, 115, 214, 91, 164, 205, 224, 59, 5, 48, 170, 187, 210, 184, 4, 83, 123, 170, 24, 194, 169, 181, 127, 47, 225, 198, 59, 145, 144, 8, 106, 166, 8, 121, 198, 120, 198, 155, 26, 143, 137, 243, 213, 27, 235, 203, 195, 28, 143, 144, 33, 123, 252, 32, 18, 248, 224, 59, 193, 210, 78, 21, 149, 16, 232, 130, 47, 93, 161, 37, 98, 80, 219, 199, 46, 45, 177, 231, 28, 127, 238, 28, 144, 0, 39, 54, 5, 215, 8, 70, 41, 196, 118, 117, 233, 11, 252, 41, 217, 123, 250, 53, 74, 20, 228, 84, 231, 254, 19, 211, 177, 231, 41, 16, 38, 47, 21, 158, 64, 255, 107, 29, 83, 142, 37, 37, 153, 116, 81, 210, 58, 227, 49, 184, 188, 219, 170, 168, 29, 19, 228, 8, 78, 45, 162, 75, 40, 157, 32, 224, 130, 72, 105, 24, 87, 20, 250, 9, 123, 187, 110, 77, 232, 243, 110, 45, 175, 67, 117, 168, 169, 57, 142, 12, 225, 19, 132, 2, 113, 42, 233, 47, 132, 241, 11, 189, 145, 11, 227, 175, 254, 14, 168, 95, 4, 241, 224, 97, 0, 196, 105, 146, 205, 254, 212, 1, 252, 81, 109, 177, 226, 171, 172, 44, 153, 216, 153, 245, 78, 167, 185, 63, 105, 184, 114, 92, 13, 107, 5, 21, 150, 22, 208, 65, 169, 159, 237, 9, 48, 206, 61, 24, 121, 172, 137, 75, 105, 105, 85, 149, 162, 190, 212, 129, 15, 74, 239, 185, 44, 162, 12, 192, 218, 84, 23, 132, 130, 120, 242, 243, 202, 192, 150, 177, 158, 242, 191, 184, 97, 16, 204, 35, 173, 159, 99, 33, 109, 204, 111, 3, 249, 253, 75, 113, 207, 98, 66, 218, 7, 81, 164, 106, 108, 77, 225, 64, 109, 33, 143, 88, 87, 76, 52, 48, 200, 172, 169, 190, 246, 172, 170, 230, 2, 43, 138, 226, 155, 225, 150, 250, 19, 234, 86, 75, 20, 18, 62, 163, 10, 172, 69, 38, 122, 35, 48, 48, 234, 21, 189, 158, 78, 153, 72, 62, 77, 157, 102, 248, 38, 151, 164, 15, 230, 232, 230, 230, 146, 195, 221, 244, 233, 250, 93, 118, 64, 249, 223, 158, 216, 33, 138, 44, 50, 225, 112, 56, 94, 44, 98, 154, 44, 31, 190, 150, 194, 223, 110, 165, 225, 157, 146, 115, 174, 157, 44, 76, 168, 155, 77, 222, 205, 138, 49, 160, 195, 193, 154, 228, 1, 60, 37, 239, 9, 18, 10, 238, 72, 220, 33, 88, 93, 40, 58, 88, 251, 117, 183, 246, 20, 109, 188, 79, 127, 123, 207, 90, 125, 178, 113, 34, 218, 135, 250, 57, 242, 163, 23, 203, 191, 231, 174, 34, 16, 210, 238, 64, 175, 248, 180, 16, 182, 177, 98, 231, 121, 51, 52, 88, 91, 236, 10, 11, 179, 145, 3, 66, 177, 33, 92, 244, 102, 231, 182, 106, 10, 237, 184, 148, 178, 39, 56, 14, 45, 223, 14, 14, 204, 22, 49, 75, 1, 241, 117, 246, 7, 29, 24, 122, 120, 132, 15, 171, 69, 223, 192, 162, 79, 44, 136, 41, 174, 170, 129, 118, 1, 74, 30, 218, 247, 39, 55, 99, 150, 72, 199, 214, 184, 4, 129, 72, 67, 121, 183, 235, 143, 183, 228, 130, 92, 160, 3, 194, 145, 242, 95, 85, 45, 170, 174, 157, 173, 73, 121, 213, 168, 95, 101, 58, 207, 57, 237, 51, 156, 67, 35, 207, 85, 161, 33, 129, 138, 8, 241, 58, 58, 218, 43, 97, 220, 177, 200, 65, 164, 152, 238, 19, 59, 174, 149, 178, 12, 116, 134, 0, 72, 43, 107, 23, 254, 57, 7, 86, 85, 22, 185, 194, 226, 25, 46, 23, 81, 132, 78, 65, 99, 41, 37, 91, 202, 168, 4, 103, 176, 70, 247, 112, 34, 178, 26, 38, 234, 249, 169, 232, 245, 141, 182, 155, 255, 2, 79, 139, 67, 182, 27, 8, 131, 32, 114, 21, 192, 243, 151, 58, 13, 202, 255, 52, 6, 209, 44, 79, 60, 83, 180, 39, 94, 235, 226, 156, 32, 152, 44, 75, 50, 22, 249, 148, 230, 69, 98, 136, 120, 252, 39, 11, 85, 109, 117, 181, 106, 249, 82, 163, 207, 240, 192, 56, 34, 98, 6, 11, 36, 89, 64, 181, 52, 148, 28, 174, 129, 74, 125, 2, 118, 246, 6, 140, 76, 196, 122, 215, 85, 51, 192, 137, 93, 192, 37, 30, 68, 155, 100, 224, 59, 192, 218, 1, 33, 57, 247, 155, 123, 126, 79, 101, 74, 8, 19, 169, 9, 41, 232, 229, 24, 102, 75, 78, 210, 239, 226, 219, 215, 170, 229, 116, 116, 190, 121, 212, 59, 20, 55, 80, 94, 246, 251, 114, 1, 252, 136, 224, 51, 243, 18, 200, 101, 13, 102, 133, 25, 157, 53, 245, 48, 241, 153, 68, 160, 148, 126, 93, 251, 113, 245, 174, 211, 43, 242, 95, 62, 43, 198, 25, 136, 140, 219, 98, 19, 42, 63, 93, 130, 63, 120, 203, 45, 113, 5, 110, 148, 163, 223, 73, 8, 202, 136, 41, 122, 54, 247, 148, 76, 211, 44, 33, 86, 36, 182, 163, 204, 160, 22, 126, 202, 172, 52, 174, 18, 132, 159, 92, 76, 90, 114, 170, 105, 4, 154, 131, 248, 128, 228, 101, 160, 212, 203, 39, 171, 149, 239, 57, 123, 168, 81, 5, 74, 147, 83, 42, 173, 196, 87, 198, 143, 248, 5, 165, 138, 198, 34, 196, 25, 1, 203, 100, 203, 238, 217, 141, 27, 158, 38, 149, 145, 45, 104, 34, 27, 237, 64, 74, 35, 68, 226, 142, 114, 174, 122, 142, 239, 104, 153, 247, 155, 19, 0, 113, 104, 228, 155, 119, 147, 216, 215, 90, 53, 47, 92, 112, 75, 201, 85, 95, 45, 29, 232, 100, 73, 61, 145, 220, 235, 94, 68, 16, 170, 210, 162, 205, 5, 118, 225, 147, 229, 142, 31, 91, 98, 235, 125, 214, 111, 222, 45, 79, 180, 40, 29, 126, 112, 149, 52, 52, 158, 53, 59, 209, 240, 231, 220, 239, 9, 17, 78, 58, 3, 81, 167, 87, 133, 110, 67, 101, 39, 147, 188, 60, 15, 243, 6, 162, 34, 162, 125, 184, 237, 10, 57, 81, 154, 213, 251, 47, 54, 245, 10, 115, 127, 166, 254, 237, 197, 167, 157, 118, 105, 92, 96, 254, 188, 140, 228, 183, 106, 153, 82, 122, 162, 242, 31, 233, 215, 186, 110, 200, 169, 178, 107, 83, 113, 130, 168, 158, 111, 20, 150, 140, 162, 125, 53, 200, 205, 128, 219, 38, 242, 196, 139, 150, 239, 78, 224, 157, 25, 104, 63, 159, 50, 48, 186, 33, 219, 82, 157, 194, 209, 13, 65, 120, 100, 254, 44, 9, 120, 31, 103, 89, 94, 79, 150, 142, 167, 115, 117, 146, 214, 96, 152, 213, 142, 228, 72, 127, 85, 102, 237, 129, 12, 220, 220, 105, 45, 43, 38, 6, 128, 133, 87, 48, 105, 136, 177, 240, 42, 185, 72, 0, 107, 230, 26, 172, 122, 251, 110, 2, 32, 170, 103, 101, 69, 49, 107, 46, 36, 226, 208, 68, 31, 186, 81, 21, 31, 30, 236, 191, 244, 50, 30, 54, 143, 67, 207, 180, 19, 116, 96, 16, 123, 210, 82, 168, 221, 199, 147, 189, 133, 188, 91, 41, 205, 62, 61, 134, 36, 46, 18, 78, 133, 139, 190, 114, 11, 16, 28, 71, 53, 175, 35, 164, 173, 144, 111, 33, 184, 196, 125, 36, 101, 243, 29, 80, 169, 81, 186, 41, 196, 124, 120, 63, 118, 15, 61, 0, 60, 177, 247, 142, 158, 220, 202, 24, 204, 68, 10, 180, 34, 54, 16, 114, 151, 107, 6, 32, 220, 210, 191, 129, 80, 190, 124, 140, 214, 61, 1, 34, 193, 136, 141, 251, 157, 193, 46, 232, 84, 160, 249, 138, 207, 67, 2, 2, 7, 8, 244, 179, 136, 166, 131, 1, 145, 14, 5, 47, 81, 190, 198, 188, 245, 5, 50, 60, 55, 70, 217, 89, 28, 3, 41, 47, 251, 77, 248, 33, 68, 6, 116, 121, 191, 24, 67, 197, 16, 215, 111, 229, 132, 37, 212, 180, 190, 21, 69, 211, 154, 146, 141, 69, 69, 16, 0, 60, 110, 57, 13, 184, 190, 241, 198, 7, 83, 89, 150, 66, 157, 141, 175, 0, 136, 156, 163, 218, 215, 127, 82, 255, 152, 215, 37, 251, 186, 223, 111, 242, 253, 233, 175, 46, 179, 1, 247, 225, 30, 19, 192, 85, 130, 137, 155, 219, 41, 33, 185, 33, 126, 131, 237, 0, 45, 246, 54, 86, 176, 133, 211, 6, 141, 230, 90, 73, 65, 75, 120, 47, 179, 96, 28, 193, 30, 17, 22, 43, 98, 93, 196, 105, 88, 201, 40, 82, 5, 186, 29, 165, 158, 119, 102, 58, 14, 85, 89, 47, 85, 29, 140, 17, 27, 113, 21, 217, 143, 195, 91, 38, 192, 181, 229, 0, 150, 248, 97, 36, 158, 62, 103, 179, 116, 191, 114, 121, 95, 124, 249, 112, 228, 21, 127, 248, 123, 5, 192, 167, 229, 174, 2, 242, 151, 132, 55, 183, 139, 51, 103, 138, 69, 210, 136, 33, 104, 169, 119, 127, 45, 152, 138, 226, 157, 201, 29, 80, 106, 224, 12, 30, 1, 132, 36, 248, 62, 0, 147, 132, 226, 104, 67, 211, 87, 38, 35, 99, 160, 131, 195, 32, 144, 10, 32, 252, 197, 133, 128, 180, 123, 104, 143, 82, 64, 74, 70, 188, 208, 2, 59, 77, 212, 55, 110, 161, 52, 248, 78, 230, 221, 102, 142, 40, 136, 142, 172, 69, 135, 25, 92, 126, 241, 174, 200, 85, 205, 44, 175, 144, 83, 54, 250, 11, 206, 204, 162, 120, 232, 215, 8, 198, 110, 71, 48, 136, 146, 12, 184, 0, 18, 30, 55, 48, 216, 77, 109, 17, 9, 249, 51, 71, 255, 170, 218, 62, 243, 195, 71, 45, 149, 217, 142, 83, 181, 38, 44, 9, 9, 66, 57, 175, 69, 15, 60, 170, 97, 112, 61, 249, 182, 34, 100, 11, 216, 137, 101, 195, 80, 14, 35, 111, 223, 11, 61, 106, 208, 91, 81, 142, 145, 96, 145, 226, 159, 88, 22, 18, 211, 192, 154, 185, 67, 93, 73, 144, 206, 221, 201, 179, 138, 223, 88, 151, 122, 128, 150, 6, 102, 9, 91, 68, 130, 217, 147, 125, 1, 225, 102, 245, 212, 7, 178, 203, 91, 139, 175, 43, 102, 221, 172, 214, 192, 107, 116, 54, 78, 92, 225, 4, 6, 241, 194, 148, 237, 44, 171, 149, 17, 180, 104, 33, 144, 86, 133, 205, 70, 236, 87, 40, 195, 147, 67, 8, 34, 112, 64, 22, 111, 196, 96, 246, 129, 131, 226, 36, 181, 250, 68, 98, 86, 159, 77, 5, 182, 147, 224, 21, 65, 18, 180, 36, 85, 224, 100, 229, 166, 85, 59, 255, 113, 41, 130, 120, 232, 2, 113, 114, 211, 53, 200, 45, 183, 238, 240, 174, 1, 68, 82, 167, 6, 198, 172, 55, 103, 200, 2, 8, 30, 53, 196, 99, 40, 138, 239, 185, 86, 191, 230, 174, 97, 61, 7, 120, 85, 142, 6, 202, 107, 114, 20, 202, 13, 209, 82, 46, 122, 14, 21, 27, 44, 152, 132, 217, 40, 254, 113, 170, 186, 229, 228, 81, 15, 148, 77, 26, 43, 113, 17, 100, 156, 33, 90, 38, 88, 129, 171, 199, 148, 30, 16, 94, 95, 182, 24, 159, 4, 96, 106, 98, 219, 36, 73, 218, 79, 152, 152, 176, 159, 34, 13, 80, 54, 176, 157, 191, 128, 46, 230, 117, 199, 127, 8, 36, 208, 7, 237, 41, 241, 160, 116, 172, 181, 90, 94, 233, 130, 233, 225, 35, 53, 155, 106, 115, 118, 192, 220, 118, 190, 248, 170, 110, 113, 23, 171, 120, 176, 247, 181, 130, 172, 197, 44, 111, 239, 3, 89, 217, 108, 182, 120, 190, 62, 138, 226, 232, 31, 233, 3, 77, 114, 53, 228, 157, 129, 209, 233, 26, 245, 254, 235, 164, 195, 194, 50, 73, 225, 14, 225, 251, 100, 59, 93, 167, 134, 171, 186, 46, 101, 169, 205, 33, 87, 23, 97, 138, 116, 226, 51, 2, 229, 221, 188, 16, 219, 175, 168, 202, 198, 113, 51, 183, 116, 137, 139, 224, 233, 20, 110, 121, 47, 206, 155, 201, 166, 114, 226, 30, 186, 157, 124, 241, 5, 119, 99, 101, 106, 151, 49, 60, 206, 210, 16, 66, 2, 247, 168, 159, 166, 192, 198, 55, 217, 22, 126, 235, 14, 203, 81, 72, 142, 194, 187, 42, 118, 189, 167, 4, 199, 59, 110, 8, 88, 121, 247, 138, 57, 180, 45, 96, 77, 227, 228, 29, 187, 65, 173, 142, 96, 100, 26, 22, 160, 88, 108, 210, 83, 138, 196, 35, 9, 58, 176, 71, 59, 21, 128, 59, 166, 47, 114, 158, 226, 145, 144, 199, 35, 25, 219, 22, 38, 104, 119, 65, 4, 222, 170, 224, 89, 206, 26, 96, 33, 60, 62, 37, 201, 27, 92, 91, 201, 64, 220, 109, 103, 222, 7, 100, 225, 114, 221, 19, 47, 192, 117, 243, 236, 23, 100, 113, 251, 111, 69, 196, 144, 237, 22, 0, 243, 251, 138, 240, 123, 95, 168, 224, 167, 223, 133, 197, 143, 144, 126, 100, 139, 36, 120, 185, 19, 175, 240, 251, 66, 46, 56, 197, 169, 168, 17, 168, 218, 183, 9, 186, 123, 140, 168, 226, 74, 117, 140, 191, 210, 161, 96, 53, 229, 192, 250, 224, 73, 189, 235, 153, 225, 28, 2, 12, 95, 25, 130, 167, 139, 189, 24, 71, 2, 102, 46, 149, 137, 237, 194, 61, 67, 138, 20, 249, 40, 35, 24, 176, 188, 60, 122, 73, 231, 156, 204, 253, 245, 41, 229, 144, 192, 152, 102, 71, 6, 241, 0, 37, 176, 223, 91, 213, 236, 216, 245, 235, 127, 83, 130, 229, 102, 244, 219, 40, 236, 135, 5, 153, 88, 186, 213, 62, 120, 187, 115, 9, 181, 44, 8, 212, 111, 78, 255, 237, 244, 101, 133, 113, 169, 31, 28, 202, 147, 120, 190, 147, 133, 123, 14, 223, 120, 41, 71, 114, 51, 165, 6, 90, 90, 113, 207, 246, 150, 40, 143, 124, 73, 170, 193, 232, 107, 43, 98, 59, 25, 123, 59, 250, 108, 7, 21, 105, 79, 72, 113, 27, 1, 88, 37, 20, 218, 254, 183, 233, 14, 124, 16, 59, 17, 164, 162, 242, 247, 9, 80, 7, 183, 151, 68, 41, 52, 22, 53, 134, 88, 223, 113, 154, 95, 205, 178, 170, 125, 216, 45, 152, 141, 76, 33, 184, 43, 186, 41, 151, 115, 223, 224, 97, 100, 154, 30, 74, 20, 148, 113, 180, 100, 226, 221, 19, 143, 119, 182, 45, 90, 99, 157, 90, 57, 80, 58, 227, 107, 36, 177, 138, 144, 245, 78, 4, 218, 205, 154, 147, 59, 62, 163, 67, 7, 174, 32, 91, 254, 145, 126, 187, 221, 208, 92, 111, 73, 170, 173, 107, 59, 69, 78, 7, 171, 135, 241, 148, 138, 50, 40, 228, 138, 10, 229, 228, 145, 95, 223, 13, 161, 183, 245, 41, 150, 149, 199, 7, 255, 138, 221, 142, 172, 65, 53, 31, 230, 47, 229, 126, 42, 131, 66, 18, 77, 203, 6, 222, 228, 215, 192, 209, 175, 98, 184, 159, 241, 106, 95, 255, 111, 55, 45, 234, 212, 4, 32, 208, 111, 37, 212, 53, 129, 70, 168, 156, 151, 188, 2, 121, 154, 140, 84, 155, 164, 51, 114, 142, 45, 24, 51, 99, 137, 224, 147, 212, 26, 220, 163, 19, 39, 180, 215, 53, 165, 162, 182, 233, 59, 221, 11, 90, 237, 112, 78, 36, 117, 233, 23, 229, 192, 94, 99, 96, 118, 171, 57, 42, 16, 98, 175, 43, 171, 196, 248, 18, 57, 19, 98, 181, 237, 235, 184, 177, 155, 6, 83, 179, 70, 162, 221, 121, 216, 116, 116, 200, 193, 164, 252, 59, 216, 48, 104, 112, 42, 207, 152, 246, 91, 109, 141, 68, 104, 49, 225, 210, 8, 79, 179, 62, 10, 31, 156, 189, 216, 179, 81, 102, 220, 79, 187, 167, 207, 11, 119, 83, 130, 24, 100, 215, 115, 143, 96, 213, 132, 109, 77, 35, 168, 40, 247, 133, 60, 55, 179, 26, 159, 70, 149, 59, 249, 130, 175, 113, 97, 166, 123, 156, 54, 129, 126, 197, 171, 18, 105, 91, 254, 211, 78, 233, 206, 145, 166, 101, 97, 32, 157, 236, 137, 252, 183, 59, 234, 219, 181, 236, 190, 76, 56, 145, 170, 245, 59, 208, 29, 16, 116, 45, 138, 135, 248, 118, 228, 3, 251, 244, 177, 85, 107, 13, 57, 60, 35, 237, 73, 5, 58, 172, 120, 165, 47, 223, 127, 98, 136, 84, 16, 18, 225, 126, 38, 100, 120, 35, 194, 204, 170, 144, 253, 217, 18, 86, 133, 225, 191, 220, 178, 177, 11, 51, 146, 205, 132, 128, 33, 90, 195, 234, 116, 68, 20, 73, 194, 135, 137, 0, 16, 169, 243, 123, 5, 130, 172, 162, 48, 240, 232, 208, 158, 32, 49, 140, 245, 51, 37, 131, 92, 67, 126, 44, 13, 31, 62, 240, 80, 131, 136, 187, 222, 199, 19, 28, 229, 240, 122, 208, 244, 180, 58, 232, 46, 1, 83, 171, 236, 220, 69, 6, 43, 152, 203, 3, 16, 246, 17, 69, 116, 54, 64, 9, 240, 109, 189, 32, 237, 189, 153, 148, 107, 2, 7, 224, 144, 242, 114, 76, 46, 66, 91, 31, 228, 112, 115, 124, 108, 39, 108, 229, 232, 245, 175, 122, 57, 47, 175, 12, 179, 39, 27, 172, 167, 249, 76, 135, 106, 133, 82, 162, 27, 220, 11, 94, 144, 228, 95, 114, 158, 217, 58, 24, 211, 24, 42, 118, 88, 178, 81, 163, 27, 41, 116, 193, 231, 88, 164, 166, 21, 95, 207, 245, 47, 245, 173, 56, 11, 144, 87, 124, 231, 79, 214, 60, 160, 185, 39, 102, 146, 204, 70, 202, 222, 203, 101, 183, 165, 180, 33, 216, 127, 96, 249, 7, 143, 237, 96, 186, 72, 40, 64, 213, 23, 251, 103, 123, 251, 135, 182, 237, 169, 43, 46, 30, 140, 133, 53, 127, 17, 18, 37, 31, 123, 86, 187, 5, 75, 64, 27, 13, 175, 180, 152, 249, 135, 82, 16, 139, 136, 204, 175, 27, 135, 255, 204, 39, 223, 160, 78, 6, 151, 95, 65, 13, 41, 64, 93, 64, 1, 218, 99, 109, 134, 201, 25, 62, 0, 191, 212, 140, 170, 8, 19, 28, 119, 45, 2, 53, 228, 169, 150, 252, 218, 233, 121, 176, 198, 208, 137, 58, 62, 37, 8, 150, 83, 247, 152, 133, 121, 85, 85, 2, 54, 179, 179, 105, 251, 99, 239, 223, 90, 42, 76, 49, 187, 250, 187, 197, 150, 141, 139, 36, 178, 143, 241, 206, 44, 80, 255, 14, 198, 156, 112, 154, 232, 11, 75, 53, 213, 83, 123, 94, 141, 155, 201, 113, 241, 56, 70, 252, 64, 158, 166, 165, 96, 152, 186, 2, 92, 3, 114, 52, 156, 134, 7, 222, 31, 90, 137, 52, 48, 12, 201, 84, 147, 254, 138, 19, 184, 114, 245, 138, 7, 90, 49, 167, 145, 107, 182, 83, 253, 40, 52, 160, 187, 243, 67, 151, 82, 3, 218, 68, 56, 202, 178, 144, 175, 238, 77, 145, 191, 171, 245, 128, 4, 208, 195, 102, 119, 57, 240, 6, 66, 254, 211, 45, 130, 58, 225, 51, 99, 73, 13, 56, 58, 28, 35, 110, 33, 180, 51, 26, 140, 70, 26, 229, 180, 229, 176, 138, 226, 9, 134, 129, 185, 187, 239, 223, 2, 229, 233, 150, 121, 138, 51, 41, 143, 68, 57, 118, 56, 31, 87, 195, 1, 75, 87, 156, 253, 225, 48, 243, 60, 94, 212, 205, 205, 151, 180, 100, 135, 245, 23, 108, 18, 5, 132, 244, 135, 177, 10, 37, 12, 28, 10, 127, 93, 103, 207, 148, 27, 227, 93, 148, 246, 204, 17, 88, 121, 29, 100, 198, 40, 185, 62, 104, 157, 5, 56, 71, 213, 100, 127, 249, 128, 244, 137, 235, 154, 144, 197, 8, 208, 124, 114, 242, 13, 251, 50, 254, 34, 91, 56, 10, 193, 195, 147, 85, 84, 21, 114, 112, 185, 50, 108, 118, 235, 123, 103, 247, 179, 202, 50, 17, 200, 66, 193, 58, 63, 43, 104, 163, 165, 140, 252, 54, 59, 102, 13, 117, 138, 175, 183, 48, 220, 215, 173, 86, 24, 135, 190, 226, 209, 212, 8, 111, 15, 152, 3, 126, 226, 149, 168, 204, 178, 165, 4, 230, 32, 34, 8, 79, 242, 94, 100, 141, 5, 125, 159, 109, 205, 161, 61, 95, 14, 59, 3, 132, 196, 133, 176, 198, 172, 25, 243, 70, 148, 96, 196, 241, 24, 65, 116, 30, 177, 162, 251, 228, 156, 147, 77, 244, 65, 138, 223, 212, 22, 40, 122, 1, 202, 219, 51, 101, 78, 118, 96, 101, 146, 112, 10, 180, 36, 211, 254, 136, 208, 48, 88, 82, 217, 33, 32, 148, 185, 234, 217, 100, 29, 141, 88, 247, 168, 34, 215, 165, 136, 149, 42, 203, 97, 227, 69, 216, 67, 65, 14, 27, 19, 84, 33, 141, 58, 75, 72, 178, 44, 16, 160, 251, 174, 94, 248, 52, 184, 125, 190, 77, 251, 88, 72, 11, 153, 160, 127, 77, 22, 127, 219, 245, 89, 76, 136, 192, 202, 239, 219, 248, 248, 171, 164, 198, 78, 148, 85, 159, 72, 218, 223, 99, 53, 38, 201, 186, 121, 68, 137, 194, 174, 136, 239, 224, 160, 67, 111, 220, 229, 93, 245, 31, 250, 193, 91, 110, 252, 12, 7, 131, 47, 62, 73, 10, 100, 129, 88, 40, 230, 53, 209, 146, 14, 132, 120, 204, 222, 135, 68, 47, 222, 19, 60, 161, 7, 67, 64, 68, 70, 29, 152, 64, 7, 183, 251, 225, 148, 61, 155, 127, 233, 89, 112, 169, 73, 157, 76, 150, 85, 219, 41, 71, 220, 234, 15, 173, 98, 124, 209, 206, 71, 56, 201, 187, 64, 16, 103, 159, 78, 9, 84, 251, 250, 154, 196, 49, 125, 168, 154, 127, 40, 15, 139, 198, 155, 71, 7, 80, 98, 219, 105, 202, 183, 96, 32, 115, 28, 168, 81, 69, 23, 103, 33, 219, 47, 154, 131, 125, 7, 229, 140, 163, 248, 62, 156, 231, 8, 141, 34, 232, 193, 150, 171, 224, 190, 62, 76, 79, 203, 161, 1, 186, 3, 67, 55, 0, 117, 153, 152, 165, 90, 146, 124, 169, 150, 90, 241, 163, 67, 146, 64, 13, 165, 218, 131, 135, 166, 193, 186, 200, 149, 8, 55, 9, 227, 66, 157, 212, 226, 97, 91, 172, 199, 196, 59, 3, 76, 170, 88, 8, 242, 30, 148, 211, 214, 208, 102, 225, 102, 165, 119, 155, 69, 208, 18, 168, 81, 84, 153, 79, 240, 92, 216, 36, 99, 75, 125, 249, 93, 182, 54, 232, 169, 235, 184, 210, 169, 104, 11, 163, 110, 116, 174, 218, 205, 75, 188, 68, 8, 194, 219, 137, 103, 93, 23, 10, 64, 49, 217, 198, 215, 166, 151, 189, 209, 148, 92, 61, 14, 11, 101, 129, 79, 230, 112, 234, 42, 125, 185, 107, 178, 135, 186, 78, 220, 33, 145, 91, 144, 176, 224, 134, 93, 16, 202, 31, 211, 10, 221, 21, 202, 245, 141, 245, 51, 147, 27, 192, 146, 205, 175, 255, 21, 186, 205, 62, 177, 127, 20, 231, 2, 81, 3, 161, 67, 225, 24, 66, 9, 102, 150, 218, 178, 3, 255, 65, 4, 141, 81, 0, 197, 198, 168, 72, 163, 246, 235, 224, 14, 62, 70, 205, 42, 161, 183, 151, 76, 86, 78, 101, 168, 253, 154, 46, 206, 132, 135, 104, 60, 217, 8, 128, 64, 60, 88, 6, 152, 85, 189, 49, 186, 230, 62, 156, 64, 47, 172, 148, 77, 114, 199, 27, 222, 122, 225, 213, 230, 57, 233, 175, 32, 113, 1, 36, 30, 146, 82, 127, 199, 75, 195, 196, 117, 250, 190, 80, 4, 229, 168, 125, 109, 55, 135, 0, 189, 75, 14, 58, 177, 239, 93, 131, 234, 227, 168, 209, 224, 140, 99, 240, 36, 225, 141, 184, 71, 253, 235, 142, 103, 83, 120, 97, 74, 94, 20, 13, 176, 36, 55, 204, 132, 64, 162, 157, 251, 233, 127, 119, 51, 143, 194, 94, 249, 60, 10, 141, 252, 138, 129, 160, 193, 213, 122, 197, 216, 74, 4, 20, 59, 47, 197, 124, 199, 186, 87, 30, 88, 120, 70, 15, 171, 134, 218, 144, 167, 229, 168, 35, 179, 203, 208, 151, 121, 47, 192, 83, 179, 102, 112, 147, 20, 118, 169, 148, 69, 103, 200, 134, 204, 254, 162, 24, 3, 120, 7, 226, 166, 163, 175, 153, 35, 252, 209, 15, 165, 29, 133, 23, 74, 179, 174, 196, 118, 97, 220, 139, 245, 22, 58, 125, 146, 250, 198, 163, 228, 225, 101, 103, 214, 180, 18, 111, 105, 127, 33, 249, 2, 217, 144, 86, 167, 107, 236, 76, 40, 72, 64, 24, 94, 2, 238, 174, 42, 26, 117, 41, 124, 44, 108, 0, 7, 49, 228, 158, 225, 78, 88, 247, 141, 142, 242, 207, 128, 58, 142, 40, 141, 36, 93, 17, 54, 9, 210, 175, 248, 170, 142, 121, 4, 221, 108, 1, 184, 162, 113, 221, 64, 181, 30, 9, 32, 13, 69, 14, 154, 11, 237, 136, 237, 188, 146, 233, 171, 57, 159, 80, 235, 12, 80, 151, 11, 42, 157, 137, 44, 104, 53, 241, 188, 62, 99, 253, 118, 220, 242, 169, 182, 146, 31, 113, 19, 16, 61, 6, 75, 128, 18, 5, 52, 168, 187, 7, 139, 94, 14, 12, 107, 223, 20, 134, 162, 13, 12, 142, 51, 39, 158, 99, 191, 124, 233, 4, 96, 172, 172, 84, 138, 84, 49, 91, 8, 133, 190, 160, 59, 122, 114, 72, 82, 57, 6, 93, 108, 9, 88, 252, 240, 247, 185, 170, 28, 163, 243, 228, 81, 212, 118, 86, 5, 30, 20, 80, 46, 173, 177, 119, 216, 111, 84, 139, 132, 97, 122, 67, 108, 176, 171, 31, 192, 71, 108, 22, 65, 42, 83, 221, 166, 15, 32, 207, 141, 92, 177, 170, 65, 169, 83, 65, 54, 118, 184, 156, 7, 197, 130, 29, 9, 157, 87, 71, 235, 66, 54, 225, 220, 48, 160, 193, 88, 185, 231, 251, 229, 157, 118, 66, 206, 143, 242, 42, 72, 52, 178, 243, 198, 193, 43, 12, 81, 121, 178, 65, 82, 39, 113, 135, 191, 197, 25, 142, 148, 52, 46, 123, 192, 188, 246, 95, 87, 173, 225, 162, 39, 182, 51, 169, 185, 228, 25, 115, 30, 210, 225, 47, 168, 93, 139, 76, 121, 224, 61, 30, 24, 45, 34, 37, 181, 180, 128, 145, 155, 43, 70, 224, 60, 218, 30, 252, 249, 131, 154, 168, 9, 191, 85, 234, 233, 1, 44, 212, 224, 137, 138, 217, 13, 22, 242, 242, 53, 56, 105, 189, 221, 117, 62, 23, 174, 5, 224, 90, 248, 165, 13, 60, 67, 82, 189, 152, 105, 3, 139, 183, 12, 172, 166, 171, 255, 217, 124, 209, 99, 54, 24, 198, 163, 255, 2, 240, 164, 227, 85, 33, 161, 145, 116, 165, 236, 167, 159, 144, 242, 3, 146, 19, 50, 41, 147, 107, 91, 175, 196, 255, 199, 237, 77, 251, 219, 134, 189, 244, 68, 30, 7, 75, 127, 198, 102, 251, 159, 11, 184, 93, 83, 138, 212, 140, 140, 6, 36, 173, 187, 180, 108, 151, 197, 118, 66, 79, 12, 118, 208, 46, 125, 226, 42, 57, 213, 210, 197, 108, 152, 71, 173, 149, 135, 237, 62, 232, 173, 29, 172, 126, 113, 71, 106, 218, 86, 188, 1, 33, 158, 245, 155, 87, 41, 192, 89, 211, 249, 179, 104, 18, 33, 85, 24, 147, 141, 184, 80, 179, 223, 73, 21, 49, 7, 51, 100, 176, 0, 147, 244, 197, 172, 193, 132, 53, 85, 13, 245, 234, 12, 200, 81, 229, 103, 54, 92, 103, 85, 26, 128, 20, 35, 187, 4, 27, 213, 225, 155, 33, 131, 173, 198, 30, 7, 9, 53, 196, 10, 94, 237, 163, 5, 172, 28, 113, 80, 194, 43, 145, 4, 236, 3, 72, 133, 153, 203, 227, 3, 246, 104, 97, 142, 157, 88, 45, 227, 179, 186, 37, 91, 33, 179, 62, 102, 144, 76, 199, 215, 113, 163, 177, 129, 129, 96, 215, 157, 4, 245, 192, 127, 80, 107, 219, 227, 216, 148, 203, 227, 212, 164, 165, 165, 83, 55, 18, 157, 178, 38, 72, 132, 180, 238, 70, 3, 12, 5, 97, 58, 155, 168, 184, 115, 175, 123, 17, 168, 187, 243, 74, 109, 199, 96, 126, 228, 98, 132, 15, 144, 164, 246, 57, 19, 83, 230, 184, 222, 50, 245, 22, 162, 245, 162, 146, 89, 186, 89, 5, 177, 128, 97, 29, 86, 147, 172, 67, 139, 57, 166, 137, 110, 149, 113, 229, 162, 164, 59, 218, 41, 17, 124, 43, 130, 13, 113, 199, 215, 165, 33, 146, 8, 220, 14, 151, 124, 1, 70, 231, 102, 246, 217, 176, 97, 79, 191, 243, 204, 172, 78, 71, 4, 239, 151, 227, 221, 255, 133, 178, 140, 248, 91, 235, 79, 111, 48, 181, 151, 236, 142, 165, 198, 189, 28, 53, 136, 250, 153, 75, 195, 82, 131, 204, 217, 175, 219, 137, 72, 87, 207, 28, 73, 112, 14, 44, 55, 68, 97, 88, 27, 154, 179, 9, 200, 145, 146, 232, 191, 23, 150, 223, 15, 205, 21, 161, 118, 30, 188, 186, 171, 208, 8, 63, 88, 180, 56, 192, 72, 228, 135, 104, 243, 190, 238, 39, 179, 179, 122, 84, 54, 120, 48, 154, 174, 253, 192, 59, 249, 111, 119, 73, 17, 139, 121, 27, 98, 57, 161, 222, 147, 146, 37, 54, 159, 66, 191, 158, 153, 60, 147, 6, 126, 84, 165, 19, 22, 147, 43, 148, 87, 63, 174, 214, 178, 22, 233, 112, 25, 157, 123, 118, 219, 179, 249, 182, 114, 217, 218, 80, 33, 248, 103, 89, 0, 87, 200, 154, 249, 23, 157, 67, 106, 97, 249, 183, 20, 67, 56, 75, 84, 176, 40, 0, 50, 144, 58, 38, 89, 93, 107, 197, 123, 90, 164, 99, 48, 17, 13, 212, 121, 152, 96, 84, 166, 118, 106, 128, 230, 107, 95, 26, 107, 4, 161, 48, 191, 181, 197, 150, 66, 18, 252, 11, 235, 79, 238, 66, 233, 26, 137, 89, 16, 5, 249, 174, 96, 250, 242, 12, 16, 241, 94, 73, 232, 36, 244, 54, 140, 38, 43, 213, 89, 53, 115, 212, 223, 21, 84, 167, 119, 246, 0, 5, 218, 87, 141, 124, 140, 206, 146, 171, 26, 171, 128, 9, 221, 33, 116, 110, 98, 87, 46, 15, 34, 41, 60, 123, 115, 8, 168, 183, 63, 117, 171, 129, 157, 216, 92, 75, 128, 46, 59, 169, 53, 33, 115, 65, 162, 155, 178, 128, 25, 109, 237, 41, 89, 107, 48, 23, 79, 191, 16, 205, 172, 148, 171, 201, 246, 104, 166, 6, 134, 23, 233, 136, 106, 157, 246, 136, 102, 57, 76, 34, 221, 231, 144, 129, 9, 26, 234, 97, 208, 97, 94, 134, 86, 25, 206, 224, 129, 138, 240, 108, 64, 17, 97, 248, 188, 16, 16, 184, 9, 123, 43, 18, 135, 33, 252, 11, 100, 46, 42, 20, 209, 144, 173, 136, 115, 65, 129, 236, 137, 53, 9, 5, 109, 211, 100, 75, 199, 57, 141, 40, 42, 32, 10, 66, 177, 93, 91, 215, 170, 24, 79, 41, 9, 230, 65, 104, 193, 139, 75, 233, 180, 90, 204, 152, 170, 244, 35, 149, 77, 41, 120, 50, 106, 72, 8, 103, 152, 32, 198, 161, 133, 129, 252, 38, 148, 229, 225, 133, 5, 81, 134, 16, 45, 17, 145, 114, 193, 12, 41, 18, 161, 219, 118, 197, 208, 151, 77, 227, 115, 137, 121, 225, 156, 42, 251, 13, 233, 206, 235, 129, 94, 197, 158, 104, 19, 26, 117, 164, 6, 236, 54, 97, 246, 84, 239, 138, 233, 18, 151, 202, 152, 137, 218, 168, 105, 128, 167, 7, 162, 193, 86, 129, 128, 95, 5, 237, 98, 57, 8, 155, 11, 199, 247, 109, 71, 90, 58, 206, 232, 88, 164, 210, 115, 126, 230, 26, 251, 216, 109, 3, 37, 203, 62, 194, 123, 27, 87, 107, 146, 154, 64, 194, 130, 148, 138, 89, 40, 242, 253, 235, 64, 128, 99, 74, 225, 162, 211, 246, 170, 219, 168, 158, 47, 173, 210, 184, 231, 53, 225, 124, 18, 57, 137, 223, 144, 48, 164, 114, 106, 209, 216, 70, 29, 69, 114, 131, 174, 112, 40, 234, 73, 138, 176, 194, 110, 119, 204, 79, 241, 81, 1, 18, 72, 164, 80, 97, 203, 114, 152, 4, 27, 118, 67, 177, 81, 53, 58, 15, 106, 163, 227, 43, 142, 91, 251, 72, 129, 99, 15, 173, 239, 36, 41, 54, 107, 131, 4, 66, 9, 42, 152, 125, 34, 68, 170, 80, 188, 250, 63, 62, 198, 231, 62, 246, 254, 127, 11, 248, 242, 76, 15, 173, 32, 230, 106, 145, 228, 85, 175, 156, 71, 40, 30, 78, 202, 15, 233, 254, 63, 68, 191, 238, 126, 87, 79, 31, 78, 135, 113, 199, 114, 193, 181, 215, 192, 108, 128, 120, 62, 34, 247, 87, 5, 111, 105, 244, 85, 56, 77, 112, 206, 109, 50, 74, 1, 163, 18, 158, 27, 21, 65, 122, 11, 232, 11, 85, 145, 177, 4, 246, 1, 133, 84, 70, 68, 61, 155, 51, 232, 150, 77, 34, 2, 64, 205, 110, 1, 179, 229, 251, 168, 238, 45, 9, 246, 52, 91, 13, 93, 109, 252, 70, 184, 105, 79, 40, 199, 91, 65, 31, 2, 163, 248, 150, 245, 2, 208, 223, 162, 18, 170, 125, 201, 16, 195, 242, 148, 17, 197, 153, 149, 234, 129, 134, 71, 30, 146, 2, 227, 248, 213, 121, 212, 153, 29, 101, 7, 246, 119, 92, 30, 63, 55, 73, 129, 27, 128, 162, 96, 10, 248, 250, 55, 99, 115, 129, 101, 230, 163, 14, 8, 158, 92, 159, 97, 2, 192, 149, 22, 3, 196, 9, 176, 114, 137, 2, 104, 182, 5, 134, 58, 60, 97, 146, 148, 6, 54, 33, 203, 162, 53, 23, 50, 45, 30, 228, 13, 233, 55, 200, 65, 150, 39, 104, 168, 200, 140, 65, 178, 143, 114, 40, 64, 225, 60, 43, 248, 40, 191, 0, 138, 172, 254, 185, 91, 2, 67, 184, 237, 169, 95, 69, 57, 162, 110, 78, 143, 92, 24, 7, 4, 63, 151, 107, 144, 82, 60, 19, 170, 227, 90, 163, 221, 81, 180, 224, 102, 136, 144, 152, 237, 77, 247, 168, 212, 87, 160, 135, 76, 58, 139, 227, 103, 212, 184, 10, 77, 150, 189, 39, 90, 149, 197, 204, 125, 100, 171, 79, 66, 202, 131, 89, 1, 15, 18, 85, 202, 30, 107, 110, 156, 181, 213, 87, 68, 44, 0, 13, 19, 69, 235, 242, 150, 69, 138, 65, 200, 55, 48, 178, 71, 211, 139, 121, 53, 182, 165, 252, 203, 117, 40, 100, 248, 16, 110, 70, 94, 39, 211, 236, 178, 194, 163, 191, 249, 233, 188, 244, 124, 122, 192, 107, 230, 78, 27, 175, 65, 222, 1, 217, 198, 37, 181, 19, 162, 241, 159, 133, 55, 110, 82, 134, 43, 192, 149, 126, 201, 214, 254, 223, 73, 62, 227, 220, 138, 83, 117, 190, 169, 25, 161, 135, 38, 83, 133, 204, 56, 212, 115, 38, 88, 46, 237, 27, 228, 40, 68, 24, 233, 116, 28, 119, 95, 36, 205, 134, 129, 220, 194, 44, 198, 222, 121, 227, 126, 192, 26, 175, 204, 149, 162, 71, 159, 158, 238, 116, 123, 249, 201, 74, 206, 30, 11, 40, 16, 72, 170, 42, 127, 197, 252, 159, 6, 9, 3, 110, 70, 213, 133, 181, 153, 92, 140, 105, 86, 185, 71, 115, 231, 85, 241, 220, 137, 34, 32, 52, 195, 234, 49, 220, 123, 165, 126, 247, 177, 10, 69, 93, 145, 71, 89, 211, 222, 234, 148, 198, 199, 206, 211, 35, 19, 96, 130, 231, 137, 108, 217, 123, 17, 167, 78, 141, 242, 196, 17, 129, 9, 159, 237, 183, 133, 1, 95, 26, 231, 8, 204, 152, 184, 96, 56, 144, 136, 128, 42, 236, 247, 18, 217, 172, 141, 57, 187, 21, 23, 198, 26, 109, 218, 180, 199, 199, 52, 118, 164, 120, 51, 3, 19, 152, 144, 249, 152, 74, 129, 82, 55, 204, 102, 74, 211, 97, 180, 104, 113, 209, 27, 229, 238, 60, 123, 251, 114, 201, 0, 8, 11, 126, 113, 102, 100, 1, 233, 218, 52, 166, 231, 69, 75, 10, 166, 179, 78, 191, 117, 254, 97, 201, 153, 1, 179, 188, 140, 137, 132, 34, 108, 132, 26, 216, 175, 234, 36, 196, 161, 45, 149, 180, 217, 174, 75, 129, 85, 205, 21, 110, 248, 108, 53, 154, 47, 4, 152, 72, 146, 46, 208, 106, 168, 37, 201, 232, 44, 211, 129, 57, 134, 251, 150, 29, 46, 60, 104, 20, 67, 56, 116, 61, 181, 52, 191, 143, 192, 5, 214, 81, 68, 73, 182, 179, 32, 23, 84, 124, 205, 49, 41, 137, 195, 167, 189, 38, 89, 22, 182, 242, 76, 52, 158, 92, 160, 224, 36, 154, 168, 212, 60, 182, 143, 12, 51, 123, 142, 80, 60, 112, 0, 213, 34, 3, 27, 161, 9, 108, 141, 28, 97, 102, 130, 29, 95, 191, 220, 148, 138, 190, 64, 49, 170, 159, 245, 227, 255, 3, 116, 128, 174, 124, 214, 165, 98, 78, 9, 216, 65, 206, 0, 240, 109, 119, 67, 165, 0, 22, 168, 170, 130, 2, 94, 14, 206, 158, 181, 157, 26, 44, 241, 21, 176, 84, 200, 91, 59, 16, 3, 138, 69, 84, 146, 150, 138, 226, 172, 18, 96, 49, 156, 163, 18, 212, 26, 169, 99, 98, 8, 205, 231, 18, 191, 36, 118, 189, 185, 60, 128, 83, 107, 88, 253, 58, 205, 163, 48, 163, 18, 221, 148, 128, 219, 103, 135, 40, 168, 232, 116, 68, 122, 38, 10, 62, 71, 41, 169, 34, 131, 174, 122, 58, 59, 82, 24, 59, 79, 184, 118, 242, 27, 214, 199, 140, 39, 105, 142, 148, 153, 43, 176, 126, 83, 217, 240, 118, 100, 76, 234, 70, 92, 22, 48, 46, 216, 75, 133, 119, 92, 108, 32, 99, 211, 25, 142, 175, 226, 156, 53, 178, 36, 117, 218, 218, 130, 5, 49, 215, 164, 191, 34, 234, 90, 1, 60, 151, 105, 226, 255, 94, 126, 182, 52, 164, 105, 139, 126, 178, 244, 160, 252, 170, 140, 160, 99, 186, 139, 43, 143, 92, 145, 250, 33, 139, 91, 252, 207, 17, 154, 169, 53, 140, 170, 64, 216, 181, 181, 69, 231, 198, 224, 170, 71, 21, 82, 187, 224, 216, 164, 51, 161, 2, 68, 131, 137, 107, 206, 196, 203, 20, 77, 51, 160, 234, 153, 61, 217, 109, 184, 164, 61, 249, 210, 156, 67, 254, 94, 254, 35, 139, 189, 123, 49, 111, 194, 101, 82, 135, 234, 205, 215, 109, 63, 84, 79, 221, 20, 132, 133, 79, 208, 84, 170, 123, 187, 24, 159, 243, 26, 124, 217, 103, 225, 238, 200, 80, 47, 245, 48, 17, 219, 60, 162, 146, 241, 182, 133, 72, 132, 4, 206, 197, 20, 181, 1, 135, 121, 121, 102, 202, 98, 211, 29, 88, 61, 100, 149, 6, 24, 103, 138, 194, 101, 107, 177, 206, 250, 179, 154, 47, 29, 144, 246, 120, 115, 27, 188, 252, 18, 150, 214, 198, 144, 182, 149, 178, 71, 12, 252, 147, 243, 126, 143, 187, 181, 21, 250, 253, 120, 103, 240, 28, 73, 36, 139, 61, 124, 6, 180, 161, 218, 142, 82, 245, 168, 60, 7, 197, 252, 83, 83, 68, 102, 64, 138, 25, 132, 194, 88, 240, 135, 232, 53, 70, 19, 212, 62, 102, 170, 32, 22, 5, 208, 231, 207, 89, 208, 157, 87, 96, 148, 67, 164, 172, 97, 249, 238, 116, 233, 217, 10, 225, 246, 202, 56, 222, 205, 23, 245, 76, 19, 201, 146, 68, 28, 166, 127, 67, 168, 145, 135, 194, 8, 129, 29, 180, 70, 38, 80, 142, 94, 9, 254, 58, 249, 113, 90, 121, 11, 27, 55, 110, 80, 43, 62, 116, 209, 48, 7, 133, 100, 72, 227, 79, 69, 25, 253, 109, 6, 127, 214, 182, 234, 26, 231, 79, 201, 180, 42, 209, 200, 185, 110, 118, 71, 103, 233, 178, 98, 56, 70, 193, 27, 32, 133, 115, 89, 37, 192, 103, 138, 49, 222, 9, 166, 94, 84, 214, 119, 147, 161, 190, 93, 253, 110, 110, 208, 89, 174, 143, 83, 164, 147, 39, 228, 244, 128, 66, 8, 46, 42, 225, 45, 150, 234, 138, 17, 139, 48, 33, 36, 88, 43, 219, 159, 3, 28, 230, 122, 23, 4, 116, 204, 220, 129, 173, 42, 0, 176, 17, 23, 221, 184, 218, 68, 210, 178, 163, 102, 122, 148, 105, 208, 188, 158, 52, 134, 84, 62, 90, 242, 66, 174, 54, 14, 51, 96, 205, 239, 250, 121, 155, 33, 163, 224, 42, 57, 199, 183, 224, 242, 114, 96, 160, 253, 199, 53, 253, 61, 158, 9, 32, 103, 93, 232, 0, 125, 247, 146, 32, 217, 137, 214, 186, 110, 15, 91, 127, 246, 127, 33, 135, 7, 44, 2, 162, 224, 205, 152, 69, 128, 162, 87, 10, 160, 38, 36, 59, 72, 118, 204, 166, 236, 102, 149, 44, 13, 60, 187, 63, 83, 19, 49, 253, 110, 147, 55, 20, 172, 83, 120, 0, 177, 96, 25, 49, 154, 37, 135, 8, 145, 124, 182, 7, 13, 47, 170, 118, 175, 60, 131, 98, 0, 128, 43, 58, 251, 84, 47, 10, 77, 140, 175, 223, 52, 132, 221, 193, 62, 191, 80, 150, 188, 62, 194, 149, 9, 145, 250, 79, 199, 24, 233, 21, 13, 55, 35, 212, 59, 6, 124, 64, 93, 67, 61, 98, 219, 129, 3, 163, 178, 107, 8, 173, 253, 110, 79, 175, 255, 253, 215, 170, 129, 49, 148, 31, 58, 203, 79, 101, 113, 18, 123, 212, 29, 2, 174, 8, 1, 14, 232, 64, 95, 205, 2, 18, 64, 181, 240, 112, 39, 155, 254, 68, 182, 53, 203, 108, 109, 215, 168, 12, 186, 184, 4, 45, 21, 222, 54, 155, 212, 64, 96, 186, 246, 162, 161, 32, 68, 205, 3, 240, 2, 207, 218, 168, 147, 50, 219, 208, 252, 74, 112, 131, 200, 28, 86, 42, 228, 62, 6, 128, 202, 234, 205, 32, 102, 143, 154, 128, 165, 77, 208, 44, 20, 134, 200, 75, 221, 112, 218, 178, 194, 170, 245, 151, 185, 16, 201, 98, 209, 37, 129, 168, 175, 23, 99, 72, 251, 40, 217, 139, 209, 131, 185, 222, 232, 197, 152, 198, 147, 33, 226, 225, 66, 211, 51, 150, 105, 103, 241, 27, 44, 236, 24, 170, 51, 142, 222, 8, 157, 106, 232, 145, 236, 170, 1, 17, 89, 91, 216, 40, 238, 187, 81, 30, 53, 51, 146, 206, 232, 142, 62, 189, 71, 145, 64, 40, 244, 96, 92, 51, 186, 135, 165, 172, 17, 180, 165, 204, 104, 232, 84, 147, 125, 49, 217, 183, 133, 14, 208, 208, 207, 195, 139, 234, 193, 139, 16, 25, 22, 131, 233, 222, 232, 97, 177, 245, 73, 225, 134, 164, 24, 121, 190, 150, 229, 85, 177, 235, 82, 164, 96, 175, 62, 105, 247, 93, 3, 84, 254, 101, 226, 65, 71, 70, 161, 190, 127, 111, 31, 239, 186, 185, 119, 191, 66, 238, 32, 58, 187, 136, 8, 3, 210, 127, 197, 17, 70, 225, 84, 248, 206, 18, 94, 163, 26, 93, 105, 96, 217, 210, 142, 12, 14, 91, 182, 61, 62, 208, 0, 91, 118, 195, 221, 38, 127, 81, 166, 106, 206, 141, 43, 191, 27, 205, 130, 156, 33, 135, 135, 38, 245, 222, 64, 39, 162, 70, 239, 152, 249, 105, 249, 4, 200, 130, 77, 65, 132, 230, 174, 163, 227, 57, 235, 106, 198, 186, 163, 244, 173, 248, 45, 238, 86, 108, 215, 100, 243, 114, 57, 125, 203, 135, 227, 122, 201, 247, 100, 19, 206, 13, 5, 29, 116, 117, 80, 19, 19, 112, 63, 63, 235, 42, 57, 7, 19, 253, 206, 106, 4, 143, 78, 61, 244, 217, 71, 252, 226, 229, 130, 205, 45, 254, 194, 233, 40, 250, 208, 32, 163, 106, 241, 161, 218, 23, 238, 94, 126, 208, 142, 223, 231, 43, 103, 178, 149, 172, 62, 33, 0, 198, 45, 197, 208, 157, 106, 21, 40, 88, 9, 211, 112, 8, 130, 246, 234, 102, 193, 185, 158, 176, 61, 40, 85, 16, 39, 238, 25, 205, 29, 100, 166, 5, 109, 34, 165, 187, 210, 36, 190, 170, 57, 243, 144, 157, 243, 24, 251, 95, 239, 23, 46, 149, 164, 179, 147, 231, 141, 111, 223, 3, 48, 175, 187, 172, 182, 225, 98, 187, 98, 180, 154, 99, 207, 38, 79, 233, 142, 163, 171, 59, 63, 151, 235, 70, 63, 32, 110, 112, 210, 11, 31, 221, 250, 245, 142, 90, 123, 8, 207, 96, 97, 29, 1, 178, 16, 151, 21, 132, 34, 19, 170, 74, 136, 70, 75, 164, 117, 97, 7, 209, 49, 64, 39, 67, 211, 233, 201, 255, 147, 85, 141, 238, 60, 253, 3, 26, 62, 66, 50, 69, 64, 4, 218, 89, 154, 254, 54, 24, 27, 136, 127, 254, 10, 77, 5, 60, 74, 116, 36, 4, 98, 129, 167, 228, 134, 187, 106, 250, 136, 174, 45, 180, 102, 38, 209, 246, 192, 231, 164, 95, 56, 74, 228, 22, 67, 141, 36, 124, 53, 192, 99, 254, 21, 110, 116, 72, 112, 231, 100, 195, 39, 222, 90, 212, 189, 174, 78, 220, 228, 36, 54, 54, 138, 230, 117, 22, 228, 24, 146, 90, 182, 180, 37, 142, 173, 194, 115, 146, 236, 192, 82, 132, 141, 5, 126, 82, 203, 70, 33, 147, 197, 234, 90, 205, 200, 180, 161, 34, 90, 156, 99, 108, 181, 185, 244, 105, 182, 12, 152, 53, 171, 149, 41, 243, 158, 153, 243, 14, 38, 161, 177, 181, 33, 27, 15, 194, 135, 20, 31, 156, 61, 53, 84, 209, 146, 179, 83, 178, 160, 170, 46, 15, 101, 178, 94, 60, 43, 22, 149, 141, 49, 199, 172, 178, 186, 23, 138, 173, 41, 244, 95, 129, 232, 165, 232, 32, 172, 45, 78, 227, 148, 56, 20, 163, 106, 35, 236, 99, 73, 132, 19, 138, 182, 171, 73, 185, 246, 99, 11, 62, 190, 255, 149, 83, 20, 37, 93, 203, 233, 83, 224, 94, 153, 149, 224, 4, 209, 138, 204, 161, 38, 50, 79, 187, 219, 29, 201, 189, 191, 107, 171, 0, 6, 23, 119, 144, 217, 146, 27, 249, 243, 234, 22, 146, 198, 248, 99, 200, 164, 120, 12, 147, 174, 101, 88, 248, 180, 111, 219, 38, 236, 203, 74, 76, 14, 73, 204, 131, 220, 92, 255, 176, 63, 133, 157, 99, 165, 237, 108, 195, 247, 104, 180, 228, 0, 128, 47, 135, 74, 184, 226, 134, 106, 118, 36, 34, 95, 80, 243, 17, 191, 4, 68, 48, 19, 28, 227, 232, 85, 147, 24, 173, 54, 20, 138, 240, 105, 203, 133, 145, 20, 134, 169, 85, 21, 168, 214, 136, 206, 46, 18, 85, 191, 167, 15, 255, 182, 60, 63, 93, 42, 61, 47, 22, 18, 82, 120, 223, 24, 50, 136, 141, 218, 227, 228, 120, 171, 49, 221, 134, 68, 222, 222, 123, 72, 17, 112, 23, 183, 227, 200, 170, 121, 13, 251, 113, 0, 184, 12, 128, 123, 75, 103, 100, 200, 161, 51, 255, 63, 83, 237, 198, 191, 117, 144, 109, 212, 34, 220, 180, 68, 69, 137, 55, 96, 216, 89, 42, 186, 104, 144, 227, 5, 102, 170, 118, 161, 133, 41, 227, 25, 244, 127, 249, 252, 132, 81, 115, 107, 59, 151, 158, 71, 69, 36, 52, 236, 254, 120, 107, 3, 100, 8, 25, 64, 174, 6, 71, 203, 11, 43, 43, 79, 75, 55, 50, 190, 208, 109, 48, 185, 253, 105, 126, 25, 1, 9, 136, 131, 150, 92, 200, 64, 154, 187, 74, 55, 167, 21, 65, 218, 202, 181, 65, 28, 213, 40, 105, 129, 212, 54, 141, 205, 106, 110, 71, 68, 109, 21, 73, 201, 173, 56, 193, 154, 144, 174, 152, 3, 81, 195, 27, 100, 231, 16, 28, 217, 11, 186, 123, 79, 149, 180, 167, 126, 93, 206, 180, 33, 45, 178, 250, 52, 96, 242, 26, 96, 128, 119, 128, 5, 24, 142, 156, 173, 159, 47, 97, 153, 16, 102, 86, 217, 161, 236, 39, 99, 33, 255, 206, 150, 165, 247, 136, 45, 175, 175, 211, 130, 174, 3, 21, 95, 41, 216, 230, 109, 168, 48, 10, 48, 97, 87, 201, 3, 221, 206, 15, 59, 6, 33, 88, 107, 115, 33, 0, 90, 170, 162, 68, 98, 150, 102, 85, 114, 79, 125, 72, 153, 218, 188, 221, 145, 206, 165, 157, 136, 96, 46, 175, 41, 99, 190, 46, 249, 224, 131, 82, 125, 229, 129, 156, 152, 248, 100, 215, 64, 40, 64, 98, 75, 249, 120, 171, 74, 65, 160, 210, 0, 215, 248, 207, 129, 148, 171, 192, 96, 79, 35, 196, 165, 232, 4, 48, 107, 145, 31, 1, 64, 145, 143, 235, 75, 43, 122, 197, 193, 97, 73, 13, 142, 36, 62, 34, 109, 47, 161, 122, 207, 184, 192, 76, 110, 210, 142, 195, 205, 178, 136, 233, 41, 184, 135, 53, 251, 69, 167, 206, 247, 16, 95, 116, 70, 225, 177, 113, 197, 94, 21, 252, 105, 245, 235, 93, 100, 226, 11, 254, 224, 214, 107, 187, 133, 152, 220, 200, 234, 237, 64, 252, 25, 76, 96, 58, 80, 201, 68, 154, 131, 141, 202, 221, 199, 26, 186, 87, 110, 199, 201, 251, 60, 170, 68, 240, 6, 15, 122, 149, 213, 110, 94, 246, 11, 50, 31, 170, 9, 3, 4, 148, 132, 9, 73, 147, 39, 120, 106, 52, 35, 73, 2, 226, 214, 68, 214, 228, 91, 4, 31, 196, 39, 129, 78, 61, 170, 247, 220, 136, 233, 67, 80, 154, 115, 140, 149, 159, 250, 208, 22, 26, 152, 199, 195, 240, 163, 80, 78, 92, 97, 238, 106, 145, 105, 18, 191, 108, 86, 197, 194, 227, 157, 51, 127, 25, 178, 11, 56, 114, 15, 102, 78, 165, 59, 53, 200, 28, 206, 141, 235, 10, 61, 154, 192, 58, 228, 132, 135, 241, 19, 116, 114, 185, 103, 210, 146, 117, 162, 19, 163, 244, 251, 123, 194, 164, 19, 209, 218, 105, 158, 87, 242, 132, 219, 4, 188, 104, 0, 219, 95, 47, 151, 15, 115, 87, 217, 218, 124, 220, 237, 40, 45, 188, 241, 81, 110, 249, 17, 69, 70, 13, 230, 76, 68, 26, 118, 147, 250, 254, 76, 195, 46, 65, 79, 181, 24, 145, 125, 55, 49, 109, 57, 171, 53, 45, 93, 198, 139, 254, 229, 160, 116, 221, 4, 20, 22, 202, 4, 87, 64, 235, 68, 180, 214, 192, 169, 224, 96, 104, 250, 56, 49, 87, 70, 38, 239, 58, 124, 27, 69, 83, 232, 127, 154, 42, 186, 53, 91, 76, 129, 202, 72, 209, 197, 182, 57, 64, 2, 34, 82, 214, 42, 126, 198, 202, 222, 241, 87, 230, 6, 162, 158, 199, 39, 215, 119, 83, 72, 172, 176, 208, 204, 67, 174, 212, 153, 70, 2, 150, 162, 175, 242, 13, 170, 143, 4, 45, 96, 44, 190, 62, 148, 184, 239, 234, 134, 116, 239, 63, 195, 15, 136, 12, 238, 69, 18, 46, 22, 59, 104, 212, 202, 66, 185, 44, 68, 55, 85, 29, 82, 181, 184, 183, 61, 200, 152, 103, 13, 82, 236, 12, 213, 158, 205, 33, 177, 139, 117, 206, 105, 78, 80, 153, 27, 222, 169, 37, 112, 79, 99, 182, 217, 35, 9, 210, 28, 241, 196, 236, 51, 104, 208, 247, 74, 118, 216, 247, 107, 182, 56, 105, 185, 131, 225, 2, 58, 80, 59, 75, 218, 52, 166, 17, 52, 0, 149, 191, 153, 67, 56, 164, 10, 169, 247, 143, 175, 203, 160, 41, 77, 251, 166, 119, 153, 146, 101, 149, 130, 22, 23, 89, 95, 128, 254, 130, 30, 100, 28, 164, 202, 224, 231, 167, 170, 9, 101, 210, 211, 144, 16, 83, 146, 204, 101, 168, 56, 133, 169, 168, 7, 65, 46, 224, 177, 28, 233, 43, 7, 27, 93, 58, 239, 75, 237, 14, 197, 213, 232, 57, 30, 39, 211, 248, 243, 192, 246, 85, 190, 64, 231, 7, 136, 60, 10, 67, 168, 185, 128, 60, 77, 210, 235, 211, 123, 24, 55, 66, 163, 201, 141, 30, 212, 130, 125, 171, 104, 57, 254, 60, 106, 25, 41, 109, 172, 195, 46, 50, 183, 222, 15, 55, 171, 47, 79, 1, 40, 32, 241, 140, 103, 13, 70, 187, 151, 50, 192, 125, 54, 108, 98, 39, 134, 10, 211, 94, 62, 198, 206, 100, 58, 220, 107, 30, 237, 113, 236, 157, 202, 244, 132, 239, 246, 147, 248, 166, 249, 79, 251, 123, 198, 203, 207, 46, 147, 37, 200, 158, 18, 237, 175, 91, 12, 225, 179, 140, 145, 84, 137, 5, 34, 56, 36, 102, 199, 89, 101, 225, 185, 38, 200, 1, 251, 73, 98, 211, 137, 135, 22, 32, 241, 144, 245, 142, 106, 22, 158, 105, 45, 192, 109, 25, 249, 251, 42, 206, 58, 20, 71, 169, 175, 96, 37, 147, 146, 34, 56, 220, 19, 137, 142, 151, 49, 174, 177, 103, 143, 251, 245, 165, 93, 105, 122, 52, 78, 57, 65, 25, 21, 241, 1, 29, 31, 228, 250, 89, 49, 51, 171, 21, 155, 92, 201, 1, 143, 132, 91, 124, 192, 40, 59, 79, 10, 185, 189, 76, 188, 123, 120, 181, 78, 208, 139, 217, 222, 121, 208, 224, 212, 175, 25, 202, 29, 122, 175, 168, 211, 52, 146, 3, 4, 50, 37, 161, 159, 183, 223, 7, 181, 180, 190, 147, 118, 119, 120, 81, 27, 132, 2, 111, 182, 81, 192, 95, 145, 229, 95, 61, 242, 51, 208, 5, 152, 207, 221, 165, 180, 219, 71, 50, 248, 72, 250, 38, 118, 202, 190, 235, 60, 250, 243, 163, 217, 101, 132, 31, 163, 89, 1, 1, 8, 14, 148, 100, 176, 29, 187, 10, 154, 87, 253, 143, 209, 162, 216, 130, 91, 237, 29, 187, 250, 150, 193, 67, 80, 165, 163, 148, 91, 54, 17, 187, 179, 154, 233, 234, 41, 185, 102, 176, 132, 48, 233, 133, 97, 229, 68, 142, 131, 90, 239, 63, 224, 150, 164, 91, 24, 251, 33, 18, 135, 117, 188, 154, 104, 59, 129, 88, 186, 141, 130, 165, 198, 149, 66, 110, 201, 20, 104, 195, 30, 7, 22, 66, 9, 32, 73, 120, 168, 127, 28, 58, 171, 103, 164, 57, 173, 10, 182, 125, 27, 169, 15, 97, 200, 167, 41, 187, 184, 13, 181, 176, 77, 43, 242, 232, 131, 252, 98, 84, 67, 254, 210, 240, 183, 232, 132, 16, 253, 129, 155, 236, 170, 13, 42, 244, 88, 86, 150, 60, 103, 59, 214, 240, 75, 20, 46, 9, 212, 71, 63, 66, 64, 135, 240, 67, 72, 253, 112, 73, 152, 250, 231, 142, 192, 149, 23, 137, 14, 115, 60, 135, 29, 134, 12, 4, 154, 86, 47, 7, 122, 51, 134, 249, 28, 222, 227, 191, 224, 107, 151, 157, 4, 200, 161, 131, 50, 248, 55, 222, 99, 97, 171, 84, 209, 146, 75, 78, 33, 37, 129, 172, 194, 235, 181, 248, 146, 127, 66, 72, 189, 59, 77, 211, 157, 5, 241, 113, 111, 47, 185, 24, 142, 240, 212, 125, 96, 166, 132, 16, 57, 30, 83, 164, 63, 243, 225, 56, 62, 87, 111, 75, 134, 154, 175, 213, 41, 186, 116, 42, 51, 144, 94, 22, 179, 252, 103, 231, 125, 45, 235, 218, 57, 232, 207, 132, 2, 221, 118, 176, 232, 181, 222, 247, 46, 2, 49, 120, 174, 47, 206, 38, 148, 117, 106, 135, 201, 193, 118, 63, 253, 24, 133, 69, 133, 95, 1, 152, 35, 6, 109, 234, 25, 183, 59, 113, 192, 238, 0, 112, 154, 30, 61, 167, 240, 75, 65, 75, 158, 162, 45, 38, 104, 227, 120, 194, 159, 141, 220, 187, 60, 121, 227, 233, 192, 197, 207, 249, 183, 20, 57, 3, 235, 71, 88, 146, 178, 101, 78, 32, 20, 255, 17, 95, 139, 112, 195, 73, 69, 86, 224, 21, 157, 86, 30, 42, 152, 188, 77, 191, 35, 212, 42, 88, 107, 162, 186, 102, 98, 48, 110, 179, 174, 198, 123, 69, 177, 169, 179, 107, 182, 249, 232, 28, 37, 193, 162, 99, 36, 171, 32, 27, 152, 97, 167, 55, 141, 248, 67, 133, 152, 125, 113, 68, 183, 139, 232, 96, 196, 91, 47, 104, 109, 249, 128, 171, 19, 153, 23, 113, 142, 191, 90, 146, 188, 161, 112, 31, 110, 31, 50, 65, 137, 55, 10, 44, 234, 57, 112, 194, 39, 71, 112, 115, 56, 177, 158, 35, 190, 153, 119, 97, 128, 72, 38, 252, 67, 27, 130, 18, 68, 149, 0, 246, 236, 9, 194, 140, 219, 18, 131, 227, 224, 116, 68, 154, 140, 79, 135, 223, 154, 73, 141, 84, 179, 6, 149, 233, 48, 234, 166, 74, 8, 9, 229, 241, 33, 84, 205, 226, 241, 43, 63, 9, 70, 163, 184, 58, 204, 53, 160, 46, 248, 38, 67, 155, 157, 207, 182, 112, 171, 65, 140, 50, 174, 80, 17, 226, 178, 243, 169, 80, 130, 101, 242, 89, 137, 5, 158, 52, 16, 139, 119, 175, 210, 112, 63, 50, 53, 173, 35, 64, 13, 40, 133, 102, 197, 250, 170, 152, 13, 102, 105, 138, 61, 100, 1, 109, 248, 107, 190, 169, 15, 45, 182, 36, 236, 34, 188, 125, 44, 119, 140, 63, 87, 74, 197, 201, 85, 193, 36, 71, 152, 130, 186, 122, 10, 176, 99, 73, 241, 208, 131, 134, 210, 136, 211, 25, 77, 202, 242, 167, 189, 163, 112, 162, 132, 55, 64, 94, 113, 111, 60, 51, 100, 136, 83, 238, 135, 190, 14, 147, 201, 36, 240, 173, 37, 45, 25, 153, 71, 15, 36, 200, 0, 241, 149, 194, 180, 141, 54, 37, 17, 72, 88, 157, 107, 137, 145, 203, 178, 208, 5, 190, 112, 19, 200, 90, 152, 8, 122, 212, 172, 130, 0, 156, 83, 106, 199, 126, 53, 126, 118, 78, 142, 164, 110, 2, 51, 206, 229, 115, 164, 191, 188, 96, 242, 143, 76, 210, 19, 63, 160, 210, 53, 167, 191, 74, 137, 36, 107, 94, 236, 129, 24, 128, 42, 156, 72, 104, 220, 101, 196, 198, 173, 191, 235, 202, 210, 187, 143, 3, 222, 146, 109, 142, 94, 19, 176, 150, 161, 146, 14, 191, 77, 100, 101, 96, 10, 249, 193, 34, 40, 141, 99, 39, 170, 25, 64, 196, 228, 160, 7, 219, 209, 252, 9, 114, 137, 126, 157, 36, 124, 50, 106, 130, 138, 182, 166, 54, 251, 227, 157, 200, 78, 225, 82, 14, 233, 140, 69, 26, 10, 67, 15, 41, 109, 11, 178, 125, 76, 165, 155, 68, 205, 194, 3, 146, 142, 85, 112, 3, 191, 97, 46, 210, 36, 135, 216, 160, 164, 87, 223, 136, 242, 110, 0, 138, 113, 115, 3, 255, 95, 124, 195, 237, 171, 192, 244, 168, 74, 174, 184, 181, 149, 17, 63, 111, 106, 173, 221, 66, 203, 120, 137, 222, 69, 236, 124, 226, 216, 137, 75, 217, 128, 79, 121, 189, 237, 116, 142, 247, 17, 9, 193, 66, 160, 232, 27, 85, 174, 153, 198, 4, 238, 28, 199, 138, 28, 204, 64, 178, 151, 43, 24, 208, 179, 88, 149, 94, 59, 255, 108, 237, 122, 86, 199, 172, 246, 24, 3, 13, 144, 84, 140, 207, 186, 6, 112, 201, 69, 44, 94, 160, 76, 155, 125, 146, 24, 254, 41, 12, 126, 175, 32, 241, 112, 251, 221, 52, 2, 96, 153, 128, 81, 191, 167, 233, 101, 20, 22, 49, 15, 235, 228, 193, 200, 48, 165, 179, 192, 154, 192, 52, 56, 235, 8, 216, 21, 72, 50, 4, 173, 34, 50, 135, 19, 114, 142, 54, 97, 247, 23, 218, 64, 223, 120, 196, 97, 37, 123, 214, 227, 245, 42, 110, 7, 225, 122, 146, 39, 159, 151, 108, 229, 130, 237, 169, 6, 61, 178, 237, 105, 121, 90, 22, 228, 249, 12, 29, 143, 207, 179, 52, 17, 163, 169, 120, 149, 242, 51, 36, 236, 95, 194, 26, 35, 226, 224, 47, 203, 138, 159, 183, 208, 41, 20, 130, 86, 9, 99, 131, 192, 175, 123, 54, 43, 120, 190, 0, 203, 178, 80, 119, 181, 39, 159, 210, 140, 147, 69, 24, 220, 168, 50, 255, 51, 34, 123, 141, 167, 160, 138, 67, 189, 206, 207, 230, 193, 95, 190, 161, 33, 231, 80, 77, 15, 134, 216, 33, 208, 235, 88, 131, 41, 146, 214, 30, 229, 220, 248, 114, 132, 10, 175, 38, 124, 55, 160, 172, 152, 37, 64, 124, 29, 233, 63, 1, 36, 239, 231, 54, 4, 79, 48, 109, 203, 128, 130, 25, 64, 83, 151, 227, 15, 226, 78, 8, 14, 117, 100, 58, 192, 243, 65, 6, 69, 88, 196, 180, 11, 140, 127, 182, 74, 187, 24, 156, 129, 20, 88, 212, 145, 235, 158, 107, 37, 39, 141, 1, 10, 112, 244, 25, 209, 37, 187, 30, 130, 177, 141, 161, 170, 129, 255, 139, 111, 40, 20, 61, 23, 60, 17, 104, 35, 134, 120, 241, 132, 25, 171, 119, 184, 22, 56, 66, 79, 153, 9, 78, 173, 9, 108, 93, 75, 177, 0, 250, 15, 254, 84, 67, 40, 99, 19, 171, 110, 3, 229, 22, 164, 144, 0, 220, 23, 98, 161, 224, 118, 52, 129, 201, 15, 164, 180, 156, 217, 139, 213, 108, 43, 61, 36, 218, 200, 85, 54, 157, 11, 47, 121, 6, 249, 158, 231, 22, 143, 28, 5, 82, 88, 188, 160, 250, 244, 237, 15, 63, 139, 235, 244, 224, 12, 62, 238, 177, 75, 197, 192, 225, 203, 38, 43, 197, 17, 178, 92, 224, 234, 102, 204, 83, 28, 209, 46, 156, 213, 31, 48, 32, 94, 118, 227, 27, 36, 212, 223, 0, 153, 208, 193, 156, 145, 100, 148, 119, 213, 20, 106, 96, 6, 105, 230, 182, 199, 33, 153, 118, 212, 36, 54, 80, 199, 254, 116, 202, 39, 201, 245, 163, 177, 236, 75, 159, 233, 37, 27, 37, 31, 25, 237, 65, 19, 190, 222, 251, 179, 199, 245, 147, 197, 238, 205, 48, 169, 250, 233, 174, 212, 235, 9, 115, 105, 161, 145, 199, 19, 202, 208, 98, 213, 47, 27, 53, 57, 124, 248, 12, 245, 2, 234, 80, 107, 213, 182, 5, 243, 29, 238, 192, 110, 132, 174, 114, 243, 123, 102, 119, 241, 100, 86, 27, 13, 210, 46, 7, 204, 144, 180, 223, 55, 47, 37, 126, 104, 16, 62, 109, 75, 245, 4, 128, 241, 149, 0, 125, 154, 82, 0, 146, 255, 99, 121, 57, 247, 120, 185, 201, 183, 102, 10, 66, 221, 252, 235, 33, 64, 60, 69, 250, 119, 211, 223, 118, 189, 253, 229, 194, 13, 230, 100, 111, 209, 71, 90, 217, 141, 40, 196, 171, 168, 118, 252, 16, 192, 124, 148, 41, 109, 126, 234, 85, 219, 95, 130, 167, 217, 196, 199, 231, 219, 77, 100, 190, 106, 253, 225, 180, 190, 193, 0, 76, 181, 254, 210, 241, 196, 76, 50, 158, 234, 120, 116, 136, 75, 52, 192, 192, 6, 16, 9, 0, 137, 110, 144, 246, 55, 14, 204, 135, 172, 93, 226, 121, 120, 0, 112, 2, 165, 151, 57, 160, 215, 201, 178, 237, 229, 194, 76, 145, 83, 103, 17, 121, 130, 192, 21, 116, 6, 252, 97, 219, 72, 173, 174, 227, 26, 128, 206, 197, 51, 31, 122, 29, 187, 60, 132, 168, 148, 90, 39, 219, 87, 117, 178, 210, 99, 121, 43, 116, 82, 21, 17, 135, 11, 3, 24, 117, 15, 222, 207, 206, 41, 242, 2, 150, 44, 174, 28, 218, 187, 181, 71, 196, 137, 193, 135, 105, 16, 172, 54, 143, 115, 79, 192, 207, 130, 21, 195, 213, 37, 244, 50, 82, 36, 62, 236, 31, 79, 193, 244, 166, 96, 239, 250, 238, 181, 65, 254, 193, 246, 143, 204, 94, 71, 6, 198, 168, 141, 48, 0, 228, 153, 70, 86, 4, 28, 87, 208, 182, 82, 12, 93, 32, 134, 176, 196, 176, 106, 36, 30, 166, 151, 128, 33, 89, 28, 171, 26, 120, 184, 227, 229, 5, 106, 165, 100, 57, 82, 248, 165, 3, 172, 98, 114, 235, 68, 178, 80, 228, 66, 139, 50, 107, 235, 68, 148, 115, 127, 111, 199, 8, 95, 64, 190, 243, 90, 232, 64, 0, 6, 234, 225, 143, 45, 171, 9, 242, 88, 109, 135, 246, 54, 31, 158, 46, 196, 2, 189, 147, 152, 70, 147, 170, 150, 134, 77, 87, 165, 64, 134, 254, 202, 193, 190, 200, 89, 21, 217, 241, 229, 110, 154, 16, 15, 20, 111, 112, 183, 208, 75, 146, 111, 201, 84, 41, 9, 133, 8, 7, 224, 162, 168, 20, 118, 191, 48, 134, 215, 129, 72, 223, 44, 193, 132, 2, 94, 177, 33, 166, 248, 249, 108, 16, 36, 231, 134, 245, 48, 213, 23, 155, 110, 206, 95, 77, 211, 49, 193, 95, 6, 63, 113, 52, 75, 163, 225, 78, 242, 245, 34, 153, 240, 53, 187, 224, 205, 223, 173, 78, 196, 129, 100, 150, 139, 157, 111, 145, 145, 176, 203, 100, 190, 115, 50, 94, 51, 137, 96, 175, 169, 91, 204, 155, 101, 35, 185, 68, 254, 116, 65, 85, 63, 75, 187, 28, 104, 224, 7, 117, 149, 129, 209, 50, 89, 60, 199, 215, 117, 147, 205, 225, 36, 39, 103, 69, 5, 91, 43, 115, 26, 131, 98, 217, 144, 123, 149, 82, 120, 45, 177, 229, 37, 3, 134, 3, 25, 25, 184, 6, 41, 142, 180, 82, 218, 18, 152, 89, 155, 83, 237, 55, 171, 31, 193, 37, 232, 246, 138, 105, 215, 81, 37, 35, 15, 82, 198, 146, 21, 41, 18, 128, 242, 250, 32, 56, 47, 150, 116, 193, 46, 178, 84, 7, 39, 124, 147, 132, 29, 94, 255, 48, 164, 66, 255, 9, 228, 33, 195, 122, 6, 125, 65, 113, 90, 186, 179, 51, 52, 90, 224, 112, 204, 14, 92, 37, 179, 184, 62, 169, 189, 97, 143, 199, 179, 212, 55, 196, 106, 26, 201, 36, 192, 253, 157, 170, 209, 155, 154, 2, 232, 152, 154, 107, 233, 138, 245, 110, 208, 41, 38, 7, 216, 79, 185, 21, 17, 47, 80, 0, 116, 242, 11, 247, 93, 85, 116, 81, 108, 129, 246, 103, 41, 56, 161, 39, 109, 143, 107, 157, 165, 115, 215, 33, 66, 113, 122, 49, 89, 38, 225, 162, 94, 221, 169, 44, 145, 225, 195, 233, 30, 65, 188, 17, 86, 245, 52, 185, 69, 66, 179, 210, 185, 45, 211, 134, 178, 166, 115, 53, 239, 161, 187, 176, 206, 216, 31, 191, 63, 65, 193, 192, 150, 237, 9, 132, 13, 147, 243, 87, 148, 116, 213, 205, 43, 243, 242, 188, 108, 28, 49, 65, 23, 25, 242, 67, 227, 120, 46, 124, 153, 165, 127, 29, 91, 250, 140, 65, 79, 67, 59, 49, 37, 124, 125, 245, 226, 224, 150, 193, 165, 6, 92, 189, 189, 114, 199, 239, 13, 11, 78, 42, 4, 195, 24, 115, 23, 231, 32, 232, 201, 24, 166, 12, 115, 53, 46, 6, 126, 74, 245, 144, 37, 22, 63, 36, 29, 149, 11, 229, 83, 109, 7, 78, 199, 24, 129, 204, 162, 118, 44, 133, 11, 234, 253, 12, 41, 110, 150, 188, 80, 66, 126, 144, 121, 32, 36, 237, 19, 235, 218, 50, 94, 253, 46, 25, 54, 124, 191, 67, 128, 143, 42, 200, 117, 108, 218, 112, 116, 123, 163, 187, 1, 209, 137, 24, 107, 156, 168, 193, 71, 247, 36, 117, 246, 4, 6, 51, 32, 147, 42, 170, 142, 101, 142, 216, 148, 9, 170, 154, 108, 165, 208, 106, 179, 236, 100, 17, 214, 232, 222, 145, 58, 210, 148, 100, 81, 255, 69, 8, 173, 194, 200, 56, 80, 66, 244, 90, 42, 7, 244, 123, 171, 22, 102, 1, 134, 9, 165, 208, 173, 136, 221, 156, 4, 57, 185, 34, 149, 106, 204, 21, 227, 60, 35, 1, 107, 176, 74, 109, 81, 66, 147, 172, 91, 32, 251, 21, 168, 167, 188, 93, 142, 159, 188, 16, 134, 67, 51, 137, 234, 158, 123, 112, 31, 186, 156, 160, 137, 8, 7, 202, 94, 190, 250, 24, 169, 230, 130, 232, 112, 166, 226, 153, 46, 29, 148, 108, 113, 112, 97, 103, 125, 36, 21, 119, 25, 185, 241, 35, 116, 211, 138, 35, 11, 140, 1, 50, 178, 91, 134, 31, 89, 69, 22, 53, 119, 150, 81, 48, 39, 29, 224, 77, 102, 117, 139, 139, 40, 32, 17, 153, 24, 17, 228, 35, 142, 9, 43, 147, 22, 88, 113, 121, 213, 11, 252, 157, 187, 190, 53, 201, 195, 239, 146, 244, 163, 122, 203, 41, 99, 32, 211, 30, 29, 32, 147, 13, 142, 239, 67, 44, 69, 185, 0, 18, 242, 222, 11, 86, 211, 59, 104, 196, 181, 152, 143, 248, 64, 42, 193, 1, 88, 157, 77, 37, 227, 81, 165, 213, 176, 198, 124, 178, 15, 200, 176, 131, 190, 21, 172, 146, 219, 164, 0, 168, 147, 110, 132, 1, 72, 131, 229, 128, 52, 183, 124, 198, 223, 172, 123, 135, 244, 217, 13, 246, 241, 207, 39, 149, 50, 52, 22, 206, 254, 34, 64, 200, 235, 210, 217, 43, 28, 171, 8, 111, 66, 96, 123, 29, 178, 7, 31, 150, 156, 42, 26, 16, 42, 117, 8, 157, 189, 104, 175, 27, 159, 238, 255, 232, 62, 221, 210, 8, 138, 159, 14, 199, 115, 146, 86, 143, 242, 80, 233, 9, 182, 197, 191, 70, 246, 98, 66, 216, 11, 123, 31, 236, 123, 39, 144, 67, 118, 202, 86, 217, 24, 86, 20, 21, 245, 34, 247, 186, 201, 134, 65, 169, 196, 231, 87, 152, 62, 97, 122, 38, 69, 180, 26, 81, 100, 88, 175, 203, 26, 107, 33, 209, 180, 202, 141, 4, 254, 108, 129, 190, 124, 23, 214, 130, 213, 6, 154, 17, 9, 204, 177, 47, 142, 113, 161, 125, 89, 56, 230, 112, 129, 212, 189, 164, 89, 149, 95, 107, 253, 37, 251, 80, 178, 134, 57, 230, 71, 96, 213, 74, 226, 199, 103, 45, 17, 49, 20, 141, 205, 246, 136, 236, 194, 62, 102, 23, 155, 67, 50, 74, 18, 164, 52, 20, 149, 193, 121, 75, 253, 217, 224, 74, 221, 179, 202, 11, 73, 63, 224, 175, 9, 228, 182, 51, 193, 218, 108, 140, 225, 141, 107, 243, 41, 170, 215, 184, 109, 9, 250, 187, 123, 28, 254, 94, 4, 116, 24, 65, 29, 106, 54, 71, 147, 229, 246, 248, 241, 143, 163, 219, 146, 137, 76, 6, 240, 226, 7, 207, 24, 242, 243, 108, 0, 120, 104, 189, 104, 203, 153, 201, 109, 142, 89, 214, 93, 59, 244, 210, 187, 228, 135, 156, 122, 42, 206, 6, 108, 97, 197, 137, 145, 78, 24, 76, 169, 7, 224, 221, 209, 48, 254, 29, 67, 34, 1, 144, 220, 15, 44, 109, 52, 56, 200, 150, 169, 17, 236, 11, 252, 209, 36, 155, 147, 36, 4, 48, 13, 172, 29, 178, 65, 206, 117, 58, 7, 228, 239, 210, 196, 79, 68, 219, 165, 174, 169, 132, 212, 11, 236, 243, 130, 195, 118, 57, 109, 137, 186, 208, 62, 202, 14, 138, 60, 6, 86, 116, 129, 172, 242, 27, 156, 14, 184, 68, 81, 3, 60, 124, 98, 214, 22, 50, 47, 218, 125, 181, 77, 125, 0, 170, 53, 202, 202, 10, 227, 211, 167, 32, 230, 102, 65, 188, 80, 246, 42, 143, 48, 167, 17, 129, 248, 5, 195, 134, 79, 251, 148, 55, 84, 215, 101, 73, 52, 134, 60, 65, 211, 14, 226, 131, 243, 136, 83, 3, 246, 249, 130, 137, 71, 141, 252, 152, 45, 20, 92, 102, 248, 223, 50, 149, 86, 214, 191, 107, 178, 14, 96, 1, 120, 84, 109, 65, 165, 46, 172, 166, 91, 6, 51, 72, 123, 128, 169, 104, 194, 53, 154, 63, 122, 16, 111, 220, 253, 113, 207, 131, 236, 170, 248, 16, 176, 189, 9, 234, 126, 78, 210, 169, 162, 105, 229, 138, 179, 56, 233, 48, 51, 170, 188, 215, 233, 186, 17, 19, 54, 209, 203, 75, 93, 158, 198, 58, 10, 120, 51, 52, 244, 55, 117, 188, 177, 145, 41, 173, 98, 110, 28, 82, 244, 141, 60, 198, 80, 174, 246, 95, 120, 176, 247, 149, 91, 22, 218, 94, 113, 108, 250, 0, 200, 17, 127, 144, 206, 107, 9, 139, 229, 206, 233, 44, 253, 100, 155, 142, 72, 20, 150, 157, 254, 144, 236, 79, 219, 34, 174, 104, 14, 217, 193, 249, 59, 28, 238, 207, 106, 39, 25, 6, 75, 32, 88, 124, 158, 34, 98, 60, 34, 172, 35, 163, 216, 134, 111, 198, 166, 120, 55, 109, 118, 250, 86, 31, 6, 27, 5, 81, 182, 187, 226, 162, 43, 80, 61, 35, 235, 128, 28, 113, 172, 157, 225, 69, 2, 9, 94, 11, 117, 103, 40, 189, 236, 131, 75, 136, 12, 60, 112, 66, 159, 208, 178, 200, 175, 37, 221, 225, 97, 130, 113, 237, 120, 69, 149, 8, 155, 10, 107, 183, 247, 75, 108, 165, 119, 121, 133, 46, 35, 11, 18, 187, 5, 5, 39, 102, 199, 163, 159, 112, 58, 19, 229, 72, 185, 188, 120, 198, 252, 213, 139, 39, 68, 33, 139, 255, 218, 14, 229, 156, 23, 2, 129, 169, 220, 13, 222, 23, 70, 251, 1, 107, 81, 145, 11, 38, 185, 108, 225, 133, 15, 27, 180, 3, 187, 138, 129, 132, 234, 199, 28, 42, 194, 246, 31, 201, 124, 189, 160, 217, 209, 19, 53, 204, 200, 181, 194, 21, 167, 142, 223, 241, 81, 154, 28, 68, 151, 41, 188, 90, 32, 208, 162, 247, 39, 43, 139, 64, 145, 170, 245, 56, 218, 102, 166, 86, 207, 54, 225, 132, 151, 208, 125, 147, 204, 124, 175, 67, 44, 11, 6, 181, 230, 51, 96, 122, 30, 212, 136, 225, 105, 213, 108, 166, 37, 42, 88, 184, 90, 67, 184, 20, 126, 83, 127, 162, 165, 72, 147, 219, 30, 23, 12, 215, 100, 101, 172, 87, 108, 46, 154, 157, 227, 2, 164, 46, 254, 50, 176, 155, 39, 230, 243, 36, 169, 17, 141, 100, 223, 68, 212, 200, 144, 43, 37, 154, 252, 70, 211, 122, 69, 94, 74, 12, 36, 224, 193, 39, 66, 245, 15, 17, 157, 254, 38, 162, 51, 11, 213, 115, 116, 216, 206, 23, 14, 4, 204, 128, 247, 192, 199, 20, 33, 169, 194, 117, 231, 31, 18, 195, 225, 185, 58, 38, 196, 57, 23, 197, 112, 17, 115, 45, 120, 250, 109, 147, 116, 133, 129, 68, 170, 73, 60, 59, 74, 182, 18, 194, 225, 75, 250, 59, 172, 155, 228, 238, 214, 181, 73, 27, 154, 238, 125, 224, 1, 9, 211, 145, 28, 144, 69, 8, 102, 12, 121, 73, 180, 146, 61, 226, 64, 85, 22, 154, 109, 141, 56, 68, 61, 65, 61, 26, 41, 33, 18, 19, 12, 237, 175, 159, 130, 7, 80, 17, 176, 104, 146, 7, 178, 13, 131, 14, 17, 142, 41, 100, 171, 214, 92, 131, 187, 184, 77, 39, 17, 46, 24, 143, 4, 142, 146, 225, 225, 143, 131, 95, 65, 127, 64, 58, 87, 205, 141, 120, 246, 189, 17, 0, 252, 254, 231, 37, 76, 71, 7, 171, 92, 227, 247, 196, 133, 212, 211, 20, 103, 109, 4, 77, 56, 62, 60, 99, 230, 55, 65, 145, 126, 163, 198, 85, 187, 241, 95, 118, 132, 34, 20, 234, 153, 211, 108, 192, 144, 104, 112, 18, 131, 232, 80, 180, 202, 178, 238, 64, 228, 35, 250, 236, 188, 178, 67, 140, 158, 187, 164, 18, 188, 27, 249, 67, 94, 155, 71, 3, 196, 103, 222, 127, 153, 23, 112, 252, 55, 113, 197, 22, 31, 84, 186, 253, 218, 242, 39, 232, 116, 246, 142, 219, 140, 107, 85, 10, 226, 137, 151, 115, 242, 6, 166, 179, 68, 47, 80, 100, 148, 160, 101, 219, 89, 28, 125, 180, 28, 232, 26, 227, 234, 141, 225, 82, 223, 106, 109, 0, 7, 225, 135, 41, 193, 96, 43, 242, 206, 192, 50, 110, 39, 187, 177, 241, 184, 80, 41, 163, 147, 130, 55, 99, 218, 9, 192, 169, 157, 127, 22, 129, 220, 254, 30, 118, 32, 49, 76, 232, 255, 194, 113, 153, 79, 137, 156, 100, 13, 162, 96, 155, 105, 176, 159, 113, 21, 120, 210, 200, 53, 145, 169, 55, 212, 244, 24, 26, 113, 70, 57, 17, 203, 202, 143, 148, 190, 118, 22, 76, 226, 58, 92, 23, 33, 110, 6, 2, 96, 3, 103, 223, 131, 219, 102, 135, 43, 20, 124, 179, 65, 100, 236, 109, 117, 39, 199, 101, 238, 202, 5, 103, 167, 137, 30, 164, 154, 214, 200, 89, 146, 147, 158, 76, 170, 105, 183, 73, 208, 65, 188, 51, 85, 213, 232, 30, 207, 144, 53, 18, 106, 3, 54, 209, 3, 209, 104, 173, 123, 183, 62, 46, 245, 90, 172, 157, 181, 117, 252, 125, 72, 11, 42, 234, 98, 214, 80, 46, 143, 44, 122, 31, 193, 78, 109, 225, 129, 148, 217, 190, 20, 206, 141, 129, 149, 225, 204, 69, 43, 34, 195, 123, 252, 54, 114, 155, 71, 159, 44, 209, 10, 220, 246, 70, 192, 122, 105, 15, 113, 214, 224, 80, 144, 33, 215, 60, 214, 119, 84, 6, 168, 152, 201, 202, 51, 52, 8, 199, 131, 153, 253, 213, 152, 218, 167, 206, 92, 32, 169, 53, 219, 212, 166, 121, 198, 131, 95, 146, 229, 11, 146, 43, 112, 224, 134, 189, 110, 216, 90, 32, 228, 85, 83, 91, 184, 229, 244, 177, 178, 247, 168, 28, 196, 178, 243, 100, 34, 128, 106, 232, 218, 219, 215, 216, 87, 186, 192, 46, 111, 102, 111, 27, 70, 229, 233, 246, 144, 64, 119, 189, 95, 211, 215, 109, 202, 86, 223, 37, 160, 104, 17, 224, 223, 126, 96, 8, 213, 44, 186, 217, 236, 116, 93, 104, 192, 212, 210, 56, 32, 101, 206, 28, 11, 6, 95, 251, 209, 232, 12, 107, 182, 231, 64, 129, 68, 65, 110, 67, 137, 133, 100, 167, 145, 36, 133, 187, 35, 43, 77, 150, 129, 198, 84, 234, 220, 170, 168, 205, 15, 132, 186, 88, 5, 78, 80, 20, 48, 103, 202, 194, 36, 21, 218, 148, 212, 103, 64, 118, 46, 214, 32, 18, 36, 93, 129, 50, 177, 201, 176, 0, 137, 192, 55, 156, 172, 226, 87, 45, 63, 240, 88, 65, 12, 121, 22, 124, 22, 8, 87, 182, 161, 180, 87, 215, 226, 144, 190, 229, 12, 123, 62, 249, 14, 177, 133, 196, 193, 37, 50, 161, 83, 156, 233, 128, 162, 167, 26, 114, 112, 95, 252, 115, 64, 243, 140, 176, 41, 220, 155, 105, 105, 47, 7, 118, 96, 244, 98, 67, 34, 145, 166, 175, 166, 231, 195, 3, 194, 35, 243, 59, 68, 24, 245, 166, 161, 234, 14, 121, 172, 1, 142, 157, 105, 246, 173, 212, 14, 11, 184, 212, 187, 133, 142, 122, 190, 165, 233, 148, 156, 126, 191, 58, 64, 91, 71, 124, 199, 40, 132, 191, 166, 93, 53, 135, 147, 224, 134, 4, 20, 135, 64, 17, 247, 11, 19, 251, 206, 75, 177, 68, 106, 131, 38, 176, 194, 169, 197, 84, 103, 75, 112, 0, 51, 34, 166, 130, 115, 183, 220, 190, 6, 169, 201, 164, 56, 14, 122, 13, 142, 166, 131, 99, 94, 57, 217, 200, 251, 86, 46, 76, 93, 20, 168, 73, 52, 72, 50, 245, 4, 60, 193, 6, 25, 120, 74, 75, 17, 229, 222, 218, 25, 28, 20, 137, 21, 127, 76, 244, 98, 205, 135, 86, 127, 151, 248, 147, 16, 168, 178, 135, 3, 192, 138, 57, 139, 1, 249, 9, 63, 12, 119, 83, 83, 3, 230, 194, 141, 249, 235, 246, 35, 92, 165, 94, 55, 251, 52, 177, 251, 236, 227, 34, 124, 60, 222, 117, 76, 167, 190, 192, 56, 200, 62, 51, 136, 114, 206, 70, 16, 187, 107, 140, 105, 142, 9, 251, 53, 236, 30, 143, 236, 169, 96, 196, 90, 0, 228, 52, 33, 88, 67, 112, 54, 27, 42, 212, 164, 241, 163, 186, 217, 107, 197, 47, 78, 21, 49, 98, 176, 227, 144, 237, 110, 43, 57, 243, 112, 97, 59, 58, 48, 174, 84, 193, 103, 140, 45, 254, 226, 179, 79, 90, 27, 16, 208, 62, 222, 107, 22, 56, 4, 219, 67, 42, 194, 142, 113, 162, 162, 224, 178, 115, 245, 128, 221, 194, 5, 13, 52, 108, 95, 54, 12, 227, 37, 130, 184, 38, 14, 136, 34, 28, 43, 132, 25, 126, 69, 79, 113, 70, 14, 153, 45, 3, 82, 233, 253, 19, 198, 26, 233, 213, 133, 180, 152, 217, 146, 2, 147, 15, 102, 45, 80, 119, 254, 163, 196, 113, 161, 125, 79, 207, 185, 88, 144, 72, 233, 21, 6, 125, 231, 23, 8, 151, 51, 152, 154, 119, 37, 130, 196, 194, 200, 151, 24, 223, 184, 25, 215, 215, 225, 224, 8, 73, 73, 244, 233, 117, 209, 217, 212, 21, 239, 114, 161, 138, 250, 248, 240, 190, 225, 219, 52, 191, 58, 232, 218, 126, 243, 50, 29, 232, 161, 156, 192, 60, 97, 177, 23, 4, 77, 58, 148, 232, 42, 140, 80, 224, 105, 9, 182, 101, 20, 14, 148, 138, 81, 64, 129, 70, 78, 236, 132, 67, 48, 227, 194, 13, 247, 154, 169, 100, 127, 12, 231, 143, 88, 23, 192, 63, 251, 4, 111, 236, 137, 71, 122, 240, 209, 166, 184, 132, 186, 10, 138, 42, 194, 197, 48, 243, 206, 219, 207, 53, 145, 24, 100, 247, 116, 128, 99, 12, 17, 173, 79, 74, 230, 170, 65, 229, 22, 108, 137, 218, 250, 133, 160, 193, 190, 195, 202, 160, 182, 236, 119, 222, 197, 25, 89, 59, 7, 59, 224, 228, 72, 91, 187, 76, 38, 156, 224, 171, 39, 35, 234, 206, 56, 34, 148, 9, 25, 224, 28, 15, 27, 35, 122, 206, 90, 66, 46, 184, 212, 69, 176, 93, 153, 12, 68, 44, 132, 116, 115, 132, 127, 77, 128, 248, 94, 123, 214, 86, 25, 86, 47, 40, 31, 180, 110, 35, 71, 78, 85, 178, 19, 28, 237, 133, 16, 183, 58, 220, 96, 117, 171, 40, 50, 59, 229, 39, 28, 162, 217, 224, 32, 50, 42, 9, 70, 69, 201, 114, 164, 18, 80, 139, 255, 12, 245, 214, 198, 186, 114, 109, 51, 40, 154, 173, 3, 56, 42, 252, 194, 21, 152, 99, 162, 139, 72, 74, 98, 10, 125, 57, 135, 125, 139, 184, 107, 91, 35, 105, 149, 170, 103, 45, 255, 52, 194, 232, 8, 79, 53, 215, 232, 147, 106, 193, 160, 171, 218, 107, 175, 146, 147, 58, 199, 14, 166, 56, 84, 245, 182, 133, 210, 141, 140, 145, 67, 39, 37, 81, 74, 50, 123, 175, 65, 108, 69, 184, 119, 111, 5, 220, 228, 215, 25, 152, 25, 193, 88, 112, 245, 131, 166, 241, 56, 25, 85, 116, 252, 118, 31, 45, 31, 57, 135, 25, 184, 240, 3, 165, 102, 184, 14, 203, 151, 32, 185, 137, 174, 228, 208, 147, 42, 192, 72, 194, 112, 51, 3, 58, 202, 143, 171, 116, 63, 28, 200, 1, 21, 28, 132, 83, 66, 47, 117, 147, 113, 37, 106, 80, 118, 217, 100, 229, 126, 182, 183, 183, 81, 65, 33, 181, 235, 223, 130, 118, 54, 177, 90, 10, 187, 200, 6, 102, 189, 93, 76, 254, 55, 69, 103, 130, 201, 57, 98, 207, 5, 152, 231, 64, 101, 0, 222, 78, 244, 13, 38, 248, 63, 163, 31, 175, 155, 203, 77, 249, 24, 139, 52, 224, 68, 199, 157, 103, 40, 131, 224, 242, 137, 225, 181, 131, 29, 128, 229, 242, 92, 42, 58, 85, 101, 69, 120, 167, 86, 99, 57, 220, 94, 231, 162, 99, 132, 221, 55, 37, 174, 194, 195, 194, 178, 232, 61, 38, 66, 42, 168, 182, 23, 106, 241, 198, 192, 217, 215, 50, 59, 225, 217, 8, 24, 147, 240, 54, 209, 158, 154, 47, 7, 212, 225, 38, 19, 4, 241, 170, 42, 2, 107, 13, 240, 77, 158, 228, 103, 237, 64, 173, 177, 143, 48, 208, 217, 140, 31, 108, 229, 140, 70, 10, 51, 122, 64, 75, 12, 145, 211, 165, 169, 145, 240, 228, 255, 115, 84, 244, 84, 125, 231, 86, 8, 52, 248, 112, 145, 221, 45, 53, 9, 92, 53, 66, 180, 172, 242, 22, 113, 106, 211, 138, 42, 63, 66, 178, 2, 160, 86, 191, 169, 237, 86, 87, 70, 78, 62, 1, 213, 97, 167, 104, 63, 60, 222, 61, 77, 55, 70, 198, 23, 8, 135, 250, 188, 93, 66, 134, 227, 192, 20, 182, 81, 129, 108, 60, 88, 141, 93, 205, 132, 52, 179, 95, 168, 181, 39, 38, 7, 206, 107, 214, 181, 101, 190, 56, 89, 60, 178, 166, 107, 99, 154, 3, 129, 39, 242, 99, 206, 124, 171, 178, 132, 138, 177, 200, 26, 11, 83, 208, 126, 142, 130, 38, 169, 82, 225, 242, 213, 101, 234, 176, 14, 229, 79, 19, 58, 72, 4, 201, 238, 77, 94, 151, 153, 10, 128, 254, 183, 134, 62, 42, 170, 39, 226, 231, 213, 223, 31, 74, 61, 94, 199, 136, 181, 153, 45, 48, 157, 50, 0, 60, 251, 155, 235, 37, 42, 168, 203, 8, 246, 116, 56, 66, 99, 34, 92, 170, 73, 29, 32, 185, 65, 23, 178, 124, 2, 254, 140, 196, 162, 33, 208, 190, 145, 237, 96, 137, 104, 94, 114, 2, 37, 83, 2, 59, 241, 115, 1, 208, 157, 193, 165, 118, 17, 156, 91, 135, 158, 192, 108, 229, 212, 236, 9, 28, 232, 75, 152, 109, 156, 152, 207, 180, 242, 34, 100, 12, 112, 243, 72, 166, 219, 31, 150, 89, 73, 243, 4, 219, 157, 46, 75, 247, 234, 143, 10, 88, 150, 67, 124, 219, 10, 6, 26, 15, 78, 177, 77, 114, 221, 121, 214, 54, 107, 254, 196, 239, 216, 168, 230, 230, 28, 94, 69, 11, 67, 161, 37, 39, 191, 18, 246, 116, 211, 14, 236, 250, 100, 23, 87, 174, 118, 164, 193, 229, 87, 38, 151, 122, 79, 217, 111, 231, 135, 82, 222, 183, 14, 208, 217, 233, 1, 121, 21, 121, 251, 162, 112, 186, 24, 65, 154, 7, 50, 186, 246, 24, 173, 198, 186, 89, 38, 117, 87, 26, 10, 94, 50, 193, 16, 135, 68, 167, 148, 251, 144, 115, 60, 48, 28, 187, 104, 161, 255, 192, 223, 214, 21, 143, 212, 214, 194, 44, 128, 162, 174, 96, 166, 91, 17, 247, 83, 230, 57, 106, 16, 104, 142, 57, 78, 235, 132, 164, 183, 174, 244, 56, 103, 113, 118, 96, 65, 40, 163, 7, 30, 134, 159, 76, 247, 31, 213, 30, 211, 203, 74, 188, 201, 38, 148, 123, 234, 157, 17, 192, 247, 26, 71, 201, 37, 226, 94, 89, 80, 180, 133, 94, 22, 94, 64, 39, 236, 227, 143, 163, 140, 126, 160, 125, 29, 99, 25, 56, 107, 89, 224, 93, 213, 48, 6, 174, 250, 127, 228, 165, 247, 193, 169, 53, 114, 176, 103, 191, 116, 118, 23, 97, 219, 73, 32, 245, 48, 81, 200, 42, 64, 190, 25, 126, 59, 198, 254, 136, 198, 30, 154, 159, 115, 133, 150, 85, 84, 81, 198, 220, 150, 67, 242, 28, 203, 189, 175, 18, 152, 74, 40, 37, 157, 101, 110, 50, 144, 94, 53, 103, 188, 60, 29, 26, 46, 38, 83, 193, 5, 41, 184, 184, 43, 65, 187, 143, 212, 123, 83, 233, 166, 99, 246, 45, 86, 5, 154, 252, 76, 189, 21, 225, 45, 46, 102, 104, 8, 225, 163, 7, 24, 22, 178, 179, 22, 211, 176, 8, 21, 171, 190, 105, 171, 201, 153, 254, 143, 184, 143, 79, 44, 99, 68, 83, 14, 221, 163, 40, 137, 30, 178, 150, 183, 168, 122, 148, 165, 126, 56, 195, 175, 162, 202, 69, 219, 175, 193, 166, 186, 252, 212, 135, 62, 240, 153, 66, 35, 240, 111, 129, 19, 45, 140, 227, 201, 185, 173, 12, 198, 97, 228, 10, 41, 101, 107, 165, 106, 140, 26, 165, 166, 212, 16, 53, 231, 73, 16, 53, 1, 76, 73, 68, 160, 75, 156, 36, 124, 36, 235, 158, 89, 98, 139, 130, 113, 19, 7, 232, 95, 112, 121, 125, 246, 130, 143, 5, 190, 216, 150, 246, 149, 254, 80, 102, 35, 174, 82, 169, 90, 189, 234, 242, 87, 91, 255, 78, 98, 197, 208, 42, 141, 31, 17, 233, 217, 151, 135, 31, 87, 71, 132, 255, 79, 98, 62, 168, 221, 172, 247, 225, 46, 155, 228, 196, 76, 95, 161, 68, 233, 203, 192, 236, 146, 149, 43, 85, 98, 110, 35, 242, 116, 216, 226, 78, 157, 114, 40, 157, 241, 33, 12, 14, 205, 192, 201, 12, 219, 255, 249, 6, 105, 86, 80, 101, 184, 26, 56, 101, 227, 25, 69, 140, 68, 35, 245, 46, 110, 221, 50, 51, 237, 20, 23, 174, 4, 137, 44, 207, 0, 201, 52, 147, 202, 111, 190, 72, 177, 228, 97, 210, 163, 150, 154, 2, 241, 97, 151, 93, 210, 199, 127, 218, 57, 45, 91, 96, 194, 160, 131, 205, 120, 102, 209, 51, 28, 68, 48, 199, 130, 77, 209, 13, 204, 141, 240, 217, 165, 87, 56, 119, 167, 53, 207, 74, 106, 163, 27, 100, 6, 252, 238, 114, 63, 40, 162, 86, 5, 153, 91, 98, 106, 124, 126, 91, 105, 173, 98, 74, 222, 85, 125, 64, 213, 102, 107, 3, 158, 243, 8, 167, 224, 50, 213, 167, 203, 19, 16, 235, 4, 43, 104, 115, 28, 1, 168, 41, 94, 241, 67, 161, 140, 45, 89, 118, 172, 162, 117, 224, 95, 245, 214, 214, 220, 117, 32, 163, 250, 84, 55, 174, 20, 7, 238, 213, 19, 177, 36, 105, 6, 75, 15, 72, 154, 18, 64, 85, 108, 213, 56, 86, 240, 124, 142, 134, 82, 100, 199, 198, 243, 12, 146, 80, 148, 251, 223, 79, 153, 181, 188, 100, 167, 228, 175, 227, 241, 164, 28, 120, 133, 170, 177, 202, 232, 101, 171, 207, 2, 32, 212, 173, 147, 117, 171, 218, 83, 216, 241, 94, 3, 103, 187, 230, 26, 168, 180, 159, 4, 173, 108, 61, 76, 182, 54, 115, 135, 144, 2, 39, 81, 126, 253, 172, 101, 144, 19, 3, 202, 12, 234, 87, 11, 222, 188, 82, 204, 27, 81, 216, 250, 163, 94, 103, 73, 149, 233, 251, 140, 172, 85, 138, 51, 203, 121, 30, 64, 184, 120, 46, 233, 199, 59, 106, 115, 123, 102, 145, 129, 213, 216, 74, 92, 11, 166, 50, 79, 3, 13, 80, 245, 241, 248, 193, 208, 78, 77, 229, 21, 67, 229, 192, 61, 115, 213, 93, 52, 225, 217, 147, 236, 135, 88, 184, 240, 49, 182, 109, 95, 67, 184, 204, 181, 176, 213, 34, 36, 149, 98, 143, 193, 225, 48, 180, 219, 69, 244, 64, 96, 234, 83, 5, 113, 122, 23, 115, 55, 87, 212, 130, 154, 96, 152, 92, 29, 136, 202, 217, 58, 236, 195, 153, 17, 14, 13, 213, 145, 36, 159, 163, 58, 191, 3, 11, 124, 34, 155, 237, 58, 57, 3, 144, 222, 25, 234, 107, 15, 183, 234, 160, 27, 44, 77, 149, 128, 57, 87, 142, 236, 113, 192, 44, 95, 140, 168, 65, 170, 167, 167, 38, 131, 33, 140, 27, 10, 248, 16, 71, 99, 115, 210, 177, 65, 198, 48, 11, 13, 1, 247, 24, 222, 248, 24, 73, 117, 11, 249, 29, 226, 114, 41, 64, 147, 58, 10, 52, 76, 19, 128, 25, 96, 78, 56, 108, 40, 200, 163, 225, 39, 179, 7, 84, 210, 59, 167, 133, 135, 35, 177, 111, 9, 96, 25, 142, 26, 71, 203, 43, 18, 176, 75, 224, 206, 24, 157, 10, 0, 133, 216, 218, 121, 210, 52, 164, 86, 148, 80, 18, 156, 150, 18, 197, 44, 74, 110, 158, 202, 194, 40, 132, 234, 166, 98, 208, 166, 193, 25, 225, 231, 118, 0, 136, 194, 251, 212, 237, 49, 94, 92, 250, 222, 143, 52, 229, 213, 147, 96, 189, 214, 182, 11, 149, 41, 202, 15, 64, 33, 216, 207, 177, 186, 8, 104, 161, 240, 145, 252, 200, 39, 45, 17, 161, 97, 92, 19, 73, 212, 7, 244, 26, 121, 77, 143, 178, 161, 48, 158, 113, 14, 2, 65, 152, 91, 51, 229, 240, 117, 52, 69, 236, 248, 75, 195, 136, 161, 56, 0, 23, 112, 252, 156, 183, 148, 116, 31, 215, 235, 78, 32, 227, 131, 219, 238, 212, 252, 43, 42, 128, 55, 12, 182, 80, 113, 168, 229, 158, 225, 54, 105, 162, 106, 41, 139, 28, 74, 213, 152, 209, 193, 3, 150, 77, 235, 193, 20, 105, 99, 66, 169, 242, 111, 229, 169, 14, 6, 26, 138, 220, 112, 172, 16, 75, 232, 233, 186, 153, 185, 253, 168, 242, 85, 202, 128, 167, 112, 84, 210, 132, 250, 61, 132, 1, 125, 51, 232, 128, 164, 2, 53, 141, 55, 237, 54, 114, 104, 0, 129, 0, 193, 109, 124, 129, 83, 48, 234, 47, 210, 47, 50, 95, 62, 156, 180, 113, 73, 81, 202, 149, 63, 161, 102, 201, 28, 165, 21, 108, 118, 205, 67, 107, 1, 242, 249, 196, 248, 179, 171, 198, 129, 145, 136, 228, 121, 198, 99, 87, 83, 133, 192, 17, 176, 12, 81, 54, 19, 66, 108, 58, 203, 110, 50, 112, 189, 12, 124, 32, 108, 70, 3, 184, 2, 11, 57, 206, 188, 255, 33, 137, 78, 63, 170, 63, 236, 212, 38, 102, 226, 116, 148, 26, 22, 30, 220, 80, 0, 244, 42, 166, 19, 192, 1, 151, 213, 35, 69, 244, 40, 88, 47, 251, 77, 95, 95, 77, 88, 40, 37, 119, 122, 50, 235, 233, 158, 215, 48, 199, 214, 84, 232, 211, 139, 193, 220, 144, 193, 94, 223, 110, 90, 146, 145, 98, 176, 143, 66, 215, 70, 157, 227, 114, 24, 187, 64, 249, 185, 134, 81, 219, 11, 187, 148, 239, 34, 232, 15, 29, 132, 225, 157, 46, 100, 93, 168, 237, 161, 86, 129, 132, 59, 67, 32, 58, 231, 132, 191, 42, 194, 2, 45, 50, 22, 180, 120, 142, 49, 191, 153, 215, 200, 224, 118, 235, 211, 196, 116, 27, 45, 116, 240, 68, 85, 168, 162, 100, 58, 10, 82, 102, 116, 177, 52, 16, 153, 61, 221, 111, 245, 128, 163, 191, 101, 108, 13, 58, 102, 171, 160, 161, 170, 129, 12, 197, 172, 228, 29, 225, 174, 214, 114, 97, 65, 160, 66, 90, 250, 229, 36, 204, 142, 163, 106, 182, 120, 67, 199, 184, 80, 147, 5, 167, 59, 117, 16, 135, 89, 69, 171, 210, 17, 226, 147, 117, 58, 33, 60, 80, 78, 103, 65, 79, 221, 48, 40, 148, 165, 149, 169, 106, 174, 50, 174, 186, 228, 122, 103, 65, 100, 3, 252, 57, 16, 176, 193, 199, 52, 103, 50, 146, 89, 87, 218, 84, 108, 175, 13, 195, 161, 111, 69, 128, 6, 191, 152, 120, 143, 177, 211, 94, 130, 41, 47, 136, 158, 165, 217, 25, 65, 234, 139, 212, 146, 51, 216, 59, 224, 4, 97, 77, 223, 128, 248, 95, 81, 39, 225, 183, 242, 69, 191, 48, 37, 177, 24, 119, 11, 227, 80, 254, 109, 164, 229, 55, 101, 88, 89, 168, 113, 244, 176, 100, 126, 79, 164, 212, 180, 241, 82, 196, 39, 81, 185, 106, 20, 3, 132, 98, 158, 244, 6, 125, 8, 77, 234, 34, 142, 170, 146, 224, 189, 127, 215, 124, 34, 24, 17, 243, 7, 74, 146, 166, 128, 179, 6, 98, 114, 190, 79, 67, 219, 171, 197, 129, 213, 239, 132, 144, 44, 234, 52, 230, 16, 94, 220, 92, 136, 0, 186, 244, 229, 53, 148, 233, 73, 249, 152, 217, 100, 6, 196, 77, 97, 138, 6, 5, 41, 196, 19, 142, 92, 46, 110, 54, 151, 156, 156, 177, 129, 2, 62, 200, 189, 193, 181, 93, 68, 60, 90, 149, 84, 203, 83, 201, 26, 18, 52, 156, 65, 179, 59, 3, 125, 19, 204, 236, 61, 163, 85, 36, 237, 47, 144, 140, 87, 154, 95, 60, 0, 22, 37, 155, 6, 7, 0, 176, 46, 247, 159, 37, 173, 224, 210, 12, 217, 248, 79, 132, 93, 138, 135, 78, 17, 227, 18, 45, 252, 48, 58, 254, 85, 36, 176, 69, 114, 1, 92, 207, 85, 193, 254, 112, 204, 78, 157, 146, 103, 123, 196, 100, 10, 46, 184, 161, 162, 78, 144, 141, 50, 86, 252, 50, 235, 184, 151, 55, 73, 187, 10, 37, 50, 198, 0, 207, 155, 104, 37, 137, 196, 54, 132, 15, 22, 93, 114, 237, 90, 250, 96, 61, 18, 152, 194, 63, 239, 16, 92, 110, 63, 209, 229, 27, 61, 154, 245, 208, 226, 145, 184, 219, 48, 187, 2, 193, 78, 24, 51, 81, 34, 172, 109, 33, 8, 23, 232, 115, 57, 152, 233, 140, 200, 196, 108, 8, 65, 251, 72, 68, 76, 181, 220, 62, 34, 119, 9, 126, 13, 186, 100, 214, 191, 149, 154, 131, 254, 200, 126, 152, 142, 103, 127, 57, 81, 255, 99, 129, 250, 33, 25, 183, 235, 134, 117, 115, 108, 95, 28, 86, 141, 217, 180, 116, 61, 201, 51, 90, 59, 160, 254, 213, 93, 21, 55, 204, 97, 62, 113, 100, 6, 107, 57, 64, 201, 157, 228, 173, 229, 35, 61, 235, 102, 161, 14, 189, 164, 112, 76, 75, 127, 18, 231, 145, 130, 79, 66, 150, 63, 30, 164, 181, 68, 176, 81, 217, 135, 54, 172, 66, 60, 232, 8, 206, 224, 245, 102, 177, 243, 64, 87, 233, 193, 244, 95, 68, 78, 255, 14, 144, 223, 147, 32, 36, 230, 212, 218, 185, 120, 243, 3, 64, 139, 233, 70, 90, 136, 5, 171, 221, 87, 98, 15, 43, 200, 131, 182, 75, 81, 139, 243, 233, 218, 246, 61, 246, 189, 204, 39, 168, 208, 131, 142, 200, 109, 158, 159, 54, 35, 91, 244, 135, 204, 241, 171, 25, 55, 255, 101, 15, 169, 221, 208, 223, 109, 244, 74, 78, 126, 25, 199, 151, 191, 110, 7, 74, 60, 169, 101, 212, 84, 228, 234, 187, 204, 110, 158, 131, 28, 21, 186, 158, 193, 129, 10, 199, 206, 160, 140, 85, 209, 196, 9, 167, 6, 157, 187, 234, 179, 190, 131, 250, 100, 34, 13, 98, 40, 94, 92, 80, 253, 7, 188, 233, 45, 45, 253, 101, 65, 250, 138, 64, 231, 109, 103, 163, 213, 33, 183, 99, 129, 181, 119, 96, 30, 234, 220, 121, 7, 109, 255, 191, 243, 188, 128, 33, 88, 16, 143, 190, 7, 175, 181, 7, 136, 203, 156, 61, 136, 2, 69, 232, 15, 168, 44, 87, 109, 95, 162, 79, 8, 203, 107, 170, 255, 6, 142, 43, 24, 69, 126, 184, 121, 213, 43, 132, 164, 198, 90, 213, 28, 144, 14, 208, 129, 24, 87, 170, 144, 6, 210, 3, 76, 220, 223, 12, 223, 191, 33, 42, 214, 218, 4, 236, 194, 78, 55, 215, 50, 24, 189, 64, 174, 166, 176, 110, 190, 23, 1, 240, 177, 109, 233, 48, 246, 116, 99, 168, 128, 246, 212, 113, 10, 168, 40, 72, 17, 184, 129, 191, 38, 158, 23, 192, 155, 21, 229, 218, 137, 168, 21, 5, 65, 28, 231, 85, 4, 162, 146, 77, 99, 228, 4, 175, 0, 27, 51, 79, 18, 111, 97, 103, 172, 198, 6, 91, 139, 38, 66, 197, 242, 219, 5, 14, 8, 127, 229, 156, 139, 219, 109, 240, 174, 20, 236, 133, 43, 9, 16, 154, 83, 150, 171, 193, 155, 217, 243, 153, 236, 53, 153, 145, 224, 243, 157, 117, 96, 254, 115, 134, 149, 101, 59, 101, 15, 198, 164, 71, 7, 151, 178, 173, 211, 235, 229, 9, 9, 216, 99, 178, 234, 127, 134, 80, 226, 219, 50, 22, 218, 153, 150, 38, 209, 194, 32, 66, 149, 30, 149, 124, 77, 60, 85, 118, 172, 161, 20, 91, 231, 157, 210, 37, 69, 134, 33, 41, 44, 94, 151, 67, 239, 251, 3, 113, 169, 83, 73, 192, 111, 144, 160, 228, 150, 146, 175, 125, 222, 155, 123, 120, 75, 181, 150, 133, 17, 143, 51, 247, 178, 66, 113, 249, 92, 118, 95, 180, 201, 132, 159, 86, 91, 191, 124, 12, 73, 198, 125, 183, 26, 228, 56, 235, 78, 33, 22, 9, 155, 187, 49, 250, 236, 170, 144, 254, 195, 101, 129, 204, 91, 228, 232, 83, 34, 133, 250, 46, 165, 21, 160, 235, 156, 158, 172, 126, 180, 15, 106, 81, 212, 178, 143, 108, 132, 145, 237, 39, 123, 72, 143, 134, 212, 135, 27, 181, 113, 35, 239, 62, 130, 93, 164, 198, 100, 252, 46, 187, 226, 50, 86, 186, 179, 196, 12, 114, 191, 240, 54, 83, 30, 201, 49, 217, 127, 202, 74, 23, 109, 216, 68, 15, 233, 13, 104, 156, 230, 200, 214, 101, 233, 175, 45, 5, 172, 142, 11, 77, 59, 228, 0, 66, 239, 70, 115, 148, 7, 67, 156, 0, 219, 132, 98, 27, 9, 144, 144, 30, 53, 134, 115, 149, 61, 197, 154, 111, 239, 224, 80, 8, 112, 195, 96, 237, 218, 127, 219, 175, 24, 53, 17, 216, 165, 180, 141, 129, 29, 101, 54, 56, 100, 229, 159, 192, 145, 52, 2, 153, 108, 127, 155, 32, 254, 200, 17, 46, 107, 205, 54, 29, 73, 214, 178, 101, 9, 180, 115, 31, 88, 253, 161, 26, 155, 120, 10, 213, 21, 61, 170, 228, 187, 227, 229, 20, 13, 78, 254, 11, 124, 55, 50, 212, 53, 166, 57, 186, 207, 11, 213, 242, 19, 215, 140, 210, 48, 136, 185, 131, 193, 183, 132, 145, 191, 195, 179, 86, 138, 83, 78, 219, 176, 27, 23, 80, 193, 113, 109, 148, 119, 97, 141, 92, 177, 70, 159, 13, 162, 139, 226, 84, 187, 120, 201, 21, 43, 242, 165, 195, 138, 70, 31, 24, 41, 58, 171, 25, 33, 30, 148, 108, 195, 238, 74, 70, 117, 66, 159, 139, 32, 185, 29, 159, 14, 174, 35, 224, 103, 147, 56, 1, 125, 46, 177, 13, 15, 3, 210, 81, 64, 203, 182, 202, 93, 111, 154, 2, 2, 86, 44, 152, 8, 167, 132, 60, 182, 67, 198, 182, 59, 84, 227, 96, 138, 251, 2, 21, 239, 58, 230, 57, 146, 193, 221, 12, 196, 61, 207, 231, 98, 11, 4, 177, 246, 216, 157, 89, 172, 178, 170, 175, 209, 162, 131, 47, 188, 103, 192, 165, 115, 97, 209, 252, 98, 231, 65, 187, 46, 16, 110, 192, 45, 167, 91, 57, 155, 96, 143, 39, 54, 55, 180, 107, 144, 184, 96, 68, 85, 87, 192, 17, 40, 90, 175, 225, 73, 82, 213, 27, 132, 105, 207, 130, 108, 238, 253, 31, 9, 225, 127, 214, 181, 236, 100, 148, 115, 164, 35, 73, 14, 16, 234, 43, 172, 86, 134, 180, 41, 169, 247, 54, 159, 144, 53, 44, 127, 207, 23, 253, 167, 50, 123, 106, 3, 74, 109, 111, 6, 105, 58, 228, 41, 2, 35, 131, 31, 117, 123, 73, 250, 146, 154, 175, 173, 76, 76, 196, 238, 132, 163, 150, 146, 219, 219, 162, 17, 80, 195, 1, 218, 225, 161, 23, 203, 47, 33, 130, 142, 104, 196, 107, 96, 40, 22, 79, 138, 143, 242, 139, 17, 13, 26, 49, 232, 163, 53, 24, 253, 191, 27, 53, 110, 165, 218, 243, 64, 82, 172, 181, 41, 86, 38, 50, 91, 32, 139, 109, 78, 246, 77, 178, 120, 213, 175, 168, 119, 85, 63, 220, 60, 161, 201, 134, 51, 147, 129, 22, 230, 17, 123, 201, 180, 236, 130, 33, 64, 141, 142, 12, 201, 155, 226, 224, 151, 19, 253, 200, 162, 85, 156, 199, 249, 221, 157, 217, 185, 123, 36, 209, 173, 203, 130, 132, 217, 6, 18, 248, 105, 46, 201, 184, 214, 35, 26, 85, 104, 33, 158, 236, 154, 152, 193, 82, 146, 188, 134, 42, 198, 199, 161, 4, 182, 101, 172, 233, 217, 160, 119, 161, 2, 90, 189, 238, 44, 85, 141, 207, 17, 249, 162, 228, 140, 189, 155, 68, 199, 162, 0, 132, 149, 176, 161, 112, 217, 249, 30, 64, 124, 242, 238, 62, 5, 87, 48, 254, 192, 199, 77, 152, 131, 116, 175, 242, 42, 211, 29, 157, 15, 182, 203, 230, 173, 217, 218, 88, 177, 68, 11, 33, 110, 198, 0, 105, 207, 231, 126, 70, 112, 244, 48, 89, 31, 101, 149, 200, 80, 177, 197, 120, 228, 183, 140, 107, 113, 148, 66, 159, 249, 136, 175, 156, 119, 43, 167, 238, 171, 11, 20, 101, 203, 192, 18, 167, 199, 29, 251, 102, 76, 232, 240, 168, 229, 75, 93, 95, 228, 194, 163, 91, 45, 178, 60, 161, 107, 85, 229, 36, 214, 247, 122, 140, 102, 109, 158, 125, 93, 248, 250, 188, 104, 44, 4, 222, 138, 241, 141, 40, 203, 30, 217, 206, 190, 170, 131, 112, 1, 69, 65, 14, 85, 36, 244, 2, 205, 80, 101, 222, 204, 48, 231, 92, 211, 65, 7, 227, 18, 31, 115, 153, 150, 78, 41, 226, 101, 210, 13, 110, 156, 132, 29, 245, 109, 49, 141, 108, 77, 166, 30, 11, 52, 79, 198, 110, 30, 15, 49, 55, 48, 13, 23, 185, 127, 78, 123, 135, 67, 15, 112, 114, 38, 222, 58, 98, 160, 206, 51, 76, 172, 101, 138, 116, 230, 163, 165, 233, 145, 62, 14, 124, 232, 137, 116, 177, 16, 22, 226, 104, 163, 35, 74, 61, 203, 245, 215, 72, 251, 49, 65, 7, 77, 7, 6, 138, 248, 242, 40, 136, 207, 167, 248, 67, 30, 30, 136, 55, 159, 249, 37, 174, 247, 63, 39, 253, 106, 206, 229, 75, 69, 189, 151, 181, 237, 72, 64, 125, 125, 232, 145, 140, 5, 99, 41, 42, 34, 117, 161, 73, 35, 72, 40, 188, 200, 69, 218, 45, 5, 149, 3, 137, 122, 109, 28, 57, 220, 58, 248, 252, 221, 14, 6, 21, 190, 98, 192, 220, 163, 225, 169, 23, 1, 133, 25, 85, 34, 126, 242, 240, 22, 158, 123, 116, 121, 129, 90, 72, 137, 80, 197, 206, 210, 141, 232, 107, 126, 235, 147, 34, 192, 217, 34, 110, 226, 16, 91, 2, 36, 156, 26, 187, 34, 68, 135, 197, 228, 157, 229, 166, 149, 134, 41, 163, 123, 119, 92, 136, 33, 73, 41, 246, 241, 122, 172, 240, 245, 6, 233, 221, 207, 2, 65, 153, 58, 47, 74, 210, 112, 19, 215, 194, 139, 148, 53, 188, 199, 134, 143, 188, 37, 27, 27, 0, 106, 213, 176, 59, 56, 180, 90, 175, 191, 202, 177, 181, 124, 101, 249, 87, 12, 177, 136, 127, 99, 141, 23, 131, 241, 241, 51, 40, 251, 127, 172, 55, 185, 112, 200, 105, 211, 95, 230, 55, 128, 199, 59, 150, 209, 84, 43, 66, 147, 102, 177, 240, 2, 51, 21, 170, 129, 145, 154, 228, 251, 62, 199, 21, 217, 126, 2, 9, 72, 23, 123, 67, 77, 145, 188, 116, 239, 164, 9, 180, 17, 229, 93, 167, 200, 35, 53, 20, 148, 11, 90, 7, 128, 38, 149, 96, 76, 211, 162, 86, 247, 47, 219, 153, 228, 208, 174, 1, 77, 130, 206, 8, 56, 77, 178, 126, 103, 64, 66, 173, 130, 178, 15, 157, 82, 151, 6, 31, 32, 24, 254, 116, 177, 125, 94, 103, 50, 23, 88, 167, 177, 178, 127, 154, 65, 221, 58, 221, 59, 226, 100, 212, 90, 195, 98, 94, 191, 30, 232, 150, 153, 106, 253, 109, 235, 75, 64, 207, 222, 250, 116, 71, 33, 65, 213, 195, 126, 156, 152, 66, 192, 144, 40, 227, 151, 193, 175, 99, 224, 91, 60, 164, 255, 6, 122, 7, 67, 247, 68, 73, 212, 29, 46, 88, 182, 8, 140, 159, 12, 53, 10, 134, 178, 137, 239, 153, 185, 79, 82, 248, 233, 246, 212, 236, 69, 141, 78, 223, 143, 137, 36, 152, 203, 115, 15, 73, 227, 247, 216, 141, 74, 85, 92, 252, 219, 11, 86, 24, 36, 132, 246, 133, 77, 210, 94, 247, 210, 48, 169, 100, 17, 141, 75, 195, 158, 42, 251, 39, 47, 60, 157, 65, 57, 125, 28, 71, 111, 42, 158, 47, 14, 42, 28, 117, 50, 96, 232, 48, 42, 244, 34, 57, 12, 138, 203, 106, 250, 25, 67, 23, 176, 220, 128, 5, 19, 7, 102, 171, 23, 9, 30, 96, 230, 35, 15, 34, 132, 122, 139, 178, 231, 226, 252, 122, 142, 51, 52, 11, 84, 228, 93, 72, 237, 102, 129, 75, 238, 112, 182, 84, 130, 158, 130, 41, 139, 174, 56, 166, 174, 139, 242, 44, 145, 148, 133, 123, 42, 62, 163, 116, 84, 154, 57, 28, 58, 32, 154, 34, 151, 21, 127, 143, 122, 136, 139, 252, 101, 165, 227, 105, 4, 244, 58, 116, 125, 45, 98, 76, 103, 94, 178, 138, 217, 234, 42, 40, 152, 61, 28, 185, 62, 43, 88, 177, 3, 57, 129, 36, 0, 238, 63, 194, 253, 71, 206, 114, 243, 137, 92, 79, 175, 23, 62, 120, 193, 114, 13, 142, 244, 4, 131, 205, 14, 186, 248, 29, 212, 164, 52, 12, 111, 31, 124, 143, 212, 208, 173, 96, 133, 27, 194, 239, 242, 62, 141, 119, 203, 52, 113, 243, 31, 84, 235, 5, 5, 64, 191, 252, 81, 217, 200, 232, 68, 61, 213, 171, 145, 221, 224, 102, 138, 6, 53, 167, 130, 6, 206, 196, 226, 4, 174, 108, 86, 154, 134, 37, 59, 110, 9, 191, 10, 117, 191, 133, 114, 72, 86, 93, 113, 19, 75, 34, 46, 2, 185, 169, 224, 240, 13, 200, 128, 24, 118, 36, 233, 120, 115, 6, 192, 92, 12, 228, 224, 111, 192, 137, 188, 16, 155, 62, 198, 60, 154, 52, 196, 125, 70, 58, 33, 43, 11, 168, 35, 190, 161, 124, 108, 153, 90, 186, 113, 57, 176, 154, 172, 202, 179, 55, 179, 115, 45, 183, 90, 4, 216, 112, 48, 228, 230, 219, 58, 70, 142, 78, 74, 9, 135, 22, 40, 70, 146, 224, 171, 128, 68, 8, 228, 90, 35, 220, 41, 184, 91, 212, 34, 57, 143, 189, 6, 215, 17, 90, 143, 19, 92, 97, 0, 32, 3, 71, 160, 179, 249, 172, 83, 31, 79, 228, 235, 186, 237, 88, 60, 223, 16, 150, 62, 200, 199, 30, 185, 44, 207, 192, 77, 194, 159, 154, 169, 139, 30, 66, 92, 141, 190, 237, 210, 202, 206, 242, 79, 195, 207, 22, 106, 63, 29, 195, 112, 209, 66, 25, 0, 132, 115, 0, 202, 40, 194, 111, 241, 33, 135, 53, 223, 250, 204, 154, 93, 179, 199, 141, 86, 243, 91, 194, 109, 181, 226, 69, 138, 254, 216, 121, 193, 63, 120, 2, 134, 176, 156, 166, 74, 11, 81, 70, 173, 20, 22, 53, 20, 94, 78, 223, 122, 51, 83, 235, 222, 40, 243, 124, 92, 42, 236, 168, 151, 228, 224, 219, 96, 235, 105, 253, 68, 151, 63, 159, 213, 61, 96, 8, 224, 24, 28, 90, 129, 156, 22, 25, 66, 66, 143, 239, 196, 171, 29, 13, 95, 163, 56, 87, 48, 212, 215, 72, 227, 81, 104, 53, 139, 236, 188, 128, 188, 39, 63, 223, 221, 87, 39, 250, 188, 147, 17, 199, 187, 191, 223, 149, 255, 172, 2, 174, 180, 30, 3, 20, 9, 179, 209, 14, 135, 177, 230, 230, 197, 6, 214, 127, 184, 220, 182, 147, 196, 1, 233, 166, 208, 117, 53, 27, 239, 167, 250, 146, 188, 191, 44, 63, 126, 25, 131, 251, 155, 209, 124, 244, 61, 128, 33, 161, 254, 124, 17, 223, 157, 9, 174, 72, 136, 130, 99, 2, 218, 76, 248, 115, 52, 140, 75, 220, 169, 145, 119, 90, 154, 55, 179, 3, 247, 245, 224, 97, 120, 11, 63, 95, 248, 227, 205, 148, 9, 156, 121, 111, 198, 183, 194, 240, 224, 127, 172, 161, 40, 176, 174, 198, 115, 39, 21, 135, 93, 120, 52, 77, 227, 203, 226, 47, 228, 208, 254, 86, 42, 178, 168, 118, 24, 219, 101, 28, 233, 205, 124, 126, 162, 249, 141, 40, 110, 247, 247, 167, 36, 186, 206, 2, 218, 68, 198, 144, 175, 3, 72, 97, 133, 245, 21, 59, 121, 75, 124, 96, 81, 44, 114, 14, 155, 78, 83, 4, 100, 18, 134, 220, 4, 88, 1, 176, 47, 235, 54, 199, 40, 55, 162, 55, 29, 186, 218, 192, 34, 234, 96, 241, 128, 217, 64, 204, 95, 238, 170, 235, 230, 242, 14, 87, 111, 159, 173, 38, 146, 75, 197, 5, 115, 239, 112, 251, 19, 178, 192, 186, 135, 123, 127, 45, 136, 135, 4, 78, 178, 164, 252, 8, 36, 171, 74, 21, 243, 236, 22, 204, 242, 123, 6, 114, 138, 102, 239, 74, 238, 255, 233, 3, 164, 62, 58, 143, 197, 248, 147, 172, 165, 4, 14, 1, 147, 251, 79, 85, 50, 48, 118, 108, 30, 77, 81, 140, 29, 143, 198, 121, 197, 19, 225, 49, 93, 53, 73, 33, 122, 100, 234, 165, 67, 183, 100, 195, 168, 123, 37, 235, 86, 147, 164, 71, 20, 232, 206, 20, 228, 22, 17, 177, 2, 116, 163, 136, 187, 43, 160, 176, 83, 52, 39, 224, 140, 250, 66, 232, 255, 36, 166, 132, 97, 252, 44, 246, 106, 21, 113, 16, 166, 70, 54, 222, 228, 10, 51, 19, 106, 141, 31, 102, 129, 132, 219, 84, 27, 192, 66, 145, 133, 208, 111, 137, 81, 145, 121, 176, 155, 133, 222, 27, 156, 93, 19, 244, 230, 154, 5, 113, 177, 247, 70, 125, 202, 138, 60, 3, 29, 182, 33, 211, 112, 136, 107, 223, 175, 131, 92, 13, 23, 133, 238, 136, 130, 231, 215, 211, 199, 47, 70, 75, 104, 253, 172, 61, 246, 99, 80, 154, 169, 205, 208, 105, 43, 2, 110, 203, 246, 16, 176, 11, 152, 190, 185, 100, 102, 6, 125, 63, 101, 184, 157, 6, 52, 237, 85, 121, 193, 4, 245, 227, 178, 121, 91, 208, 31, 149, 32, 198, 6, 44, 160, 127, 164, 97, 113, 61, 8, 129, 126, 48, 10, 29, 100, 71, 211, 225, 40, 9, 0, 3, 68, 93, 210, 80, 229, 218, 36, 186, 188, 107, 182, 149, 10, 6, 152, 149, 89, 117, 111, 83, 95, 195, 187, 170, 69, 248, 36, 46, 55, 27, 32, 176, 49, 156, 89, 40, 187, 234, 208, 124, 4, 208, 147, 55, 234, 237, 170, 226, 161, 111, 205, 227, 202, 198, 15, 149, 253, 102, 56, 203, 135, 155, 57, 133, 7, 109, 38, 45, 84, 8, 201, 120, 98, 237, 208, 163, 213, 53, 176, 121, 188, 246, 40, 141, 178, 27, 12, 74, 154, 55, 231, 250, 214, 249, 165, 18, 187, 143, 85, 131, 175, 192, 203, 220, 173, 219, 162, 181, 130, 100, 203, 31, 68, 146, 157, 10, 1, 49, 123, 56, 175, 34, 92, 31, 205, 201, 39, 97, 89, 162, 176, 166, 198, 242, 192, 212, 230, 208, 253, 110, 118, 141, 136, 68, 241, 174, 93, 119, 157, 164, 70, 52, 222, 125, 170, 235, 170, 115, 129, 254, 58, 191, 19, 12, 9, 76, 159, 116, 183, 185, 166, 169, 247, 179, 96, 43, 63, 202, 50, 91, 14, 150, 45, 142, 89, 161, 224, 94, 7, 25, 127, 143, 190, 148, 251, 243, 246, 157, 36, 116, 199, 185, 196, 245, 6, 4, 255, 135, 86, 236, 255, 223, 240, 191, 8, 186, 178, 34, 247, 77, 40, 193, 224, 191, 235, 56, 14, 246, 154, 127, 15, 214, 232, 95, 120, 83, 143, 147, 159, 97, 207, 96, 9, 174, 129, 106, 21, 250, 164, 65, 103, 111, 23, 160, 242, 127, 5, 172, 168, 68, 41, 119, 189, 125, 79, 82, 22, 58, 113, 205, 193, 107, 168, 144, 220, 34, 198, 164, 235, 153, 160, 200, 39, 196, 87, 81, 195, 247, 81, 215, 98, 5, 153, 67, 60, 255, 1, 229, 149, 1, 59, 195, 242, 114, 27, 7, 17, 7, 47, 7, 204, 54, 109, 29, 180, 46, 179, 74, 29, 223, 182, 12, 4, 150, 186, 216, 97, 205, 148, 220, 137, 99, 1, 226, 167, 248, 69, 252, 252, 16, 252, 207, 237, 252, 195, 115, 179, 238, 153, 117, 28, 162, 172, 225, 213, 224, 254, 157, 7, 227, 102, 38, 222, 95, 58, 21, 109, 253, 246, 148, 61, 255, 164, 173, 57, 68, 128, 104, 109, 187, 48, 126, 248, 136, 182, 233, 36, 8, 50, 172, 76, 188, 80, 3, 104, 109, 50, 69, 173, 106, 39, 220, 15, 180, 9, 64, 176, 18, 14, 184, 165, 14, 69, 131, 39, 237, 98, 6, 20, 109, 75, 21, 179, 5, 173, 107, 93, 162, 9, 85, 207, 37, 63, 213, 3, 179, 212, 113, 9, 243, 130, 154, 23, 104, 203, 84, 34, 200, 186, 236, 119, 100, 96, 222, 18, 161, 223, 113, 209, 186, 40, 217, 16, 151, 137, 161, 111, 194, 64, 21, 51, 36, 233, 84, 72, 194, 236, 158, 26, 208, 223, 9, 106, 85, 107, 223, 194, 64, 153, 58, 143, 18, 224, 250, 249, 142, 88, 61, 117, 199, 128, 182, 93, 255, 152, 129, 245, 109, 41, 188, 53, 235, 170, 26, 172, 197, 46, 145, 3, 18, 230, 70, 4, 73, 120, 45, 79, 243, 187, 115, 252, 142, 13, 73, 226, 228, 248, 29, 25, 30, 113, 140, 223, 113, 225, 145, 181, 150, 121, 36, 105, 223, 17, 226, 244, 29, 21, 212, 46, 214, 229, 162, 20, 136, 123, 126, 199, 171, 36, 237, 59, 151, 136, 165, 190, 227, 195, 99, 245, 142, 13, 188, 234, 29, 23, 38, 77, 145, 122, 199, 133, 122, 71, 5, 202, 61, 2, 129, 241, 20, 186, 246, 155, 166, 86, 135, 252, 127, 23, 242, 207, 119, 116, 232, 239, 1, 84, 211, 175, 104, 3, 132, 98, 118, 84, 87, 211, 240, 67, 86, 38, 94, 248, 80, 197, 12, 125, 190, 99, 195, 249, 165, 32, 127, 100, 231, 59, 46, 104, 36, 14, 210, 216, 35, 13, 218, 182, 105, 138, 30, 84, 51, 210, 249, 1, 144, 1, 191, 142, 229, 59, 46, 84, 75, 71, 155, 124, 199, 70, 132, 187, 6, 105, 202, 126, 135, 150, 140, 161, 44, 155, 113, 120, 4, 249, 2, 207, 73, 203, 132, 250, 173, 5, 66, 83, 246, 63, 32, 205, 146, 148, 143, 12, 239, 24, 0, 79, 180, 220, 17, 226, 17, 8, 108, 221, 113, 1, 97, 28, 69, 112, 220, 17, 34, 130, 227, 142, 10, 207, 76, 27, 57, 238, 216, 192, 113, 71, 7, 227, 142, 10, 212, 29, 21, 48, 76, 38, 119, 100, 216, 118, 124, 188, 122, 106, 71, 134, 212, 142, 142, 214, 86, 246, 188, 113, 66, 62, 193, 17, 210, 84, 123, 130, 35, 195, 154, 224, 216, 208, 223, 53, 193, 145, 193, 215, 4, 71, 138, 180, 239, 203, 208, 4, 199, 136, 53, 193, 177, 129, 147, 162, 9, 142, 144, 111, 218, 216, 177, 199, 57, 66, 56, 191, 204, 245, 245, 115, 57, 166, 143, 94, 213, 113, 253, 109, 231, 184, 224, 87, 226, 96, 190, 109, 59, 199, 5, 51, 109, 209, 130, 216, 126, 232, 97, 246, 217, 57, 62, 154, 198, 206, 241, 33, 105, 207, 193, 181, 165, 243, 166, 179, 209, 180, 237, 135, 184, 149, 184, 227, 189, 151, 65, 141, 29, 50, 49, 118, 57, 71, 137, 223, 229, 252, 201, 229, 28, 27, 174, 219, 218, 58, 71, 134, 71, 32, 180, 117, 142, 139, 138, 58, 71, 5, 237, 231, 169, 12, 41, 85, 231, 216, 64, 171, 36, 173, 107, 94, 156, 16, 123, 20, 141, 251, 147, 58, 71, 198, 243, 155, 150, 217, 164, 206, 241, 241, 164, 164, 206, 145, 65, 219, 171, 160, 164, 206, 31, 229, 28, 29, 30, 229, 28, 21, 92, 155, 150, 253, 112, 181, 16, 234, 64, 221, 93, 219, 45, 240, 135, 79, 218, 93, 81, 206, 17, 82, 81, 206, 81, 65, 49, 184, 108, 138, 35, 181, 199, 215, 82, 199, 31, 149, 102, 180, 170, 78, 74, 51, 131, 154, 187, 117, 193, 90, 43, 105, 208, 224, 77, 39, 106, 20, 135, 90, 186, 204, 239, 130, 212, 17, 226, 145, 236, 69, 155, 149, 107, 66, 167, 115, 124, 112, 93, 12, 9, 20, 67, 146, 86, 182, 223, 212, 33, 77, 233, 28, 27, 73, 21, 39, 228, 146, 61, 172, 126, 14, 46, 89, 132, 83, 218, 224, 17, 93, 75, 186, 198, 30, 65, 223, 170, 217, 31, 149, 124, 210, 200, 194, 15, 9, 231, 155, 166, 11, 125, 123, 164, 145, 171, 148, 33, 247, 196, 32, 57, 227, 201, 238, 68, 223, 236, 232, 96, 204, 11, 74, 219, 216, 209, 225, 105, 251, 89, 77, 99, 71, 135, 46, 111, 66, 68, 103, 99, 199, 134, 214, 137, 50, 118, 92, 244, 98, 199, 135, 54, 217, 58, 137, 104, 126, 126, 213, 46, 118, 100, 128, 189, 85, 236, 216, 224, 19, 18, 72, 32, 247, 136, 36, 177, 35, 3, 47, 47, 133, 175, 210, 134, 104, 125, 151, 42, 81, 4, 47, 132, 6, 62, 52, 78, 155, 216, 113, 1, 177, 248, 195, 147, 118, 177, 123, 56, 199, 181, 74, 210, 69, 172, 101, 36, 73, 113, 99, 160, 77, 30, 116, 61, 197, 236, 209, 182, 121, 139, 27, 7, 9, 201, 211, 28, 31, 146, 167, 57, 42, 184, 111, 142, 10, 200, 155, 99, 131, 36, 165, 163, 112, 115, 100, 184, 108, 10, 115, 115, 100, 56, 233, 149, 145, 104, 115, 108, 60, 21, 21, 217, 28, 25, 60, 146, 208, 163, 153, 44, 24, 102, 21, 194, 134, 181, 255, 80, 227, 38, 91, 185, 108, 142, 14, 109, 126, 127, 248, 133, 104, 115, 66, 207, 142, 35, 151, 205, 209, 65, 146, 205, 209, 177, 46, 221, 51, 199, 197, 163, 241, 62, 184, 182, 82, 137, 220, 51, 199, 9, 231, 152, 163, 194, 2, 2, 52, 60, 72, 82, 58, 199, 153, 153, 163, 163, 109, 101, 217, 114, 92, 168, 109, 222, 114, 100, 104, 222, 114, 116, 104, 222, 114, 84, 144, 108, 227, 229, 200, 144, 120, 57, 42, 160, 131, 98, 88, 111, 137, 52, 237, 114, 116, 52, 56, 213, 229, 184, 240, 128, 216, 92, 142, 193, 98, 239, 52, 124, 83, 214, 184, 119, 210, 20, 77, 84, 45, 104, 69, 13, 244, 115, 57, 46, 184, 46, 34, 48, 56, 158, 203, 113, 161, 105, 185, 28, 23, 30, 102, 35, 36, 204, 206, 162, 148, 134, 135, 217, 119, 160, 67, 227, 253, 85, 104, 201, 229, 40, 225, 45, 149, 73, 28, 23, 189, 112, 165, 206, 173, 196, 177, 193, 163, 98, 29, 29, 235, 45, 91, 223, 215, 209, 49, 233, 117, 84, 208, 247, 46, 225, 176, 233, 36, 228, 104, 220, 214, 113, 65, 219, 46, 138, 182, 6, 40, 157, 35, 132, 64, 15, 179, 11, 60, 130, 30, 102, 23, 80, 197, 152, 39, 5, 165, 212, 160, 111, 130, 58, 151, 92, 30, 58, 23, 93, 21, 21, 75, 113, 240, 180, 239, 251, 249, 30, 1, 65, 58, 254, 192, 251, 46, 167, 238, 17, 193, 249, 151, 172, 108, 217, 163, 237, 138, 240, 134, 55, 78, 11, 89, 176, 114, 242, 104, 134, 96, 172, 28, 216, 176, 62, 177, 117, 100, 104, 238, 86, 132, 176, 215, 154, 117, 100, 128, 124, 83, 233, 42, 160, 253, 190, 161, 117, 101, 107, 214, 113, 209, 154, 117, 116, 180, 62, 179, 142, 12, 207, 172, 163, 130, 170, 117, 132, 172, 201, 115, 28, 23, 214, 254, 123, 52, 172, 124, 19, 20, 65, 212, 122, 236, 56, 50, 60, 59, 142, 10, 142, 167, 211, 104, 118, 28, 29, 170, 184, 161, 117, 137, 30, 102, 29, 59, 142, 16, 21, 93, 142, 227, 194, 163, 18, 244, 77, 39, 202, 214, 113, 108, 176, 146, 117, 28, 23, 158, 103, 214, 113, 100, 240, 8, 4, 213, 234, 184, 164, 21, 133, 224, 17, 73, 82, 39, 61, 191, 9, 15, 117, 153, 28, 50, 105, 138, 214, 82, 199, 177, 225, 208, 180, 92, 212, 113, 124, 64, 13, 236, 121, 58, 142, 12, 174, 211, 113, 92, 112, 28, 27, 186, 150, 81, 215, 88, 249, 38, 168, 175, 124, 19, 212, 97, 229, 155, 160, 143, 99, 8, 91, 199, 145, 132, 54, 94, 216, 208, 250, 228, 114, 40, 37, 233, 56, 66, 58, 35, 232, 193, 35, 43, 225, 67, 66, 58, 142, 10, 186, 150, 65, 19, 72, 16, 33, 29, 199, 135, 174, 101, 16, 4, 233, 56, 54, 32, 72, 199, 81, 193, 35, 16, 210, 113, 100, 216, 149, 80, 69, 49, 142, 12, 71, 135, 117, 217, 80, 196, 171, 171, 243, 234, 216, 96, 235, 56, 146, 64, 175, 142, 13, 43, 39, 105, 27, 179, 78, 7, 189, 58, 46, 104, 253, 215, 6, 189, 58, 58, 84, 181, 250, 74, 24, 35, 154, 182, 146, 196, 107, 65, 175, 142, 144, 135, 89, 232, 78, 90, 29, 25, 144, 36, 229, 251, 55, 101, 141, 157, 127, 30, 96, 245, 212, 219, 235, 6, 238, 177, 78, 74, 211, 182, 105, 242, 145, 118, 1, 92, 55, 1, 234, 75, 153, 109, 88, 229, 167, 114, 74, 34, 159, 224, 136, 129, 132, 183, 62, 185, 80, 170, 133, 229, 66, 105, 151, 54, 69, 91, 171, 67, 174, 139, 27, 177, 92, 2, 72, 188, 74, 210, 91, 208, 55, 101, 186, 84, 123, 139, 83, 26, 96, 146, 130, 244, 115, 19, 187, 59, 120, 64, 105, 214, 37, 106, 224, 174, 171, 29, 144, 136, 101, 73, 32, 1, 4, 81, 81, 213, 246, 209, 56, 237, 36, 25, 164, 147, 86, 199, 134, 110, 116, 63, 60, 130, 248, 25, 52, 246, 8, 62, 60, 204, 166, 230, 160, 88, 204, 78, 146, 152, 57, 236, 74, 168, 65, 43, 118, 233, 155, 160, 142, 141, 9, 234, 168, 224, 87, 242, 174, 239, 192, 174, 162, 232, 233, 111, 187, 156, 71, 168, 103, 66, 154, 154, 126, 83, 199, 134, 181, 201, 84, 83, 71, 13, 106, 187, 81, 189, 139, 106, 234, 200, 240, 181, 255, 32, 143, 196, 67, 3, 132, 54, 203, 248, 126, 58, 122, 215, 79, 237, 70, 0, 12, 179, 10, 181, 78, 152, 58, 62, 84, 47, 196, 93, 23, 218, 231, 9, 237, 123, 240, 2, 248, 47, 99, 140, 0, 132, 240, 38, 31, 97, 68, 235, 100, 91, 45, 74, 145, 152, 232, 140, 32, 109, 188, 216, 219, 166, 75, 29, 31, 104, 11, 173, 216, 134, 50, 117, 34, 124, 210, 21, 13, 66, 254, 216, 240, 202, 14, 249, 227, 194, 53, 135, 252, 145, 193, 31, 29, 143, 11, 127, 84, 210, 144, 63, 50, 248, 87, 146, 88, 146, 152, 57, 137, 43, 140, 8, 151, 208, 207, 110, 214, 33, 129, 114, 201, 144, 63, 50, 52, 12, 143, 13, 73, 98, 134, 34, 139, 111, 234, 218, 14, 249, 34, 127, 108, 240, 71, 136, 251, 163, 99, 77, 112, 92, 118, 131, 252, 49, 194, 31, 33, 159, 212, 85, 20, 249, 99, 227, 155, 170, 134, 63, 62, 30, 31, 210, 249, 35, 69, 243, 211, 143, 11, 191, 79, 63, 46, 240, 163, 167, 31, 33, 218, 219, 9, 61, 253, 216, 64, 198, 171, 99, 175, 31, 23, 186, 24, 230, 245, 227, 194, 249, 135, 33, 125, 253, 216, 112, 154, 199, 253, 200, 48, 225, 107, 255, 73, 124, 69, 31, 165, 100, 185, 31, 35, 86, 238, 100, 251, 17, 130, 165, 46, 72, 151, 219, 126, 124, 184, 182, 93, 19, 239, 52, 219, 74, 27, 156, 97, 56, 194, 181, 237, 98, 219, 143, 18, 108, 251, 81, 193, 35, 216, 160, 208, 229, 165, 86, 247, 188, 166, 229, 246, 227, 130, 135, 217, 69, 106, 143, 47, 85, 204, 28, 107, 173, 164, 225, 218, 104, 63, 66, 218, 166, 147, 144, 131, 122, 235, 36, 251, 23, 226, 17, 228, 160, 178, 253, 201, 22, 64, 120, 68, 226, 175, 142, 84, 83, 42, 73, 217, 143, 11, 250, 45, 154, 225, 155, 118, 58, 77, 217, 143, 143, 9, 34, 232, 71, 5, 167, 121, 252, 8, 113, 210, 227, 199, 133, 206, 110, 126, 148, 112, 207, 229, 240, 205, 254, 205, 142, 86, 166, 109, 120, 177, 227, 71, 136, 135, 217, 229, 216, 70, 60, 32, 131, 29, 63, 42, 116, 46, 142, 31, 25, 60, 2, 1, 29, 17, 64, 136, 64, 4, 61, 204, 46, 198, 143, 144, 197, 248, 81, 161, 43, 150, 209, 84, 194, 143, 144, 214, 101, 246, 155, 170, 229, 71, 72, 227, 69, 8, 126, 100, 120, 4, 225, 67, 215, 50, 19, 196, 143, 140, 9, 48, 255, 16, 63, 46, 38, 240, 109, 31, 226, 231, 199, 5, 226, 71, 7, 63, 50, 248, 29, 248, 145, 81, 113, 136, 17, 63, 226, 71, 7, 196, 207, 143, 14, 136, 49, 13, 226, 199, 136, 71, 4, 9, 159, 188, 30, 23, 46, 241, 240, 163, 195, 245, 249, 77, 224, 71, 136, 79, 133, 248, 17, 226, 154, 150, 157, 132, 248, 209, 193, 143, 13, 216, 120, 103, 112, 120, 224, 71, 136, 8, 72, 0, 1, 4, 237, 145, 193, 177, 199, 135, 147, 62, 217, 35, 131, 71, 212, 122, 92, 88, 191, 143, 14, 93, 191, 15, 113, 213, 50, 223, 237, 59, 183, 143, 140, 213, 111, 161, 79, 223, 4, 77, 236, 105, 251, 184, 208, 79, 197, 104, 94, 156, 148, 186, 231, 159, 190, 9, 14, 39, 181, 50, 136, 199, 144, 52, 51, 168, 23, 196, 253, 59, 168, 177, 71, 28, 244, 115, 49, 109, 209, 211, 246, 27, 78, 74, 125, 154, 100, 37, 5, 253, 50, 198, 73, 98, 49, 39, 122, 218, 62, 62, 124, 179, 179, 125, 92, 48, 182, 143, 10, 16, 146, 196, 12, 105, 227, 138, 6, 143, 32, 109, 92, 129, 12, 199, 87, 20, 121, 63, 204, 70, 120, 51, 180, 74, 210, 58, 116, 240, 104, 117, 170, 18, 143, 64, 224, 38, 29, 218, 184, 2, 82, 89, 230, 129, 97, 86, 33, 101, 251, 216, 120, 152, 85, 107, 31, 23, 143, 36, 237, 227, 194, 227, 146, 246, 156, 71, 6, 73, 202, 133, 194, 237, 60, 54, 92, 50, 200, 195, 55, 237, 126, 169, 113, 66, 19, 17, 156, 230, 113, 59, 143, 12, 93, 255, 17, 77, 251, 228, 118, 30, 25, 40, 205, 120, 102, 219, 121, 100, 128, 88, 118, 169, 119, 136, 83, 56, 147, 5, 57, 174, 12, 57, 168, 182, 243, 184, 224, 11, 149, 218, 206, 99, 3, 83, 30, 61, 223, 235, 60, 58, 218, 58, 143, 144, 196, 74, 91, 157, 127, 152, 109, 234, 60, 62, 158, 165, 169, 243, 200, 224, 12, 106, 234, 60, 46, 154, 182, 76, 157, 199, 197, 62, 164, 76, 157, 71, 134, 164, 61, 230, 113, 97, 237, 191, 6, 186, 94, 35, 138, 111, 187, 190, 162, 143, 140, 215, 206, 132, 14, 141, 247, 51, 98, 2, 136, 249, 55, 193, 160, 129, 97, 86, 161, 175, 232, 127, 69, 31, 29, 173, 206, 235, 35, 195, 186, 68, 107, 179, 253, 183, 189, 72, 131, 197, 222, 65, 190, 152, 159, 1, 50, 244, 209, 225, 161, 139, 93, 31, 33, 239, 250, 168, 160, 205, 9, 69, 120, 4, 2, 66, 22, 180, 122, 235, 35, 131, 132, 130, 24, 100, 183, 62, 62, 154, 63, 219, 54, 233, 36, 126, 37, 144, 214, 214, 114, 65, 11, 31, 180, 98, 29, 177, 214, 199, 134, 71, 84, 113, 115, 255, 14, 114, 215, 213, 52, 53, 125, 108, 240, 56, 166, 143, 11, 17, 160, 215, 150, 177, 242, 231, 152, 62, 62, 120, 58, 155, 27, 74, 159, 92, 171, 31, 196, 49, 125, 100, 232, 111, 83, 124, 193, 244, 177, 225, 152, 62, 42, 188, 182, 165, 143, 13, 223, 236, 38, 26, 123, 132, 201, 110, 116, 233, 35, 195, 229, 55, 222, 181, 169, 62, 54, 84, 160, 169, 62, 66, 28, 31, 40, 245, 231, 210, 99, 195, 35, 163, 241, 46, 140, 211, 35, 196, 251, 174, 181, 86, 34, 241, 124, 100, 116, 231, 163, 130, 51, 168, 243, 145, 65, 93, 190, 203, 199, 69, 82, 231, 200, 229, 35, 227, 31, 35, 151, 143, 11, 201, 202, 87, 73, 62, 50, 220, 147, 106, 75, 89, 155, 143, 143, 181, 249, 168, 176, 168, 135, 97, 242, 113, 225, 141, 31, 39, 229, 35, 3, 53, 127, 174, 183, 228, 35, 196, 146, 191, 228, 35, 195, 55, 123, 67, 43, 246, 1, 162, 107, 201, 199, 5, 93, 75, 46, 75, 62, 50, 28, 183, 126, 91, 7, 173, 16, 30, 97, 250, 254, 56, 50, 126, 37, 169, 61, 142, 139, 228, 24, 16, 39, 189, 50, 142, 164, 21, 69, 169, 61, 142, 141, 199, 113, 66, 205, 8, 31, 84, 251, 31, 17, 200, 208, 234, 150, 226, 200, 128, 142, 68, 113, 116, 60, 73, 113, 84, 240, 8, 98, 157, 20, 119, 73, 113, 108, 68, 128, 144, 120, 95, 133, 30, 246, 57, 124, 49, 191, 127, 126, 195, 202, 77, 203, 48, 220, 32, 177, 242, 200, 91, 140, 78, 26, 71, 124, 83, 135, 38, 41, 142, 15, 138, 163, 99, 1, 117, 82, 38, 109, 135, 40, 142, 15, 245, 87, 105, 38, 142, 11, 100, 52, 246, 102, 226, 200, 192, 205, 196, 81, 1, 33, 30, 197, 203, 211, 58, 209, 8, 154, 137, 99, 3, 243, 31, 97, 225, 17, 8, 159, 116, 169, 59, 174, 153, 57, 159, 14, 66, 51, 113, 156, 240, 8, 132, 102, 210, 250, 107, 25, 8, 205, 164, 105, 235, 169, 16, 154, 137, 99, 131, 3, 133, 190, 9, 226, 247, 38, 31, 53, 19, 71, 70, 3, 140, 114, 136, 243, 19, 16, 222, 76, 28, 25, 120, 147, 139, 193, 136, 86, 73, 46, 168, 153, 56, 54, 90, 183, 66, 23, 148, 118, 121, 9, 241, 163, 212, 137, 154, 137, 99, 131, 111, 157, 56, 62, 154, 57, 142, 137, 170, 8, 73, 82, 136, 131, 254, 210, 137, 35, 195, 163, 147, 126, 142, 144, 149, 219, 253, 28, 23, 254, 218, 144, 166, 100, 250, 57, 66, 220, 162, 148, 86, 247, 56, 19, 254, 205, 206, 161, 217, 119, 242, 174, 13, 151, 207, 248, 244, 58, 237, 231, 63, 190, 162, 143, 32, 79, 5, 66, 66, 146, 152, 161, 86, 247, 28, 29, 250, 220, 90, 25, 123, 142, 142, 86, 73, 82, 39, 177, 183, 248, 112, 95, 116, 54, 207, 113, 161, 178, 12, 243, 28, 25, 222, 49, 110, 247, 96, 245, 28, 29, 234, 217, 233, 57, 46, 220, 53, 165, 231, 232, 240, 21, 253, 252, 229, 57, 50, 232, 122, 222, 151, 231, 200, 144, 180, 245, 229, 57, 46, 156, 130, 188, 241, 190, 91, 96, 31, 66, 137, 9, 95, 158, 227, 163, 81, 88, 65, 208, 210, 137, 174, 229, 57, 66, 120, 175, 90, 158, 227, 162, 233, 92, 158, 35, 131, 123, 18, 126, 254, 116, 189, 94, 223, 200, 151, 225, 219, 46, 26, 247, 127, 202, 180, 140, 63, 81, 227, 254, 6, 14, 220, 147, 59, 52, 35, 64, 53, 63, 184, 246, 251, 84, 6, 41, 109, 15, 113, 99, 64, 235, 59, 205, 58, 7, 80, 127, 74, 155, 91, 179, 136, 27, 202, 149, 84, 65, 208, 236, 12, 248, 66, 249, 2, 184, 39, 71, 15, 60, 112, 109, 187, 84, 237, 107, 144, 123, 250, 0, 220, 147, 35, 2, 184, 107, 82, 7, 90, 85, 115, 11, 192, 61, 37, 115, 212, 170, 154, 145, 3, 22, 123, 7, 45, 120, 32, 128, 32, 81, 195, 37, 41, 29, 237, 101, 26, 21, 104, 88, 169, 152, 61, 18, 21, 143, 32, 229, 240, 198, 105, 145, 122, 43, 39, 186, 158, 127, 124, 210, 72, 219, 254, 79, 116, 40, 140, 144, 32, 225, 239, 119, 92, 248, 179, 28, 104, 218, 62, 51, 237, 135, 86, 214, 204, 240, 98, 128, 20, 202, 224, 252, 75, 180, 250, 233, 63, 102, 30, 153, 240, 111, 234, 9, 57, 199, 82, 251, 157, 113, 13, 140, 23, 228, 214, 91, 34, 87, 177, 96, 169, 253, 144, 87, 119, 201, 26, 254, 201, 139, 121, 152, 149, 192, 21, 61, 204, 186, 238, 195, 236, 195, 236, 54, 109, 21, 39, 85, 21, 112, 248, 206, 119, 167, 217, 102, 219, 191, 192, 51, 186, 216, 246, 59, 88, 43, 25, 248, 206, 247, 7, 170, 169, 74, 7, 1, 130, 90, 202, 179, 26, 35, 182, 253, 252, 139, 189, 131, 220, 246, 63, 203, 195, 243, 219, 185, 150, 173, 59, 176, 64, 83, 46, 167, 20, 148, 134, 116, 46, 18, 218, 217, 239, 179, 49, 104, 240, 140, 174, 8, 38, 64, 142, 167, 227, 224, 120, 58, 145, 133, 81, 68, 131, 210, 135, 198, 235, 176, 80, 1, 244, 179, 225, 238, 231, 104, 101, 191, 39, 242, 69, 7, 152, 52, 157, 232, 129, 12, 255, 203, 244, 211, 246, 59, 46, 32, 105, 235, 173, 107, 113, 67, 244, 233, 155, 240, 4, 216, 144, 137, 39, 168, 144, 120, 130, 10, 58, 35, 232, 181, 9, 46, 252, 29, 183, 9, 50, 76, 88, 19, 84, 208, 120, 43, 118, 130, 12, 238, 105, 85, 91, 10, 69, 4, 125, 147, 110, 38, 14, 145, 20, 87, 81, 108, 39, 8, 161, 191, 19, 84, 104, 188, 190, 19, 100, 240, 8, 66, 212, 119, 130, 10, 107, 255, 33, 223, 9, 50, 180, 237, 82, 182, 143, 124, 39, 8, 65, 190, 19, 124, 48, 112, 201, 30, 38, 220, 249, 116, 74, 89, 182, 7, 211, 95, 119, 72, 180, 102, 221, 19, 65, 214, 211, 118, 130, 11, 205, 159, 169, 149, 225, 3, 143, 32, 195, 35, 16, 254, 39, 14, 12, 197, 145, 71, 30, 19, 208, 69, 30, 121, 112, 60, 23, 211, 224, 75, 39, 186, 208, 243, 187, 242, 77, 120, 192, 53, 245, 99, 119, 192, 151, 131, 150, 237, 159, 240, 8, 4, 198, 167, 212, 126, 168, 218, 9, 66, 48, 230, 10, 6, 15, 30, 36, 41, 223, 181, 211, 241, 5, 12, 180, 254, 103, 242, 7, 223, 74, 162, 206, 197, 78, 66, 215, 233, 100, 63, 155, 131, 182, 93, 170, 105, 163, 139, 223, 215, 137, 112, 143, 187, 233, 92, 154, 187, 21, 162, 181, 109, 106, 39, 7, 218, 156, 190, 211, 105, 240, 156, 56, 72, 210, 190, 235, 82, 45, 211, 132, 182, 93, 18, 175, 27, 60, 47, 135, 42, 12, 209, 185, 60, 124, 43, 8, 242, 52, 127, 218, 9, 46, 222, 217, 153, 224, 2, 196, 55, 187, 163, 213, 193, 61, 164, 218, 50, 72, 215, 50, 147, 9, 46, 52, 119, 235, 4, 25, 20, 197, 61, 221, 59, 18, 191, 234, 37, 122, 224, 77, 41, 85, 235, 4, 27, 75, 83, 235, 4, 25, 60, 2, 161, 53, 171, 166, 19, 92, 120, 196, 1, 61, 191, 137, 151, 78, 16, 66, 61, 94, 73, 53, 83, 28, 150, 27, 55, 79, 156, 53, 51, 202, 182, 225, 141, 23, 37, 83, 135, 129, 227, 178, 27, 109, 154, 252, 65, 87, 38, 87, 182, 223, 94, 67, 26, 237, 198, 187, 116, 201, 229, 104, 125, 109, 215, 250, 109, 31, 39, 117, 182, 174, 227, 192, 218, 184, 131, 166, 102, 198, 209, 120, 31, 38, 19, 15, 119, 110, 136, 93, 9, 101, 163, 19, 100, 100, 163, 19, 84, 80, 157, 32, 100, 130, 12, 175, 128, 203, 52, 193, 134, 167, 115, 130, 10, 157, 19, 108, 124, 219, 206, 9, 50, 48, 204, 42, 132, 13, 223, 114, 130, 10, 17, 173, 18, 79, 230, 160, 50, 215, 218, 150, 19, 132, 80, 8, 142, 88, 249, 38, 120, 228, 177, 16, 84, 178, 203, 129, 74, 118, 161, 6, 14, 60, 152, 160, 104, 101, 152, 183, 72, 168, 100, 23, 98, 176, 16, 34, 90, 213, 45, 192, 92, 107, 64, 63, 87, 63, 164, 32, 86, 63, 181, 43, 39, 232, 160, 159, 10, 237, 202, 9, 54, 114, 50, 129, 9, 46, 38, 48, 65, 136, 9, 50, 36, 158, 12, 77, 144, 65, 117, 242, 226, 30, 21, 164, 106, 125, 87, 66, 19, 140, 152, 160, 195, 109, 197, 67, 133, 8, 38, 106, 223, 67, 6, 8, 212, 190, 135, 11, 13, 17, 76, 22, 234, 157, 206, 241, 56, 236, 123, 8, 209, 247, 80, 129, 110, 255, 195, 133, 138, 54, 218, 13, 154, 254, 231, 98, 144, 43, 199, 134, 135, 89, 8, 107, 31, 162, 154, 254, 163, 162, 104, 237, 63, 92, 172, 253, 135, 10, 170, 56, 53, 125, 184, 67, 255, 89, 208, 4, 152, 127, 8, 49, 1, 230, 31, 42, 72, 128, 249, 135, 10, 58, 1, 196, 252, 67, 135, 212, 30, 71, 13, 202, 178, 49, 190, 105, 147, 249, 202, 80, 51, 118, 26, 254, 104, 114, 65, 232, 208, 234, 15, 21, 182, 223, 209, 238, 11, 213, 30, 123, 103, 82, 181, 142, 212, 31, 62, 90, 33, 148, 50, 230, 10, 164, 90, 162, 150, 14, 66, 27, 35, 102, 202, 212, 183, 164, 200, 85, 202, 26, 251, 250, 195, 9, 72, 43, 99, 139, 52, 53, 51, 73, 25, 70, 145, 182, 83, 85, 72, 253, 97, 131, 230, 79, 186, 40, 32, 143, 227, 228, 118, 73, 48, 218, 72, 146, 114, 121, 8, 225, 188, 149, 136, 87, 247, 68, 234, 15, 27, 234, 15, 21, 44, 254, 80, 193, 202, 244, 126, 216, 224, 253, 80, 193, 154, 208, 15, 21, 34, 152, 64, 61, 23, 203, 174, 213, 15, 25, 218, 114, 100, 245, 195, 133, 227, 233, 172, 126, 184, 192, 6, 59, 64, 154, 183, 252, 105, 125, 19, 208, 171, 55, 44, 224, 44, 59, 93, 132, 171, 104, 163, 189, 250, 97, 3, 210, 90, 255, 31, 158, 168, 31, 82, 160, 163, 45, 71, 208, 234, 135, 140, 213, 15, 21, 84, 182, 31, 42, 108, 63, 124, 120, 100, 251, 225, 130, 55, 232, 239, 218, 126, 24, 225, 17, 180, 253, 144, 1, 181, 58, 215, 52, 247, 112, 241, 188, 220, 195, 133, 215, 70, 45, 5, 105, 103, 194, 8, 135, 214, 7, 231, 213, 82, 208, 63, 215, 86, 130, 97, 86, 61, 36, 73, 157, 132, 32, 250, 169, 220, 67, 134, 134, 23, 82, 238, 61, 92, 104, 117, 12, 136, 58, 72, 64, 149, 78, 232, 225, 182, 162, 61, 92, 80, 75, 247, 105, 15, 23, 248, 208, 30, 54, 190, 162, 13, 41, 253, 124, 111, 15, 27, 94, 189, 61, 124, 80, 178, 219, 195, 133, 246, 144, 161, 110, 93, 123, 200, 192, 154, 219, 195, 5, 199, 83, 87, 123, 232, 240, 48, 91, 217, 246, 112, 225, 88, 162, 202, 118, 163, 28, 30, 65, 234, 81, 101, 219, 67, 136, 135, 89, 200, 162, 148, 5, 86, 191, 134, 167, 68, 144, 115, 137, 146, 37, 20, 14, 86, 122, 235, 100, 219, 67, 8, 143, 64, 248, 109, 15, 23, 238, 96, 125, 39, 15, 30, 102, 29, 88, 64, 0, 46, 153, 195, 39, 117, 222, 86, 98, 173, 7, 173, 207, 36, 82, 109, 129, 111, 123, 24, 241, 174, 189, 237, 225, 162, 87, 33, 199, 244, 31, 38, 24, 171, 150, 221, 128, 12, 124, 194, 182, 135, 11, 106, 39, 108, 123, 200, 48, 97, 219, 67, 133, 214, 111, 203, 110, 219, 67, 135, 190, 149, 19, 212, 120, 219, 195, 135, 210, 111, 118, 142, 6, 6, 160, 146, 9, 160, 41, 153, 198, 15, 144, 174, 29, 128, 166, 100, 56, 37, 83, 0, 77, 201, 124, 203, 247, 198, 15, 48, 160, 41, 153, 3, 184, 68, 190, 237, 225, 130, 8, 109, 219, 52, 117, 240, 166, 19, 41, 93, 102, 219, 67, 8, 195, 172, 218, 246, 84, 109, 123, 216, 208, 237, 135, 44, 207, 35, 30, 3, 184, 174, 132, 2, 158, 244, 201, 8, 144, 44, 41, 114, 101, 217, 208, 243, 173, 169, 65, 93, 38, 215, 246, 144, 209, 42, 201, 159, 104, 149, 228, 67, 136, 104, 85, 201, 11, 248, 91, 238, 193, 249, 116, 143, 74, 150, 149, 208, 230, 228, 14, 237, 231, 174, 237, 80, 171, 106, 15, 29, 148, 73, 103, 84, 181, 135, 141, 246, 144, 129, 123, 106, 15, 23, 42, 218, 104, 35, 231, 211, 161, 212, 30, 58, 68, 112, 91, 177, 180, 135, 14, 58, 217, 95, 182, 237, 80, 133, 151, 246, 240, 161, 61, 100, 172, 156, 40, 106, 15, 23, 205, 171, 96, 15, 23, 150, 61, 124, 44, 123, 168, 64, 177, 135, 10, 36, 158, 236, 225, 66, 227, 254, 245, 144, 65, 237, 122, 168, 176, 30, 6, 96, 178, 15, 21, 252, 74, 246, 225, 66, 4, 181, 15, 21, 148, 73, 71, 106, 31, 50, 30, 102, 27, 238, 137, 159, 66, 39, 233, 19, 30, 113, 69, 216, 120, 239, 101, 210, 195, 5, 63, 183, 107, 93, 30, 54, 60, 130, 242, 85, 60, 50, 188, 58, 195, 48, 170, 120, 108, 60, 206, 61, 143, 11, 30, 65, 236, 158, 199, 5, 106, 102, 30, 104, 26, 196, 155, 246, 48, 235, 158, 199, 134, 149, 105, 221, 243, 184, 104, 176, 246, 31, 197, 3, 111, 204, 24, 39, 180, 128, 171, 132, 39, 242, 72, 99, 199, 61, 143, 19, 173, 191, 77, 81, 247, 60, 58, 212, 151, 162, 235, 249, 70, 99, 135, 104, 236, 238, 65, 232, 67, 72, 103, 222, 117, 1, 228, 74, 37, 204, 14, 242, 149, 208, 74, 214, 60, 128, 166, 173, 82, 117, 196, 154, 117, 27, 98, 253, 128, 53, 35, 134, 39, 48, 91, 104, 106, 102, 184, 29, 242, 150, 142, 52, 37, 227, 192, 91, 58, 106, 234, 24, 105, 74, 38, 187, 213, 191, 49, 67, 154, 146, 81, 247, 60, 78, 168, 66, 137, 25, 44, 195, 131, 191, 66, 79, 118, 167, 242, 8, 4, 134, 35, 245, 174, 173, 34, 190, 213, 61, 17, 242, 104, 155, 78, 98, 120, 161, 44, 155, 123, 152, 134, 186, 231, 37, 26, 190, 105, 99, 247, 60, 58, 168, 123, 30, 21, 22, 171, 60, 42, 68, 168, 60, 42, 96, 207, 17, 83, 30, 23, 207, 148, 199, 199, 47, 229, 81, 65, 219, 82, 30, 23, 184, 83, 50, 8, 109, 41, 143, 14, 86, 181, 19, 8, 69, 98, 17, 13, 188, 107, 41, 143, 12, 190, 210, 189, 86, 168, 89, 202, 227, 132, 195, 70, 152, 41, 229, 113, 225, 17, 8, 173, 21, 170, 148, 71, 199, 99, 237, 63, 228, 176, 82, 182, 87, 165, 60, 54, 188, 169, 82, 30, 31, 90, 87, 191, 71, 6, 252, 61, 130, 152, 126, 143, 13, 151, 180, 93, 14, 111, 94, 250, 61, 50, 112, 220, 145, 99, 105, 107, 239, 31, 218, 247, 8, 241, 252, 99, 227, 249, 71, 5, 17, 26, 12, 195, 20, 198, 179, 70, 96, 254, 113, 161, 77, 219, 126, 252, 145, 145, 94, 145, 63, 46, 220, 243, 71, 5, 215, 149, 246, 59, 157, 63, 62, 146, 253, 81, 97, 49, 127, 84, 104, 120, 193, 191, 179, 177, 167, 212, 134, 52, 164, 87, 7, 131, 165, 45, 189, 73, 225, 128, 12, 203, 46, 127, 92, 208, 37, 73, 235, 143, 139, 138, 242, 71, 5, 229, 143, 10, 220, 249, 116, 201, 31, 25, 14, 184, 243, 233, 144, 131, 63, 197, 117, 45, 131, 146, 63, 54, 146, 63, 42, 80, 150, 254, 184, 208, 216, 35, 16, 242, 83, 65, 240, 71, 72, 115, 5, 249, 35, 131, 127, 179, 171, 40, 82, 234, 175, 61, 228, 143, 17, 234, 158, 95, 234, 143, 15, 228, 143, 17, 141, 27, 67, 221, 243, 14, 239, 137, 212, 31, 27, 252, 17, 162, 105, 109, 153, 164, 74, 5, 50, 84, 42, 48, 0, 170, 229, 251, 171, 192, 69, 107, 5, 54, 90, 85, 211, 174, 192, 5, 99, 174, 64, 135, 71, 32, 104, 227, 10, 92, 84, 224, 194, 35, 203, 174, 10, 100, 72, 237, 241, 198, 195, 236, 178, 171, 2, 31, 150, 93, 21, 168, 224, 254, 29, 180, 128, 189, 126, 111, 251, 128, 175, 132, 36, 218, 74, 220, 86, 32, 131, 171, 226, 228, 182, 2, 25, 110, 43, 208, 209, 171, 144, 219, 10, 92, 76, 96, 220, 90, 129, 12, 222, 180, 229, 214, 10, 116, 224, 119, 90, 129, 11, 90, 129, 140, 181, 184, 147, 55, 173, 192, 134, 227, 207, 161, 166, 21, 200, 240, 71, 77, 43, 208, 193, 149, 101, 5, 46, 168, 111, 179, 178, 2, 27, 222, 119, 101, 235, 247, 96, 195, 189, 7, 21, 120, 36, 177, 218, 247, 32, 99, 223, 131, 10, 84, 115, 242, 85, 40, 66, 155, 19, 90, 234, 159, 127, 176, 209, 238, 104, 125, 114, 57, 132, 14, 78, 122, 252, 224, 194, 147, 206, 15, 46, 240, 131, 1, 104, 15, 6, 224, 65, 199, 235, 245, 160, 130, 71, 30, 84, 208, 158, 132, 171, 165, 251, 32, 132, 155, 235, 131, 11, 239, 250, 15, 136, 230, 79, 172, 80, 75, 198, 250, 96, 195, 123, 234, 131, 11, 157, 250, 160, 66, 91, 230, 158, 30, 92, 172, 138, 124, 80, 97, 85, 188, 124, 112, 65, 194, 236, 180, 206, 7, 25, 204, 53, 212, 252, 208, 207, 180, 203, 61, 165, 10, 162, 117, 62, 248, 160, 61, 7, 136, 47, 252, 203, 198, 77, 231, 131, 141, 197, 236, 242, 65, 6, 143, 160, 202, 99, 249, 32, 163, 85, 37, 63, 190, 237, 106, 120, 100, 209, 152, 132, 22, 203, 135, 241, 251, 75, 136, 129, 126, 79, 180, 88, 62, 248, 192, 242, 65, 5, 15, 46, 210, 202, 7, 21, 158, 36, 31, 84, 216, 215, 124, 112, 161, 241, 230, 131, 143, 54, 1, 8, 30, 84, 64, 15, 62, 252, 193, 199, 162, 176, 225, 17, 199, 211, 169, 84, 144, 177, 48, 147, 10, 42, 32, 164, 130, 13, 137, 95, 6, 177, 214, 175, 224, 3, 107, 253, 10, 46, 184, 123, 5, 31, 238, 21, 84, 224, 17, 8, 206, 167, 67, 206, 167, 171, 84, 112, 33, 185, 94, 172, 130, 12, 203, 29, 185, 127, 103, 177, 10, 74, 104, 59, 114, 176, 196, 106, 177, 10, 50, 44, 86, 193, 134, 119, 58, 105, 177, 10, 50, 22, 171, 68, 88, 172, 194, 82, 251, 181, 185, 130, 42, 184, 192, 85, 113, 163, 153, 85, 80, 194, 35, 104, 177, 10, 50, 176, 10, 54, 240, 187, 167, 19, 90, 172, 130, 142, 183, 160, 197, 42, 8, 177, 88, 5, 21, 248, 170, 60, 199, 14, 85, 124, 85, 176, 161, 226, 171, 130, 10, 30, 241, 85, 193, 5, 134, 217, 85, 193, 133, 8, 237, 84, 80, 161, 157, 10, 62, 36, 137, 25, 106, 167, 130, 140, 118, 42, 168, 64, 21, 55, 196, 173, 21, 108, 44, 85, 65, 5, 189, 202, 241, 236, 71, 141, 170, 32, 164, 87, 169, 231, 130, 26, 85, 193, 135, 126, 170, 74, 165, 130, 11, 30, 137, 80, 65, 133, 9, 36, 136, 80, 65, 133, 231, 118, 200, 189, 130, 42, 157, 28, 61, 217, 168, 130, 13, 141, 247, 83, 123, 76, 131, 47, 170, 160, 195, 35, 13, 91, 84, 193, 6, 93, 75, 254, 42, 69, 21, 116, 60, 21, 21, 143, 130, 11, 19, 64, 204, 83, 112, 193, 41, 24, 128, 197, 242, 89, 44, 31, 72, 35, 113, 232, 161, 177, 71, 28, 107, 25, 244, 64, 127, 155, 130, 11, 78, 122, 109, 10, 50, 56, 169, 105, 83, 144, 65, 215, 190, 203, 166, 32, 131, 129, 194, 197, 226, 160, 39, 101, 163, 107, 0, 217, 20, 108, 180, 174, 166, 101, 83, 144, 177, 46, 29, 133, 130, 12, 201, 53, 106, 117, 52, 176, 78, 6, 181, 82, 88, 181, 117, 160, 56, 156, 165, 74, 52, 109, 255, 177, 186, 77, 250, 224, 12, 154, 182, 78, 202, 164, 237, 156, 3, 9, 109, 134, 52, 181, 228, 2, 235, 42, 170, 214, 190, 6, 7, 239, 153, 84, 114, 63, 144, 218, 227, 72, 181, 199, 221, 72, 82, 46, 168, 194, 139, 164, 153, 130, 13, 60, 226, 178, 41, 46, 155, 162, 154, 41, 200, 112, 217, 148, 134, 106, 166, 160, 35, 37, 141, 41, 184, 32, 129, 9, 60, 204, 98, 10, 82, 44, 236, 53, 10, 46, 84, 36, 20, 84, 192, 40, 199, 191, 216, 59, 18, 74, 83, 199, 14, 206, 47, 5, 27, 36, 212, 73, 153, 212, 45, 5, 31, 34, 26, 94, 254, 248, 55, 59, 1, 172, 205, 254, 86, 151, 110, 81, 220, 52, 102, 15, 188, 21, 14, 142, 231, 59, 132, 100, 189, 5, 61, 171, 105, 120, 77, 164, 125, 207, 165, 11, 116, 45, 131, 208, 179, 54, 213, 3, 39, 125, 82, 212, 227, 149, 144, 68, 227, 247, 7, 95, 204, 143, 212, 196, 83, 225, 118, 200, 217, 61, 88, 201, 16, 188, 16, 133, 85, 91, 10, 50, 104, 233, 164, 182, 20, 92, 244, 127, 182, 165, 224, 66, 61, 117, 105, 163, 182, 20, 124, 72, 154, 25, 212, 150, 130, 12, 181, 150, 130, 14, 181, 150, 130, 15, 102, 41, 168, 64, 155, 90, 10, 62, 190, 181, 45, 106, 210, 82, 208, 209, 180, 109, 237, 53, 90, 244, 56, 20, 156, 120, 178, 59, 35, 188, 189, 70, 13, 204, 49, 116, 61, 197, 12, 162, 238, 121, 212, 246, 215, 62, 9, 165, 21, 94, 208, 2, 39, 173, 67, 193, 133, 87, 135, 130, 143, 71, 165, 54, 98, 172, 80, 83, 135, 130, 14, 77, 29, 10, 42, 44, 85, 135, 130, 11, 104, 129, 213, 207, 161, 238, 121, 101, 203, 156, 244, 202, 64, 26, 202, 167, 67, 193, 7, 231, 27, 210, 161, 160, 35, 130, 9, 120, 67, 193, 5, 165, 19, 110, 199, 22, 189, 54, 20, 108, 120, 109, 40, 168, 128, 13, 71, 107, 181, 85, 10, 50, 124, 231, 187, 68, 149, 130, 13, 137, 230, 135, 89, 73, 74, 202, 162, 20, 116, 172, 9, 190, 40, 5, 25, 36, 64, 240, 80, 202, 178, 25, 4, 129, 141, 244, 173, 77, 107, 231, 226, 120, 248, 138, 182, 7, 232, 233, 215, 22, 128, 196, 87, 177, 108, 212, 252, 153, 252, 49, 11, 175, 108, 173, 175, 77, 43, 115, 60, 29, 36, 129, 98, 16, 13, 175, 199, 194, 171, 65, 223, 236, 216, 46, 240, 236, 176, 227, 159, 172, 185, 129, 75, 218, 115, 18, 114, 252, 45, 6, 73, 82, 186, 237, 111, 138, 158, 213, 184, 178, 204, 3, 18, 19, 101, 128, 156, 234, 131, 136, 207, 212, 120, 193, 62, 218, 166, 147, 26, 90, 151, 106, 90, 177, 222, 64, 171, 90, 219, 100, 243, 230, 45, 239, 202, 108, 75, 134, 252, 213, 189, 129, 59, 224, 194, 27, 175, 47, 181, 139, 82, 80, 98, 53, 139, 82, 36, 190, 49, 179, 40, 5, 27, 22, 165, 224, 2, 222, 71, 196, 162, 20, 92, 96, 146, 106, 81, 10, 50, 104, 115, 66, 252, 238, 233, 180, 40, 101, 81, 10, 46, 180, 109, 211, 36, 44, 74, 65, 10, 239, 69, 41, 72, 225, 154, 210, 45, 74, 65, 135, 175, 44, 22, 165, 32, 100, 81, 10, 50, 240, 8, 242, 198, 187, 40, 5, 35, 42, 234, 82, 41, 144, 100, 146, 84, 10, 66, 188, 94, 72, 146, 74, 65, 135, 212, 158, 198, 0, 210, 73, 204, 34, 18, 154, 214, 41, 3, 7, 90, 63, 98, 162, 1, 175, 162, 32, 133, 162, 96, 0, 222, 179, 201, 68, 193, 6, 255, 182, 236, 158, 164, 96, 163, 105, 249, 36, 133, 233, 231, 58, 73, 10, 54, 168, 199, 188, 116, 162, 10, 53, 246, 79, 10, 50, 240, 181, 255, 30, 146, 169, 147, 28, 34, 183, 245, 183, 19, 146, 208, 182, 171, 245, 147, 130, 141, 8, 19, 146, 148, 174, 241, 48, 235, 164, 79, 10, 46, 160, 131, 118, 82, 80, 161, 105, 73, 65, 135, 171, 100, 37, 5, 25, 122, 149, 100, 37, 5, 23, 206, 167, 67, 238, 65, 36, 41, 23, 36, 89, 73, 193, 134, 100, 37, 5, 21, 26, 163, 223, 164, 224, 98, 177, 10, 74, 18, 40, 24, 161, 44, 219, 163, 18, 148, 36, 80, 240, 177, 240, 90, 80, 146, 64, 65, 70, 99, 143, 32, 10, 50, 84, 42, 19, 84, 224, 21, 125, 19, 84, 209, 55, 153, 112, 181, 116, 25, 228, 146, 61, 184, 231, 74, 168, 162, 111, 130, 14, 7, 92, 100, 235, 155, 224, 66, 3, 238, 218, 78, 223, 4, 25, 250, 38, 216, 80, 7, 143, 56, 233, 113, 4, 3, 119, 201, 32, 28, 18, 65, 146, 214, 233, 167, 66, 17, 52, 37, 138, 160, 111, 130, 15, 173, 43, 223, 247, 78, 146, 255, 162, 31, 255, 42, 125, 79, 254, 199, 227, 220, 190, 3, 145, 0, 130, 8, 68, 112, 109, 160, 23, 44, 253, 8, 105, 155, 137, 67, 107, 235, 210, 113, 180, 114, 19, 75, 60, 42, 249, 102, 167, 181, 85, 53, 109, 254, 181, 184, 147, 35, 125, 147, 201, 126, 210, 94, 69, 241, 248, 54, 243, 109, 55, 225, 34, 160, 198, 187, 191, 94, 190, 50, 164, 47, 45, 122, 186, 177, 39, 115, 60, 21, 47, 71, 171, 199, 65, 79, 69, 174, 198, 255, 111, 65, 30, 161, 88, 169, 152, 33, 143, 52, 19, 215, 223, 182, 76, 91, 138, 79, 217, 95, 81, 212, 38, 0, 193, 182, 9, 64, 176, 140, 38, 191, 209, 213, 48, 55, 13, 116, 45, 249, 72, 49, 55, 218, 180, 178, 149, 15, 190, 41, 107, 178, 25, 214, 204, 60, 154, 54, 137, 213, 50, 85, 250, 169, 60, 2, 193, 143, 190, 61, 214, 149, 48, 59, 154, 23, 55, 20, 51, 85, 172, 56, 130, 195, 179, 26, 163, 135, 39, 41, 41, 73, 187, 82, 68, 2, 30, 102, 95, 223, 132, 129, 54, 210, 245, 32, 192, 193, 174, 5, 30, 249, 78, 231, 241, 38, 8, 225, 127, 15, 74, 255, 57, 198, 9, 165, 246, 184, 4, 175, 197, 206, 225, 105, 255, 89, 217, 18, 233, 155, 96, 3, 179, 56, 244, 19, 100, 208, 55, 217, 126, 14, 2, 232, 39, 251, 138, 254, 67, 243, 156, 175, 230, 248, 138, 126, 1, 22, 63, 240, 77, 119, 165, 5, 201, 117, 99, 143, 56, 48, 192, 222, 97, 224, 233, 87, 166, 75, 31, 185, 39, 164, 138, 147, 79, 112, 1, 77, 62, 65, 5, 215, 245, 186, 39, 184, 192, 41, 60, 65, 5, 125, 250, 38, 32, 10, 79, 176, 225, 12, 162, 240, 4, 25, 86, 186, 230, 9, 50, 168, 229, 73, 137, 145, 168, 100, 171, 73, 227, 131, 196, 233, 68, 30, 6, 57, 144, 67, 202, 49, 165, 142, 202, 6, 147, 17, 40, 210, 3, 97, 44, 20, 137, 2, 73, 21, 133, 15, 20, 0, 3, 14, 64, 173, 25, 205, 76, 19, 164, 76, 169, 170, 13, 64, 16, 0, 4, 109, 75, 111, 237, 120, 170, 176, 201, 1, 78, 65, 242, 207, 98, 231, 248, 155, 37, 98, 142, 118, 116, 122, 6, 69, 240, 26, 157, 196, 61, 207, 229, 171, 211, 118, 68, 198, 142, 40, 103, 168, 102, 48, 188, 43, 26, 45, 249, 235, 140, 168, 165, 124, 54, 255, 142, 34, 25, 28, 15, 15, 7, 51, 179, 7, 109, 171, 165, 175, 67, 121, 9, 25, 190, 128, 198, 47, 71, 166, 61, 171, 12, 194, 125, 81, 62, 133, 61, 176, 25, 172, 66, 207, 46, 240, 250, 136, 21, 95, 93, 21, 109, 2, 45, 170, 136, 127, 78, 167, 63, 71, 118, 198, 110, 67, 39, 244, 24, 31, 119, 14, 61, 110, 109, 68, 17, 154, 243, 229, 149, 199, 135, 120, 58, 46, 81, 50, 71, 174, 122, 85, 31, 36, 158, 218, 166, 121, 26, 120, 230, 52, 172, 117, 155, 193, 237, 43, 141, 84, 148, 247, 191, 123, 49, 197, 218, 15, 73, 29, 124, 250, 198, 47, 7, 129, 50, 172, 194, 193, 55, 97, 35, 146, 73, 103, 73, 25, 137, 248, 242, 119, 10, 222, 11, 114, 8, 161, 29, 217, 2, 31, 195, 156, 139, 31, 144, 19, 49, 77, 243, 250, 250, 158, 29, 91, 131, 133, 11, 173, 87, 119, 15, 209, 216, 4, 111, 201, 119, 204, 170, 12, 229, 220, 185, 218, 97, 208, 149, 132, 246, 107, 162, 130, 91, 222, 97, 123, 201, 73, 22, 157, 3, 139, 213, 122, 136, 16, 211, 171, 145, 253, 126, 175, 213, 63, 36, 80, 40, 74, 46, 229, 152, 185, 30, 29, 213, 127, 236, 167, 160, 71, 141, 178, 173, 45, 2, 4, 65, 100, 96, 16, 109, 18, 223, 179, 37, 88, 62, 97, 198, 128, 89, 31, 28, 171, 155, 67, 234, 24, 166, 229, 210, 1, 36, 125, 123, 33, 32, 159, 235, 21, 154, 114, 49, 161, 209, 38, 248, 131, 160, 239, 52, 206, 165, 78, 153, 191, 179, 16, 42, 160, 128, 112, 38, 251, 192, 90, 206, 130, 88, 119, 70, 252, 18, 19, 179, 240, 5, 100, 198, 75, 115, 52, 66, 150, 128, 138, 172, 98, 221, 8, 158, 17, 246, 14, 141, 120, 235, 229, 96, 229, 38, 166, 254, 35, 123, 81, 186, 64, 22, 66, 16, 101, 234, 75, 141, 194, 154, 204, 160, 33, 197, 1, 164, 244, 196, 56, 52, 1, 230, 17, 165, 50, 203, 106, 231, 107, 255, 71, 126, 255, 83, 70, 32, 14, 208, 139, 229, 226, 138, 222, 163, 27, 134, 240, 219, 246, 188, 154, 62, 151, 167, 106, 0, 111, 96, 182, 220, 50, 223, 221, 34, 135, 240, 83, 156, 114, 29, 53, 107, 46, 148, 169, 111, 250, 153, 57, 135, 197, 216, 102, 163, 127, 53, 245, 203, 58, 142, 97, 151, 166, 77, 26, 90, 165, 113, 133, 3, 211, 169, 168, 233, 135, 37, 226, 23, 139, 175, 179, 198, 136, 20, 22, 109, 224, 185, 222, 51, 2, 77, 1, 21, 91, 58, 141, 1, 254, 39, 222, 220, 161, 150, 232, 214, 206, 133, 116, 175, 101, 131, 104, 229, 86, 114, 173, 94, 26, 84, 77, 121, 235, 211, 159, 120, 165, 227, 125, 45, 11, 6, 120, 215, 203, 97, 132, 167, 107, 114, 2, 63, 167, 80, 100, 118, 8, 168, 20, 10, 88, 130, 247, 36, 104, 167, 86, 49, 242, 147, 141, 55, 121, 206, 224, 73, 188, 54, 218, 224, 30, 234, 52, 66, 117, 125, 196, 8, 206, 95, 111, 5, 137, 155, 199, 14, 204, 128, 209, 175, 40, 9, 170, 39, 57, 63, 34, 25, 41, 144, 20, 52, 191, 143, 140, 47, 200, 15, 254, 180, 209, 74, 88, 18, 237, 88, 104, 188, 136, 146, 188, 32, 113, 74, 111, 82, 169, 247, 76, 73, 222, 208, 129, 181, 51, 131, 210, 3, 142, 9, 254, 221, 46, 51, 186, 85, 24, 193, 137, 43, 2, 177, 133, 141, 182, 235, 30, 173, 240, 78, 104, 184, 120, 239, 75, 106, 178, 243, 105, 169, 57, 11, 252, 172, 139, 247, 36, 4, 3, 60, 142, 188, 214, 138, 149, 137, 212, 43, 30, 208, 251, 181, 41, 81, 153, 107, 139, 70, 60, 202, 192, 178, 31, 69, 153, 26, 178, 170, 5, 27, 159, 164, 135, 6, 75, 231, 231, 210, 179, 22, 92, 107, 192, 110, 86, 174, 53, 125, 52, 210, 243, 11, 243, 206, 53, 185, 58, 34, 50, 117, 222, 30, 26, 97, 122, 209, 129, 141, 246, 76, 101, 208, 79, 111, 243, 217, 105, 178, 227, 88, 219, 40, 54, 211, 46, 12, 238, 22, 201, 176, 24, 246, 117, 145, 177, 7, 158, 173, 6, 203, 30, 67, 205, 203, 18, 44, 171, 177, 238, 84, 167, 123, 168, 52, 65, 199, 170, 77, 117, 50, 201, 0, 42, 105, 27, 193, 91, 60, 152, 238, 83, 218, 246, 151, 33, 138, 16, 172, 65, 228, 30, 38, 200, 137, 214, 31, 140, 12, 227, 197, 164, 80, 251, 215, 153, 59, 87, 118, 248, 74, 117, 152, 44, 112, 169, 155, 66, 63, 219, 82, 190, 113, 213, 217, 15, 80, 28, 133, 75, 234, 156, 56, 109, 240, 28, 229, 19, 244, 25, 106, 11, 28, 210, 191, 115, 178, 226, 128, 7, 130, 213, 90, 188, 33, 63, 184, 31, 99, 153, 36, 128, 28, 123, 36, 197, 40, 166, 51, 83, 234, 195, 42, 92, 172, 162, 110, 231, 8, 171, 250, 65, 99, 198, 137, 235, 224, 73, 81, 207, 4, 250, 204, 78, 72, 102, 82, 141, 85, 202, 92, 226, 36, 230, 22, 137, 67, 234, 142, 136, 96, 14, 83, 162, 53, 9, 7, 165, 66, 241, 199, 74, 141, 188, 63, 253, 107, 148, 2, 248, 65, 138, 123, 227, 220, 48, 249, 213, 32, 2, 252, 42, 190, 107, 99, 205, 110, 239, 3, 119, 218, 246, 52, 167, 46, 50, 232, 66, 164, 80, 68, 64, 194, 41, 8, 0, 25, 216, 162, 206, 222, 137, 107, 149, 114, 205, 198, 16, 67, 146, 212, 141, 181, 149, 247, 252, 14, 66, 173, 223, 125, 254, 126, 152, 34, 75, 107, 91, 204, 195, 185, 206, 199, 232, 6, 226, 128, 104, 142, 209, 160, 21, 238, 81, 44, 113, 3, 230, 250, 236, 161, 142, 124, 40, 106, 132, 206, 233, 89, 99, 100, 226, 246, 177, 31, 127, 158, 221, 200, 67, 35, 143, 140, 9, 22, 99, 102, 143, 127, 120, 255, 225, 234, 103, 88, 205, 128, 128, 156, 166, 127, 60, 20, 180, 231, 246, 237, 66, 13, 97, 121, 166, 188, 236, 4, 62, 227, 174, 89, 64, 34, 176, 95, 159, 49, 41, 137, 69, 199, 48, 188, 93, 219, 103, 140, 33, 11, 199, 65, 241, 100, 133, 160, 3, 18, 26, 119, 136, 229, 38, 129, 136, 121, 34, 168, 144, 85, 241, 96, 72, 29, 93, 16, 4, 136, 97, 53, 59, 183, 36, 44, 141, 140, 136, 131, 91, 74, 19, 4, 207, 189, 0, 227, 93, 81, 151, 91, 67, 216, 122, 118, 153, 22, 246, 242, 231, 69, 102, 95, 173, 97, 72, 66, 136, 12, 217, 206, 79, 140, 24, 11, 79, 251, 209, 203, 35, 198, 121, 231, 229, 6, 214, 88, 132, 224, 126, 255, 176, 129, 36, 204, 94, 130, 235, 86, 226, 14, 197, 149, 44, 136, 165, 139, 195, 229, 180, 195, 241, 164, 112, 219, 37, 62, 195, 245, 100, 77, 180, 229, 144, 60, 222, 135, 160, 63, 106, 78, 34, 17, 216, 152, 173, 81, 27, 1, 44, 232, 36, 81, 104, 58, 47, 32, 100, 164, 211, 188, 125, 238, 219, 179, 131, 97, 199, 137, 25, 205, 162, 200, 145, 197, 38, 220, 24, 102, 152, 150, 158, 43, 234, 238, 66, 49, 90, 131, 174, 97, 219, 26, 117, 38, 36, 82, 247, 130, 156, 205, 161, 248, 80, 56, 181, 70, 137, 146, 17, 103, 30, 168, 35, 99, 3, 7, 215, 81, 169, 118, 55, 162, 131, 132, 124, 156, 193, 241, 85, 147, 187, 47, 54, 51, 125, 20, 241, 20, 2, 41, 229, 62, 1, 73, 240, 126, 190, 178, 71, 69, 141, 94, 180, 131, 67, 102, 8, 233, 80, 73, 0, 137, 161, 142, 175, 0, 181, 86, 206, 144, 205, 103, 78, 53, 100, 139, 158, 99, 187, 111, 238, 109, 201, 241, 130, 246, 174, 163, 51, 123, 115, 225, 33, 255, 12, 41, 84, 69, 209, 109, 151, 96, 244, 151, 3, 201, 255, 96, 125, 221, 123, 239, 163, 182, 138, 138, 211, 200, 82, 228, 110, 239, 131, 44, 191, 123, 159, 156, 94, 133, 218, 142, 212, 20, 204, 53, 39, 71, 138, 197, 147, 130, 27, 240, 124, 116, 113, 175, 215, 58, 106, 133, 224, 9, 122, 175, 33, 23, 20, 105, 244, 166, 1, 167, 118, 19, 156, 50, 192, 195, 128, 104, 11, 14, 245, 88, 3, 174, 184, 169, 6, 74, 156, 128, 16, 68, 121, 198, 229, 50, 42, 176, 176, 144, 44, 60, 112, 243, 55, 105, 196, 184, 102, 91, 98, 202, 57, 77, 55, 3, 38, 102, 130, 51, 111, 14, 71, 16, 118, 208, 180, 36, 59, 37, 237, 59, 13, 253, 193, 65, 175, 92, 79, 64, 11, 31, 18, 22, 69, 86, 156, 188, 165, 63, 50, 105, 49, 18, 243, 114, 12, 222, 78, 3, 228, 175, 206, 231, 72, 59, 227, 42, 144, 198, 225, 19, 67, 27, 120, 192, 164, 5, 65, 42, 224, 33, 69, 218, 64, 176, 6, 217, 104, 169, 68, 229, 218, 167, 153, 63, 26, 41, 17, 202, 243, 12, 158, 44, 126, 84, 25, 123, 196, 72, 197, 135, 197, 101, 122, 191, 150, 226, 170, 135, 18, 107, 234, 63, 237, 94, 236, 227, 111, 120, 82, 193, 182, 52, 206, 104, 46, 234, 81, 23, 88, 116, 248, 108, 48, 1, 48, 224, 78, 162, 208, 197, 208, 223, 130, 202, 206, 60, 16, 56, 168, 240, 8, 236, 142, 216, 107, 200, 76, 111, 113, 208, 32, 13, 125, 137, 223, 163, 172, 14, 38, 32, 22, 177, 74, 204, 99, 133, 115, 241, 136, 232, 253, 159, 254, 10, 251, 114, 134, 179, 0, 161, 120, 211, 89, 35, 171, 183, 203, 244, 93, 1, 68, 226, 185, 162, 79, 90, 158, 189, 50, 138, 140, 213, 157, 193, 44, 153, 98, 228, 165, 31, 125, 231, 218, 227, 247, 27, 144, 177, 87, 202, 76, 177, 177, 53, 109, 142, 205, 233, 240, 33, 1, 99, 37, 93, 6, 131, 91, 90, 96, 193, 79, 93, 148, 73, 192, 197, 20, 52, 223, 108, 236, 179, 19, 132, 66, 186, 56, 102, 179, 253, 89, 73, 2, 235, 83, 198, 40, 96, 44, 102, 146, 46, 169, 83, 199, 47, 246, 150, 46, 109, 108, 22, 254, 126, 150, 9, 178, 41, 89, 64, 250, 213, 59, 79, 1, 244, 241, 234, 115, 98, 254, 65, 255, 57, 170, 52, 107, 66, 220, 186, 201, 89, 168, 10, 172, 179, 35, 64, 249, 77, 10, 247, 2, 18, 172, 205, 249, 222, 139, 12, 100, 170, 19, 227, 128, 16, 6, 114, 119, 238, 186, 239, 137, 248, 167, 92, 234, 55, 185, 107, 53, 153, 93, 155, 192, 110, 179, 205, 8, 153, 194, 237, 243, 203, 164, 98, 16, 217, 19, 56, 31, 248, 92, 68, 233, 200, 21, 182, 81, 250, 9, 20, 50, 144, 187, 251, 15, 112, 203, 42, 187, 23, 72, 60, 64, 191, 61, 86, 64, 158, 58, 196, 8, 154, 174, 30, 134, 63, 47, 75, 34, 37, 64, 70, 28, 71, 45, 126, 101, 5, 53, 224, 55, 131, 48, 193, 101, 47, 134, 186, 42, 33, 139, 111, 155, 224, 118, 149, 39, 113, 5, 115, 233, 10, 234, 171, 166, 229, 119, 156, 46, 142, 251, 136, 104, 141, 89, 204, 70, 186, 163, 201, 194, 100, 91, 202, 104, 186, 138, 59, 146, 178, 205, 30, 65, 180, 84, 252, 209, 3, 104, 240, 87, 70, 186, 159, 42, 177, 146, 202, 224, 12, 212, 201, 213, 153, 210, 57, 210, 248, 98, 254, 29, 32, 97, 185, 161, 108, 163, 129, 30, 7, 194, 181, 208, 198, 166, 212, 199, 224, 41, 38, 39, 135, 165, 0, 170, 159, 11, 89, 254, 21, 62, 205, 234, 106, 0, 34, 211, 99, 251, 21, 19, 96, 2, 87, 230, 112, 58, 22, 118, 90, 88, 169, 121, 193, 135, 88, 231, 199, 126, 92, 130, 166, 96, 54, 94, 15, 242, 32, 154, 89, 104, 68, 205, 96, 62, 26, 208, 50, 54, 157, 233, 33, 81, 119, 9, 160, 106, 227, 212, 41, 212, 67, 184, 103, 48, 192, 238, 84, 165, 216, 147, 210, 115, 111, 204, 27, 228, 166, 65, 203, 22, 59, 95, 190, 99, 11, 75, 78, 247, 225, 101, 151, 132, 170, 49, 180, 158, 246, 37, 201, 39, 123, 135, 220, 27, 11, 167, 112, 80, 230, 106, 222, 6, 247, 225, 31, 194, 71, 200, 131, 231, 45, 90, 156, 154, 232, 167, 170, 177, 237, 227, 119, 28, 55, 228, 236, 238, 39, 217, 50, 119, 196, 118, 58, 251, 215, 242, 158, 99, 185, 144, 92, 100, 54, 70, 46, 55, 75, 34, 7, 229, 14, 230, 142, 197, 187, 70, 205, 184, 84, 165, 174, 106, 88, 14, 34, 61, 31, 182, 23, 253, 12, 162, 15, 75, 97, 250, 12, 121, 46, 20, 228, 134, 253, 99, 234, 77, 215, 60, 79, 136, 31, 237, 138, 29, 140, 41, 23, 161, 248, 114, 31, 204, 57, 68, 251, 57, 129, 254, 238, 80, 121, 3, 36, 131, 95, 224, 238, 82, 171, 251, 120, 36, 54, 132, 51, 252, 54, 51, 224, 92, 147, 71, 59, 163, 0, 220, 235, 240, 63, 9, 64, 53, 216, 243, 45, 197, 172, 8, 128, 90, 142, 111, 253, 211, 246, 132, 135, 69, 238, 108, 176, 0, 27, 170, 29, 128, 185, 79, 0, 28, 20, 203, 187, 210, 42, 103, 117, 37, 146, 173, 238, 50, 71, 89, 168, 56, 153, 195, 240, 73, 243, 54, 132, 77, 86, 4, 67, 144, 18, 43, 22, 201, 42, 47, 112, 148, 26, 36, 248, 106, 102, 149, 109, 22, 239, 49, 125, 40, 207, 63, 170, 109, 250, 137, 124, 138, 162, 59, 181, 59, 104, 92, 84, 204, 41, 243, 11, 238, 140, 251, 124, 96, 34, 103, 205, 15, 103, 28, 31, 135, 135, 169, 109, 156, 15, 146, 88, 56, 32, 145, 202, 98, 26, 220, 183, 103, 206, 155, 153, 12, 229, 242, 159, 2, 27, 76, 236, 62, 111, 155, 67, 193, 137, 153, 4, 113, 139, 114, 34, 3, 174, 131, 14, 248, 85, 206, 93, 53, 27, 60, 145, 134, 206, 139, 234, 95, 197, 100, 141, 251, 244, 126, 224, 138, 66, 147, 145, 126, 144, 176, 161, 253, 52, 211, 112, 130, 203, 246, 230, 28, 196, 111, 224, 187, 29, 169, 176, 54, 64, 148, 77, 105, 80, 11, 172, 27, 133, 66, 74, 239, 14, 248, 40, 15, 40, 51, 180, 174, 93, 198, 216, 116, 169, 66, 249, 86, 118, 41, 141, 203, 30, 46, 196, 104, 50, 116, 140, 148, 22, 236, 95, 123, 212, 133, 132, 226, 136, 121, 83, 160, 218, 8, 155, 241, 141, 216, 16, 103, 212, 72, 246, 184, 233, 174, 42, 10, 148, 249, 214, 70, 76, 108, 133, 117, 170, 234, 183, 183, 58, 174, 67, 204, 100, 227, 57, 44, 236, 152, 74, 15, 225, 72, 92, 196, 93, 40, 1, 68, 53, 254, 128, 78, 178, 93, 193, 234, 133, 86, 160, 31, 139, 64, 123, 190, 94, 76, 221, 66, 83, 115, 217, 144, 195, 72, 109, 213, 158, 3, 33, 247, 113, 166, 29, 144, 125, 218, 141, 165, 149, 54, 227, 59, 230, 115, 153, 148, 226, 141, 61, 180, 247, 171, 103, 219, 88, 37, 1, 74, 64, 37, 55, 162, 27, 236, 34, 45, 24, 136, 71, 228, 211, 55, 5, 134, 137, 162, 166, 175, 75, 13, 230, 120, 212, 54, 133, 213, 13, 212, 4, 75, 141, 17, 248, 142, 201, 250, 5, 221, 163, 237, 12, 161, 28, 238, 54, 158, 171, 228, 241, 92, 6, 0, 81, 232, 157, 213, 166, 240, 149, 3, 113, 11, 68, 217, 104, 163, 44, 113, 158, 213, 129, 142, 169, 83, 128, 174, 159, 118, 192, 38, 166, 163, 1, 198, 235, 155, 12, 16, 156, 12, 21, 244, 216, 229, 30, 161, 210, 22, 35, 22, 117, 126, 237, 94, 7, 217, 143, 145, 188, 52, 104, 98, 103, 53, 225, 105, 49, 246, 72, 3, 53, 240, 210, 195, 27, 186, 43, 247, 24, 204, 81, 229, 242, 32, 97, 84, 239, 144, 247, 4, 84, 158, 212, 187, 14, 18, 4, 12, 88, 248, 37, 10, 225, 196, 28, 170, 41, 138, 32, 149, 30, 134, 240, 43, 63, 144, 55, 220, 192, 49, 179, 137, 88, 163, 118, 187, 115, 167, 230, 99, 71, 225, 136, 190, 250, 55, 29, 186, 209, 106, 249, 128, 137, 153, 173, 182, 206, 68, 108, 38, 17, 165, 211, 69, 183, 74, 75, 43, 189, 59, 81, 189, 108, 108, 161, 183, 4, 24, 213, 237, 145, 162, 209, 80, 110, 35, 125, 172, 242, 209, 135, 3, 47, 212, 183, 137, 131, 95, 148, 95, 62, 211, 138, 17, 206, 113, 108, 150, 15, 132, 147, 227, 65, 39, 108, 224, 222, 148, 167, 68, 47, 10, 35, 104, 77, 79, 57, 240, 199, 184, 236, 76, 184, 130, 167, 150, 221, 17, 116, 132, 135, 128, 90, 63, 149, 158, 32, 27, 228, 82, 235, 61, 29, 137, 135, 245, 134, 183, 172, 78, 150, 234, 243, 196, 68, 162, 80, 79, 63, 108, 251, 114, 40, 250, 180, 84, 215, 162, 255, 38, 126, 85, 181, 5, 122, 4, 46, 93, 4, 68, 237, 84, 160, 191, 255, 46, 160, 103, 118, 242, 126, 40, 214, 157, 129, 245, 101, 13, 236, 36, 243, 11, 0, 91, 229, 253, 187, 217, 117, 133, 3, 22, 84, 25, 68, 237, 53, 127, 36, 59, 0, 69, 6, 33, 119, 202, 100, 131, 170, 240, 138, 178, 10, 104, 63, 129, 237, 145, 53, 80, 160, 152, 191, 62, 87, 0, 46, 14, 44, 15, 181, 64, 114, 89, 156, 238, 183, 153, 199, 9, 4, 31, 41, 91, 240, 109, 188, 209, 54, 125, 214, 86, 210, 150, 231, 193, 192, 70, 103, 109, 220, 148, 144, 50, 100, 184, 197, 35, 4, 22, 39, 246, 65, 168, 134, 144, 151, 125, 65, 42, 9, 167, 46, 35, 220, 208, 188, 211, 115, 84, 28, 221, 254, 21, 54, 67, 63, 235, 214, 42, 108, 118, 91, 172, 249, 252, 172, 208, 154, 238, 152, 19, 3, 16, 227, 124, 68, 72, 176, 240, 36, 48, 13, 194, 216, 227, 147, 231, 16, 242, 32, 42, 23, 93, 204, 3, 206, 10, 141, 255, 94, 43, 37, 107, 174, 61, 165, 221, 27, 52, 144, 8, 138, 50, 46, 64, 184, 168, 144, 13, 240, 20, 72, 174, 105, 84, 5, 79, 112, 55, 230, 170, 37, 229, 197, 61, 209, 24, 171, 3, 35, 170, 168, 96, 254, 84, 149, 170, 114, 252, 101, 78, 60, 21, 88, 69, 214, 79, 140, 244, 150, 181, 197, 17, 69, 184, 194, 144, 32, 18, 202, 36, 146, 124, 28, 46, 218, 237, 137, 139, 169, 242, 0, 122, 218, 44, 162, 77, 23, 221, 129, 111, 172, 145, 215, 86, 43, 197, 176, 242, 197, 38, 224, 189, 169, 229, 0, 20, 96, 50, 139, 4, 13, 213, 152, 45, 231, 24, 122, 11, 106, 2, 244, 114, 179, 184, 10, 12, 244, 131, 160, 22, 145, 48, 136, 195, 101, 65, 8, 210, 237, 182, 111, 4, 42, 50, 190, 43, 134, 121, 52, 197, 165, 89, 188, 30, 226, 161, 50, 182, 104, 200, 166, 254, 251, 178, 9, 14, 69, 204, 74, 147, 182, 204, 18, 97, 247, 255, 10, 191, 221, 122, 72, 106, 173, 224, 247, 239, 23, 93, 79, 108, 207, 58, 202, 143, 217, 194, 55, 131, 147, 192, 171, 139, 19, 49, 204, 51, 137, 63, 238, 115, 140, 41, 12, 27, 194, 16, 50, 168, 155, 208, 27, 33, 229, 87, 219, 56, 37, 100, 62, 97, 215, 183, 41, 134, 54, 211, 199, 33, 109, 83, 184, 155, 13, 156, 140, 180, 220, 142, 220, 57, 232, 80, 151, 241, 250, 170, 52, 224, 59, 38, 10, 214, 33, 219, 21, 82, 10, 227, 243, 215, 241, 165, 244, 248, 115, 103, 1, 28, 111, 6, 135, 178, 161, 167, 193, 5, 39, 62, 100, 216, 217, 155, 211, 203, 128, 81, 161, 77, 44, 82, 85, 255, 30, 80, 161, 236, 128, 216, 9, 229, 56, 174, 224, 68, 69, 25, 119, 169, 240, 7, 229, 5, 149, 141, 47, 195, 102, 190, 163, 179, 195, 80, 207, 61, 154, 71, 100, 111, 192, 98, 205, 22, 243, 108, 217, 14, 228, 118, 44, 87, 247, 34, 171, 180, 164, 124, 187, 194, 161, 39, 140, 22, 63, 147, 114, 190, 241, 248, 33, 44, 226, 29, 195, 99, 36, 213, 180, 66, 3, 7, 91, 49, 150, 140, 233, 99, 57, 0, 197, 106, 6, 93, 147, 230, 140, 51, 124, 154, 97, 181, 225, 247, 163, 35, 64, 5, 127, 110, 225, 62, 121, 23, 180, 214, 110, 230, 61, 127, 57, 36, 180, 102, 130, 75, 102, 155, 195, 154, 204, 254, 189, 198, 20, 142, 55, 155, 172, 181, 221, 78, 98, 177, 117, 165, 40, 52, 57, 72, 1, 246, 213, 159, 72, 190, 31, 1, 130, 136, 177, 107, 25, 127, 211, 228, 27, 115, 158, 59, 21, 83, 96, 82, 83, 78, 151, 73, 224, 226, 200, 79, 24, 11, 139, 201, 166, 188, 99, 228, 10, 203, 185, 161, 36, 167, 119, 158, 107, 165, 221, 161, 174, 87, 61, 239, 20, 255, 96, 122, 181, 239, 138, 8, 155, 82, 37, 24, 168, 227, 21, 177, 28, 252, 190, 236, 89, 243, 60, 232, 103, 12, 126, 129, 246, 143, 27, 220, 252, 141, 96, 57, 123, 250, 121, 43, 212, 247, 125, 148, 33, 204, 137, 190, 145, 57, 101, 52, 101, 78, 219, 199, 194, 126, 106, 250, 86, 44, 141, 40, 54, 67, 131, 80, 228, 105, 117, 39, 240, 128, 208, 17, 215, 11, 32, 205, 2, 75, 200, 89, 219, 28, 205, 141, 117, 3, 36, 58, 156, 18, 95, 7, 220, 252, 7, 146, 100, 221, 69, 120, 42, 233, 247, 2, 143, 214, 188, 58, 214, 99, 212, 91, 176, 9, 117, 105, 22, 0, 54, 26, 131, 171, 61, 54, 73, 51, 100, 178, 32, 183, 148, 180, 44, 211, 42, 251, 138, 157, 218, 244, 165, 0, 136, 40, 235, 192, 96, 65, 41, 8, 116, 114, 238, 41, 69, 200, 36, 38, 75, 46, 49, 233, 130, 9, 192, 57, 3, 132, 31, 129, 229, 96, 211, 88, 150, 88, 135, 115, 51, 242, 53, 239, 34, 181, 206, 166, 191, 126, 161, 78, 134, 189, 234, 187, 73, 54, 177, 160, 242, 183, 54, 231, 36, 57, 127, 88, 252, 167, 112, 141, 34, 51, 11, 9, 242, 221, 44, 252, 147, 250, 150, 130, 253, 149, 211, 14, 128, 75, 230, 68, 63, 2, 101, 233, 1, 58, 32, 24, 141, 146, 26, 21, 234, 83, 111, 16, 230, 187, 229, 152, 84, 156, 173, 80, 81, 249, 76, 162, 41, 213, 27, 116, 151, 13, 3, 101, 21, 10, 86, 12, 80, 192, 118, 104, 133, 14, 0, 19, 94, 45, 238, 229, 92, 229, 32, 159, 80, 84, 178, 110, 14, 102, 97, 127, 136, 172, 5, 180, 38, 114, 82, 196, 67, 140, 218, 180, 253, 26, 217, 160, 0, 125, 2, 211, 3, 173, 198, 92, 217, 167, 195, 177, 114, 214, 11, 169, 243, 69, 112, 238, 2, 121, 54, 163, 138, 43, 144, 39, 96, 145, 201, 251, 165, 166, 228, 248, 51, 55, 230, 24, 194, 83, 112, 125, 245, 213, 36, 79, 51, 79, 168, 198, 164, 236, 143, 176, 131, 243, 161, 201, 46, 54, 132, 9, 14, 154, 182, 31, 122, 35, 238, 233, 115, 224, 83, 44, 176, 26, 15, 31, 1, 160, 104, 18, 235, 103, 107, 1, 35, 221, 74, 206, 8, 207, 168, 166, 147, 51, 189, 213, 6, 244, 172, 145, 114, 56, 83, 121, 231, 215, 136, 174, 58, 174, 7, 7, 197, 1, 1, 125, 219, 115, 221, 25, 96, 85, 3, 84, 218, 47, 191, 148, 134, 97, 114, 195, 228, 121, 5, 246, 10, 236, 83, 85, 149, 179, 42, 154, 148, 51, 43, 192, 175, 226, 7, 128, 38, 31, 224, 253, 76, 199, 37, 214, 163, 56, 83, 74, 238, 47, 117, 139, 224, 68, 75, 114, 0, 161, 88, 29, 134, 54, 0, 209, 128, 171, 150, 147, 177, 37, 136, 69, 253, 89, 179, 182, 182, 129, 43, 66, 66, 166, 122, 229, 14, 203, 70, 224, 38, 57, 147, 253, 178, 93, 201, 209, 3, 61, 29, 201, 12, 224, 69, 215, 123, 221, 204, 40, 198, 0, 60, 131, 98, 92, 63, 215, 92, 84, 230, 186, 64, 76, 239, 206, 243, 182, 224, 248, 52, 68, 151, 193, 126, 238, 86, 66, 89, 164, 231, 3, 68, 92, 5, 133, 241, 173, 96, 244, 149, 127, 102, 188, 225, 225, 199, 181, 57, 58, 236, 245, 151, 65, 26, 41, 47, 84, 34, 18, 220, 240, 249, 129, 83, 195, 163, 216, 167, 229, 159, 139, 254, 230, 24, 95, 17, 3, 212, 112, 22, 132, 55, 235, 139, 43, 52, 5, 180, 64, 156, 237, 225, 44, 76, 230, 113, 77, 39, 249, 183, 75, 245, 23, 229, 33, 3, 255, 236, 41, 64, 197, 104, 98, 86, 113, 10, 97, 25, 232, 124, 28, 28, 13, 28, 5, 0, 76, 223, 89, 151, 78, 120, 139, 143, 23, 80, 70, 17, 185, 14, 76, 220, 4, 140, 132, 111, 71, 40, 67, 166, 146, 48, 10, 199, 51, 72, 10, 207, 66, 236, 30, 131, 16, 199, 104, 159, 95, 112, 223, 199, 155, 158, 231, 212, 162, 86, 80, 72, 203, 7, 71, 69, 143, 120, 84, 39, 69, 20, 19, 129, 61, 83, 135, 140, 137, 135, 203, 237, 204, 128, 97, 253, 214, 98, 104, 214, 57, 104, 31, 185, 67, 108, 147, 133, 178, 191, 153, 253, 17, 91, 149, 88, 215, 128, 103, 204, 95, 44, 137, 163, 117, 134, 129, 225, 185, 62, 180, 16, 71, 75, 123, 94, 10, 140, 37, 137, 217, 1, 204, 195, 70, 85, 57, 15, 47, 16, 22, 62, 22, 152, 207, 75, 135, 103, 142, 1, 10, 166, 177, 174, 152, 62, 125, 202, 98, 92, 153, 103, 19, 164, 53, 181, 76, 113, 146, 65, 17, 185, 94, 193, 156, 254, 185, 59, 100, 173, 227, 33, 17, 202, 189, 127, 255, 246, 97, 167, 94, 48, 168, 119, 119, 141, 122, 205, 213, 26, 16, 231, 11, 86, 94, 38, 116, 105, 177, 52, 147, 41, 211, 150, 137, 95, 237, 18, 245, 10, 209, 100, 209, 3, 84, 180, 213, 47, 251, 48, 51, 81, 101, 188, 67, 111, 243, 231, 65, 95, 163, 138, 2, 156, 129, 245, 98, 146, 246, 212, 166, 160, 147, 75, 176, 2, 193, 65, 230, 199, 117, 21, 56, 134, 163, 186, 115, 148, 207, 251, 145, 153, 232, 227, 97, 195, 93, 243, 90, 112, 35, 168, 151, 232, 225, 196, 156, 207, 188, 208, 79, 109, 82, 148, 83, 159, 63, 96, 211, 132, 178, 248, 83, 106, 231, 202, 1, 7, 57, 62, 177, 220, 133, 160, 136, 150, 242, 53, 20, 186, 201, 19, 90, 9, 216, 62, 193, 83, 199, 46, 14, 248, 154, 58, 3, 168, 45, 5, 40, 209, 223, 233, 69, 232, 67, 167, 163, 56, 59, 160, 53, 125, 231, 88, 116, 243, 171, 250, 109, 195, 85, 109, 125, 29, 163, 168, 124, 240, 24, 154, 38, 51, 221, 131, 223, 34, 172, 147, 3, 222, 255, 25, 202, 143, 78, 171, 22, 185, 198, 161, 51, 41, 108, 112, 84, 23, 98, 76, 54, 251, 149, 141, 211, 163, 249, 138, 135, 107, 206, 114, 177, 202, 1, 181, 2, 200, 131, 83, 148, 69, 170, 248, 81, 208, 38, 194, 73, 128, 147, 121, 166, 212, 43, 71, 243, 66, 197, 248, 75, 128, 23, 175, 106, 130, 202, 207, 162, 252, 11, 28, 152, 130, 64, 238, 200, 95, 112, 141, 48, 51, 201, 198, 145, 66, 173, 213, 142, 29, 159, 241, 183, 190, 244, 33, 236, 73, 234, 210, 67, 128, 185, 62, 249, 26, 192, 136, 142, 49, 17, 23, 71, 95, 254, 136, 134, 169, 83, 138, 250, 134, 239, 52, 180, 27, 199, 12, 33, 45, 121, 247, 201, 26, 151, 111, 26, 185, 154, 195, 200, 32, 233, 88, 215, 70, 140, 137, 124, 98, 40, 137, 70, 94, 2, 129, 6, 69, 219, 11, 11, 233, 157, 3, 191, 98, 89, 118, 17, 185, 8, 218, 170, 105, 36, 64, 202, 56, 13, 248, 35, 219, 17, 234, 34, 182, 212, 127, 153, 2, 20, 139, 136, 15, 162, 250, 152, 212, 24, 100, 193, 202, 238, 233, 111, 141, 233, 246, 127, 82, 31, 77, 32, 129, 81, 34, 227, 203, 50, 1, 179, 148, 50, 159, 28, 148, 197, 236, 248, 181, 16, 232, 45, 6, 212, 121, 53, 231, 179, 97, 176, 66, 68, 178, 176, 64, 206, 122, 146, 46, 86, 100, 43, 125, 98, 238, 201, 108, 167, 87, 246, 20, 70, 167, 9, 98, 115, 253, 11, 122, 70, 219, 71, 20, 11, 184, 196, 181, 104, 159, 124, 33, 228, 107, 190, 30, 77, 220, 233, 77, 37, 8, 32, 61, 168, 19, 112, 200, 59, 212, 26, 93, 215, 190, 221, 58, 10, 159, 81, 98, 31, 5, 64, 55, 137, 23, 19, 47, 105, 61, 92, 73, 37, 192, 86, 225, 7, 69, 208, 234, 164, 138, 196, 241, 187, 83, 240, 59, 239, 135, 10, 9, 157, 63, 26, 207, 125, 55, 146, 102, 164, 92, 105, 98, 234, 147, 100, 146, 131, 164, 153, 222, 32, 242, 137, 137, 6, 93, 194, 25, 4, 85, 69, 116, 155, 46, 107, 181, 14, 170, 101, 166, 210, 11, 124, 190, 214, 186, 48, 124, 38, 153, 128, 95, 244, 227, 65, 191, 230, 171, 15, 192, 252, 21, 253, 26, 222, 25, 201, 58, 59, 2, 65, 191, 108, 219, 99, 75, 201, 251, 137, 57, 123, 47, 114, 85, 163, 249, 196, 216, 235, 49, 27, 141, 95, 18, 62, 102, 174, 81, 173, 56, 102, 34, 47, 156, 77, 3, 232, 149, 155, 227, 226, 254, 41, 105, 252, 134, 212, 44, 64, 9, 34, 166, 234, 46, 3, 50, 132, 105, 178, 110, 38, 86, 139, 8, 239, 218, 122, 32, 241, 79, 43, 149, 192, 90, 108, 28, 35, 47, 26, 227, 169, 92, 150, 131, 155, 226, 250, 239, 73, 67, 151, 84, 92, 173, 115, 7, 36, 103, 184, 10, 160, 237, 247, 189, 188, 145, 114, 181, 151, 28, 71, 251, 238, 90, 0, 26, 208, 123, 104, 136, 144, 214, 242, 137, 178, 119, 23, 84, 98, 7, 239, 17, 195, 130, 185, 135, 27, 23, 111, 205, 19, 52, 140, 121, 134, 18, 50, 32, 141, 79, 134, 177, 59, 5, 190, 232, 112, 128, 96, 165, 99, 88, 167, 240, 186, 170, 216, 176, 130, 24, 214, 56, 223, 20, 188, 0, 30, 31, 66, 71, 110, 3, 233, 80, 220, 147, 135, 90, 24, 160, 137, 158, 58, 134, 240, 221, 75, 243, 151, 214, 28, 4, 150, 8, 15, 202, 178, 240, 122, 231, 219, 197, 46, 240, 70, 92, 232, 184, 178, 56, 64, 249, 10, 207, 230, 172, 181, 0, 23, 112, 50, 205, 183, 16, 58, 140, 50, 242, 197, 108, 158, 39, 225, 184, 211, 246, 21, 255, 56, 232, 67, 5, 130, 161, 104, 6, 176, 142, 184, 21, 42, 246, 172, 246, 236, 28, 255, 231, 163, 19, 126, 17, 176, 37, 121, 72, 202, 113, 71, 188, 184, 196, 105, 45, 64, 221, 191, 53, 81, 32, 160, 112, 0, 36, 243, 56, 127, 157, 117, 150, 212, 134, 150, 112, 210, 162, 214, 122, 87, 222, 74, 153, 116, 238, 170, 81, 103, 63, 230, 46, 69, 31, 223, 12, 32, 81, 157, 2, 65, 40, 142, 77, 92, 190, 214, 70, 94, 248, 87, 30, 148, 92, 243, 200, 146, 220, 185, 135, 174, 232, 81, 8, 126, 130, 15, 250, 76, 19, 112, 155, 218, 8, 166, 137, 248, 134, 156, 22, 173, 131, 44, 96, 115, 211, 148, 140, 95, 14, 189, 54, 32, 240, 150, 75, 99, 191, 74, 189, 29, 52, 209, 168, 229, 100, 80, 228, 100, 220, 176, 104, 115, 202, 29, 34, 136, 103, 39, 79, 14, 221, 51, 130, 152, 197, 87, 140, 92, 107, 3 }; - var i: u8 = 'a'; - var tokenizer = std.mem.tokenize(u8, add_completions, "\n"); +const uncompressed_size: usize = 162205; - while (i <= 'z') { - var init_tokenizer = tokenizer; - var count: usize = 0; - @setEvalBranchQuota(9999999); - while (init_tokenizer.next()) |pkg| { - if (pkg.len == 0) continue; - if (pkg[0] == i) { - count += 1; - } else { - break; - } - } - - var record: [count][]const u8 = undefined; - var record_i: usize = 0; - var next_i = i + 1; - - while (tokenizer.next()) |pkg| { - if (pkg.len == 0) continue; - - if (pkg[0] == i) { - record[record_i] = pkg; - record_i += 1; - } else { - next_i = pkg[0]; - break; - } - } - - const cloned = record; - array.set(@as(FirstLetter, @enumFromInt(i)), &cloned); - - @setEvalBranchQuota(999999); - i = next_i; - } - break :brk array; -}; -pub const biggest_list: usize = brk: { - var a = index; - var iter = a.iterator(); - var max: usize = 0; - while (iter.next()) |list| { - max = @max(list.value.len, max); - } - break :brk max; +pub const IndexEntry = struct { + offset: usize, + length: usize, }; -const index_blob = "add_completions.index.blob"; +pub const Index = std.EnumArray(FirstLetter, IndexEntry); + +pub const index = Index.init(.{ .a = .{ .offset = 0, .length = 540 }, .b = .{ .offset = 540, .length = 513 }, .c = .{ .offset = 1053, .length = 691 }, .d = .{ .offset = 1744, .length = 377 }, .e = .{ .offset = 2121, .length = 660 }, .f = .{ .offset = 2781, .length = 344 }, .g = .{ .offset = 3125, .length = 434 }, .h = .{ .offset = 3559, .length = 275 }, .i = .{ .offset = 3834, .length = 391 }, .j = .{ .offset = 4225, .length = 335 }, .k = .{ .offset = 4560, .length = 117 }, .l = .{ .offset = 4677, .length = 398 }, .m = .{ .offset = 5075, .length = 497 }, .n = .{ .offset = 5572, .length = 386 }, .o = .{ .offset = 5958, .length = 149 }, .p = .{ .offset = 6107, .length = 709 }, .q = .{ .offset = 6816, .length = 33 }, .r = .{ .offset = 6849, .length = 1034 }, .s = .{ .offset = 7883, .length = 817 }, .t = .{ .offset = 8700, .length = 417 }, .u = .{ .offset = 9117, .length = 217 }, .v = .{ .offset = 9334, .length = 302 }, .w = .{ .offset = 9636, .length = 220 }, .x = .{ .offset = 9856, .length = 60 }, .y = .{ .offset = 9916, .length = 53 }, .z = .{ .offset = 9969, .length = 30 } }); + +var decompressed_data: ?[]u8 = null; +var packages_list: ?[][]const u8 = null; + +pub fn init(allocator: std.mem.Allocator) !void { + // Decompress data + var data = try allocator.alloc(u8, uncompressed_size); + errdefer allocator.free(data); + + const result = zstd.decompress(data, &compressed_data); + decompressed_data = data[0..result.success]; + + // Parse package list + const total_count = std.mem.readInt(u32, data[0..4], .little); + var packages = try allocator.alloc([]const u8, total_count); + errdefer allocator.free(packages); + + var pos: usize = 4; + var i: usize = 0; + while (i < total_count) : (i += 1) { + const len = std.mem.readInt(u16, data[pos..][0..2], .little); + pos += 2; + packages[i] = data[pos .. pos + len]; + pos += len; + } + + packages_list = packages; +} + +pub fn deinit(allocator: std.mem.Allocator) void { + if (packages_list) |pkgs| { + allocator.free(pkgs); + packages_list = null; + } + + if (decompressed_data) |data| { + allocator.free(data); + decompressed_data = null; + } +} + +pub fn getPackages(letter: FirstLetter) []const []const u8 { + const entry = index.get(letter); + if (entry.length == 0) return &[_][]const u8{}; + + return packages_list.?[entry.offset .. entry.offset + entry.length]; +} + +pub const biggest_list: usize = 1034; From 2b2ca3275c5e035a424f16ed5bc1f30f43d96fa1 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 25 Dec 2024 21:47:13 -0800 Subject: [PATCH 094/125] Improve stack overflow, show more properties in Error objects (#15985) Co-authored-by: Dave Caruso --- cmake/targets/BuildBun.cmake | 2 +- src/bit_set.zig | 7 +- src/bun.js/ConsoleObject.zig | 180 ++++- src/bun.js/api/BunObject.zig | 14 +- src/bun.js/api/bun/subprocess.zig | 74 +- src/bun.js/bindings/BunString.cpp | 18 + src/bun.js/bindings/ErrorCode.ts | 3 + src/bun.js/bindings/JSPropertyIterator.cpp | 116 ++- src/bun.js/bindings/JSPropertyIterator.zig | 17 +- src/bun.js/bindings/bindings.cpp | 44 +- src/bun.js/bindings/bindings.zig | 26 +- src/bun.js/bindings/exports.zig | 4 + src/bun.js/bindings/wtf-bindings.cpp | 15 +- src/bun.js/javascript.zig | 254 ++++--- src/bun.js/node/node_fs.zig | 25 +- src/bun.js/node/types.zig | 16 +- src/bun.js/web_worker.zig | 3 + src/bun.js/webcore/streams.zig | 7 +- src/bun.zig | 91 +++ src/hive_array.zig | 2 +- src/http/websocket_http_client.zig | 6 - src/install/semver.zig | 2 +- src/js/builtins/shell.ts | 23 +- src/js_lexer.zig | 2 +- src/js_lexer/identifier_data.zig | 5 +- src/js_parser.zig | 48 +- src/main.zig | 2 +- src/output.zig | 1 + src/patch.zig | 6 +- src/pool.zig | 16 + src/shell/interpreter.zig | 21 +- src/shell/shell.zig | 4 +- src/string.zig | 13 +- src/string_immutable.zig | 21 +- src/sys.zig | 92 ++- src/url.zig | 2 +- src/which.zig | 14 +- .../transpiler/fixtures/lots-of-for-loop.js | 713 ++++++++++++++++++ test/bundler/transpiler/transpiler.test.js | 16 + test/js/bun/test/stack.test.ts | 23 +- test/js/bun/util/error-gc-test.test.js | 19 +- test/js/bun/util/reportError.test.ts | 46 +- test/js/node/util/bun-inspect.test.ts | 46 +- 43 files changed, 1735 insertions(+), 324 deletions(-) create mode 100644 test/bundler/transpiler/fixtures/lots-of-for-loop.js diff --git a/cmake/targets/BuildBun.cmake b/cmake/targets/BuildBun.cmake index 11759e2f7a..35949d5239 100644 --- a/cmake/targets/BuildBun.cmake +++ b/cmake/targets/BuildBun.cmake @@ -860,7 +860,7 @@ endif() if(WIN32) target_link_options(${bun} PUBLIC - /STACK:0x1200000,0x100000 + /STACK:0x1200000,0x200000 /errorlimit:0 ) if(RELEASE) diff --git a/src/bit_set.zig b/src/bit_set.zig index 245dbd09e6..2ecd5b3591 100644 --- a/src/bit_set.zig +++ b/src/bit_set.zig @@ -1,3 +1,8 @@ +//! This is a fork of Zig standard library bit_set.zig +//! - https://github.com/ziglang/zig/pull/14129 +//! - AutoBitset which optimally chooses between a dynamic or static bitset. +//! Prefer our fork over std.bit_set.zig. +//! //! This file defines several variants of bit sets. A bit set //! is a densely stored set of integers with a known maximum, //! in which each integer gets a single bit. Bit sets have very @@ -402,7 +407,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { /// Returns true if the bit at the specified index /// is present in the set, false otherwise. - pub inline fn isSet(self: *const Self, index: usize) bool { + pub fn isSet(self: *const Self, index: usize) bool { if (comptime Environment.allow_assert) bun.assert(index < bit_length); if (num_masks == 0) return false; // doesn't compile in this case return (self.masks[maskIndex(index)] & maskBit(index)) != 0; diff --git a/src/bun.js/ConsoleObject.zig b/src/bun.js/ConsoleObject.zig index 12a2506a41..b6f05770b6 100644 --- a/src/bun.js/ConsoleObject.zig +++ b/src/bun.js/ConsoleObject.zig @@ -299,6 +299,8 @@ pub const TablePrinter = struct { .quote_strings = false, .single_line = true, .max_depth = 5, + .can_throw_stack_overflow = true, + .stack_check = bun.StackCheck.init(), }, }; } @@ -481,8 +483,12 @@ pub const TablePrinter = struct { defer { if (value_formatter.map_node) |node| { - node.data = value_formatter.map; - node.data.clearRetainingCapacity(); + this.value_formatter.map_node = null; + if (node.data.capacity() > 512) { + node.data.clearAndFree(); + } else { + node.data.clearRetainingCapacity(); + } node.release(); } } @@ -767,17 +773,9 @@ pub fn format2( writer: Writer, options: FormatOptions, ) void { - var fmt: ConsoleObject.Formatter = undefined; - defer { - if (fmt.map_node) |node| { - node.data = fmt.map; - node.data.clearRetainingCapacity(); - node.release(); - } - } - if (len == 1) { - fmt = ConsoleObject.Formatter{ + // initialized later in this function. + var fmt = ConsoleObject.Formatter{ .remaining_values = &[_]JSValue{}, .globalThis = global, .ordered_properties = options.ordered_properties, @@ -785,7 +783,10 @@ pub fn format2( .max_depth = options.max_depth, .single_line = options.single_line, .indent = options.default_indent, + .stack_check = bun.StackCheck.init(), + .can_throw_stack_overflow = true, }; + defer fmt.deinit(); const tag = ConsoleObject.Formatter.Tag.get(vals[0], global); fmt.writeIndent(Writer, writer) catch return; @@ -858,14 +859,17 @@ pub fn format2( } var this_value: JSValue = vals[0]; - fmt = ConsoleObject.Formatter{ + var fmt = ConsoleObject.Formatter{ .remaining_values = vals[0..len][1..], .globalThis = global, .ordered_properties = options.ordered_properties, .quote_strings = options.quote_strings, .single_line = options.single_line, .indent = options.default_indent, + .stack_check = bun.StackCheck.init(), + .can_throw_stack_overflow = true, }; + defer fmt.deinit(); var tag: ConsoleObject.Formatter.Tag.Result = undefined; fmt.writeIndent(Writer, writer) catch return; @@ -942,6 +946,21 @@ pub const Formatter = struct { single_line: bool = false, ordered_properties: bool = false, custom_formatted_object: CustomFormattedObject = .{}, + disable_inspect_custom: bool = false, + stack_check: bun.StackCheck = .{ .cached_stack_end = std.math.maxInt(usize) }, + can_throw_stack_overflow: bool = false, + + pub fn deinit(this: *Formatter) void { + if (bun.take(&this.map_node)) |node| { + node.data = this.map; + if (node.data.capacity() > 512) { + node.data.clearAndFree(); + } else { + node.data.clearRetainingCapacity(); + } + node.release(); + } + } pub fn goodTimeForANewLine(this: *@This()) bool { if (this.estimated_line_length > 80) { @@ -1052,8 +1071,11 @@ pub const Formatter = struct { }; } - pub inline fn canHaveCircularReferences(tag: Tag) bool { - return tag == .Array or tag == .Object or tag == .Map or tag == .Set; + pub fn canHaveCircularReferences(tag: Tag) bool { + return switch (tag) { + .Function, .Array, .Object, .Map, .Set, .Error, .Class, .Event => true, + else => false, + }; } const Result = struct { @@ -1106,8 +1128,10 @@ pub const Formatter = struct { return getAdvanced(value, globalThis, .{ .hide_global = false }); } - pub const Options = struct { + // It sounds silly to make this packed, but Tag.getAdvanced is extremely recursive. + pub const Options = packed struct { hide_global: bool = false, + disable_inspect_custom: bool = false, }; pub fn getAdvanced(value: JSValue, globalThis: *JSGlobalObject, opts: Options) Result { @@ -1154,7 +1178,7 @@ pub const Formatter = struct { }; } - if (js_type.canGet() and js_type != .ProxyObject) { + if (js_type.canGet() and js_type != .ProxyObject and !opts.disable_inspect_custom) { // Attempt to get custom formatter if (value.fastGet(globalThis, .inspectCustom)) |callback_value| { if (callback_value.isCallable(globalThis.vm())) { @@ -1181,7 +1205,7 @@ pub const Formatter = struct { // If we check an Object has a method table and it does not // it will crash - if (js_type != .Object and value.isCallable(globalThis.vm())) { + if (js_type != .Object and js_type != .ProxyObject and value.isCallable(globalThis.vm())) { if (value.isClass(globalThis)) { return .{ .tag = .{ .Class = {} }, @@ -1544,11 +1568,17 @@ pub const Formatter = struct { } pub fn WrappedWriter(comptime Writer: type) type { + if (@hasDecl(Writer, "is_wrapped_writer")) { + @compileError("Do not nest WrappedWriter"); + } + return struct { ctx: Writer, failed: bool = false, estimated_line_length: *usize, + pub const is_wrapped_writer = true; + pub fn print(self: *@This(), comptime fmt: string, args: anytype) void { self.ctx.print(fmt, args) catch { self.failed = true; @@ -1642,16 +1672,16 @@ pub const Formatter = struct { }; } + const indentation_buf = [_]u8{' '} ** 64; pub fn writeIndent( this: *ConsoleObject.Formatter, comptime Writer: type, writer: Writer, ) !void { - var buf = [_]u8{' '} ** 64; var total_remain: u32 = this.indent; while (total_remain > 0) { const written: u8 = @min(32, total_remain); - try writer.writeAll(buf[0 .. written * 2]); + try writer.writeAll(indentation_buf[0 .. written * 2]); total_remain -|= written; } } @@ -1668,6 +1698,7 @@ pub const Formatter = struct { count: usize = 0, pub fn forEach(_: [*c]JSC.VM, globalObject: *JSGlobalObject, ctx: ?*anyopaque, nextValue: JSValue) callconv(.C) void { var this: *@This() = bun.cast(*@This(), ctx orelse return); + if (this.formatter.failed) return; if (single_line and this.count > 0) { this.formatter.printComma(Writer, this.writer, enable_ansi_colors) catch unreachable; this.writer.writeAll(" ") catch unreachable; @@ -1679,7 +1710,10 @@ pub const Formatter = struct { if (!single_line) { this.formatter.writeIndent(Writer, this.writer) catch unreachable; } - const key_tag = Tag.getAdvanced(key, globalObject, .{ .hide_global = true }); + const key_tag = Tag.getAdvanced(key, globalObject, .{ + .hide_global = true, + .disable_inspect_custom = this.formatter.disable_inspect_custom, + }); this.formatter.format( key_tag, @@ -1690,7 +1724,10 @@ pub const Formatter = struct { enable_ansi_colors, ); this.writer.writeAll(": ") catch unreachable; - const value_tag = Tag.getAdvanced(value, globalObject, .{ .hide_global = true }); + const value_tag = Tag.getAdvanced(value, globalObject, .{ + .hide_global = true, + .disable_inspect_custom = this.formatter.disable_inspect_custom, + }); this.formatter.format( value_tag, Writer, @@ -1704,7 +1741,10 @@ pub const Formatter = struct { this.writer.writeAll("\n") catch unreachable; this.formatter.writeIndent(Writer, this.writer) catch unreachable; } - const tag = Tag.getAdvanced(nextValue, globalObject, .{ .hide_global = true }); + const tag = Tag.getAdvanced(nextValue, globalObject, .{ + .hide_global = true, + .disable_inspect_custom = this.formatter.disable_inspect_custom, + }); this.formatter.format( tag, Writer, @@ -1732,6 +1772,7 @@ pub const Formatter = struct { is_first: bool = true, pub fn forEach(_: [*c]JSC.VM, globalObject: *JSGlobalObject, ctx: ?*anyopaque, nextValue: JSValue) callconv(.C) void { var this: *@This() = bun.cast(*@This(), ctx orelse return); + if (this.formatter.failed) return; if (single_line) { if (!this.is_first) { this.formatter.printComma(Writer, this.writer, enable_ansi_colors) catch unreachable; @@ -1741,7 +1782,10 @@ pub const Formatter = struct { } else { this.formatter.writeIndent(Writer, this.writer) catch {}; } - const key_tag = Tag.getAdvanced(nextValue, globalObject, .{ .hide_global = true }); + const key_tag = Tag.getAdvanced(nextValue, globalObject, .{ + .hide_global = true, + .disable_inspect_custom = this.formatter.disable_inspect_custom, + }); this.formatter.format( key_tag, Writer, @@ -1807,6 +1851,7 @@ pub const Formatter = struct { var ctx: *@This() = bun.cast(*@This(), ctx_ptr orelse return); var this = ctx.formatter; + if (this.failed) return; const writer_ = ctx.writer; var writer = WrappedWriter(Writer){ .ctx = writer_, @@ -1814,7 +1859,10 @@ pub const Formatter = struct { .estimated_line_length = &this.estimated_line_length, }; - const tag = Tag.getAdvanced(value, globalThis, .{ .hide_global = true }); + const tag = Tag.getAdvanced(value, globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }); if (tag.cell.isHidden()) return; if (ctx.i == 0) { @@ -1949,6 +1997,11 @@ pub const Formatter = struct { ) void { if (this.failed) return; + if (this.globalThis.hasException()) { + this.failed = true; + return; + } + var writer = WrappedWriter(Writer){ .ctx = writer_, .estimated_line_length = &this.estimated_line_length }; defer { if (writer.failed) { @@ -1956,6 +2009,14 @@ pub const Formatter = struct { } } if (comptime Format.canHaveCircularReferences()) { + if (!this.stack_check.isSafeToRecurse()) { + this.failed = true; + if (this.can_throw_stack_overflow) { + this.globalThis.throwStackOverflow(); + } + return; + } + if (this.map_node == null) { this.map_node = Visited.Pool.get(default_allocator); this.map_node.?.data.clearRetainingCapacity(); @@ -2156,6 +2217,7 @@ pub const Formatter = struct { value, null, null, + this, Writer, writer_, enable_ansi_colors, @@ -2270,7 +2332,10 @@ pub const Formatter = struct { first: { const element = value.getDirectIndex(this.globalThis, 0); - const tag = Tag.getAdvanced(element, this.globalThis, .{ .hide_global = true }); + const tag = Tag.getAdvanced(element, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }); was_good_time = was_good_time or !tag.tag.isPrimitive() or this.goodTimeForANewLine(); @@ -2291,6 +2356,10 @@ pub const Formatter = struct { } this.format(tag, Writer, writer_, element, this.globalThis, enable_ansi_colors); + if (this.globalThis.hasException()) { + this.failed = true; + } + if (this.failed) return; if (tag.cell.isStringLike()) { if (comptime enable_ansi_colors) { @@ -2350,9 +2419,13 @@ pub const Formatter = struct { writer.space(); } - const tag = Tag.getAdvanced(element, this.globalThis, .{ .hide_global = true }); + const tag = Tag.getAdvanced(element, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }); this.format(tag, Writer, writer_, element, this.globalThis, enable_ansi_colors); + if (this.failed) return; if (tag.cell.isStringLike()) { if (comptime enable_ansi_colors) { @@ -2395,6 +2468,10 @@ pub const Formatter = struct { .i = i, }; value.forEachPropertyNonIndexed(this.globalThis, &iter, Iterator.forEach); + if (this.globalThis.hasException()) { + this.failed = true; + } + if (this.failed) return; } } @@ -2581,6 +2658,7 @@ pub const Formatter = struct { .writer = writer_, }; value.forEach(this.globalThis, &iter, @TypeOf(iter).forEach); + if (this.failed) return; if (single_line and iter.count > 0) { writer.writeAll(" "); } @@ -2610,6 +2688,7 @@ pub const Formatter = struct { .writer = writer_, }; value.forEach(this.globalThis, &iter, @TypeOf(iter).forEach); + if (this.failed) return; if (iter.count > 0) { if (single_line) { writer.writeAll(" "); @@ -2643,6 +2722,7 @@ pub const Formatter = struct { .writer = writer_, }; value.forEach(this.globalThis, &iter, @TypeOf(iter).forEach); + if (this.failed) return; if (iter.count > 0 and !single_line) { writer.writeAll("\n"); } @@ -2689,6 +2769,7 @@ pub const Formatter = struct { .writer = writer_, }; value.forEach(this.globalThis, &iter, @TypeOf(iter).forEach); + if (this.failed) return; if (single_line and !iter.is_first) { writer.writeAll(" "); } @@ -2794,8 +2875,12 @@ pub const Formatter = struct { .{}, ); - const tag = Tag.getAdvanced(message_value, this.globalThis, .{ .hide_global = true }); + const tag = Tag.getAdvanced(message_value, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }); this.format(tag, Writer, writer_, message_value, this.globalThis, enable_ansi_colors); + if (this.failed) return; this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable; if (!this.single_line) { writer.writeAll("\n"); @@ -2814,8 +2899,12 @@ pub const Formatter = struct { .{}, ); const data = value.fastGet(this.globalThis, .data) orelse JSValue.undefined; - const tag = Tag.getAdvanced(data, this.globalThis, .{ .hide_global = true }); + const tag = Tag.getAdvanced(data, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }); this.format(tag, Writer, writer_, data, this.globalThis, enable_ansi_colors); + if (this.failed) return; this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable; if (!this.single_line) { writer.writeAll("\n"); @@ -2832,8 +2921,12 @@ pub const Formatter = struct { .{}, ); - const tag = Tag.getAdvanced(error_value, this.globalThis, .{ .hide_global = true }); + const tag = Tag.getAdvanced(error_value, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }); this.format(tag, Writer, writer_, error_value, this.globalThis, enable_ansi_colors); + if (this.failed) return; this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable; if (!this.single_line) { writer.writeAll("\n"); @@ -2863,7 +2956,10 @@ pub const Formatter = struct { defer if (tag_name_slice.isAllocated()) tag_name_slice.deinit(); if (value.get_unsafe(this.globalThis, "type")) |type_value| { - const _tag = Tag.getAdvanced(type_value, this.globalThis, .{ .hide_global = true }); + const _tag = Tag.getAdvanced(type_value, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }); if (_tag.cell == .Symbol) {} else if (_tag.cell.isStringLike()) { type_value.toZigString(&tag_name_str, this.globalThis); @@ -2903,7 +2999,10 @@ pub const Formatter = struct { this.quote_strings = true; defer this.quote_strings = old_quote_strings; - this.format(Tag.getAdvanced(key_value, this.globalThis, .{ .hide_global = true }), Writer, writer_, key_value, this.globalThis, enable_ansi_colors); + this.format(Tag.getAdvanced(key_value, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }), Writer, writer_, key_value, this.globalThis, enable_ansi_colors); needs_space = true; } @@ -2933,7 +3032,10 @@ pub const Formatter = struct { continue; const property_value = props_iter.value; - const tag = Tag.getAdvanced(property_value, this.globalThis, .{ .hide_global = true }); + const tag = Tag.getAdvanced(property_value, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }); if (tag.cell.isHidden()) continue; @@ -3037,7 +3139,10 @@ pub const Formatter = struct { var j: usize = 0; while (j < length) : (j += 1) { const child = children.getIndex(this.globalThis, @as(u32, @intCast(j))); - this.format(Tag.getAdvanced(child, this.globalThis, .{ .hide_global = true }), Writer, writer_, child, this.globalThis, enable_ansi_colors); + this.format(Tag.getAdvanced(child, this.globalThis, .{ + .hide_global = true, + .disable_inspect_custom = this.disable_inspect_custom, + }), Writer, writer_, child, this.globalThis, enable_ansi_colors); if (j + 1 < length) { writer.writeAll("\n"); this.writeIndent(Writer, writer_) catch unreachable; @@ -3129,6 +3234,11 @@ pub const Formatter = struct { value.forEachProperty(this.globalThis, &iter, Iterator.forEach); } + if (this.globalThis.hasException()) { + this.failed = true; + } + if (this.failed) return; + if (iter.i == 0) { if (value.isClass(this.globalThis)) this.printAs(.Class, Writer, writer_, value, jsType, enable_ansi_colors) @@ -3446,6 +3556,8 @@ pub fn timeLog( .globalThis = global, .ordered_properties = false, .quote_strings = false, + .stack_check = bun.StackCheck.init(), + .can_throw_stack_overflow = true, }; var console = global.bunVM().console; var writer = console.error_writer.writer(); diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index 13d6f66d79..259e741f33 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -344,7 +344,8 @@ pub fn braces(global: *JSC.JSGlobalObject, brace_str: bun.String, opts: gen.Brac pub fn which(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { const arguments_ = callframe.arguments_old(2); - var path_buf: bun.PathBuffer = undefined; + const path_buf = bun.PathBufferPool.get(); + defer bun.PathBufferPool.put(path_buf); var arguments = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments_.slice()); defer arguments.deinit(); const path_arg = arguments.nextEat() orelse { @@ -397,7 +398,7 @@ pub fn which(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSE } if (Which.which( - &path_buf, + path_buf, path_str.slice(), cwd_str.slice(), bin_str.slice(), @@ -506,6 +507,7 @@ pub fn inspect(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.J // very stable memory address var array = MutableString.init(getAllocator(globalThis), 0) catch unreachable; + defer array.deinit(); var buffered_writer_ = MutableString.BufferedWriter{ .context = &array }; var buffered_writer = &buffered_writer_; @@ -523,15 +525,19 @@ pub fn inspect(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.J writer, formatOptions, ); + if (globalThis.hasException()) { + return .zero; + } + buffered_writer.flush() catch { - return .undefined; + return globalThis.throwOutOfMemory(); }; // we are going to always clone to keep things simple for now // the common case here will be stack-allocated, so it should be fine var out = ZigString.init(array.slice()).withEncoding(); const ret = out.toJS(globalThis); - array.deinit(); + return ret; } diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 143b87fb25..7c8774d548 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -1703,15 +1703,58 @@ pub const Subprocess = struct { return spawnMaybeSync(globalThis, args, secondaryArgsValue, true); } + // This is split into a separate function to conserve stack space. + // On Windows, a single path buffer can take 64 KB. + fn getArgv0(globalThis: *JSC.JSGlobalObject, PATH: []const u8, cwd: []const u8, argv0: ?[*:0]const u8, first_cmd: JSValue, allocator: std.mem.Allocator) bun.JSError!struct { + argv0: [:0]const u8, + arg0: [:0]u8, + } { + var arg0 = try first_cmd.toSliceOrNullWithAllocator(globalThis, allocator); + defer arg0.deinit(); + // Heap allocate it to ensure we don't run out of stack space. + const path_buf: *bun.PathBuffer = try bun.default_allocator.create(bun.PathBuffer); + defer bun.default_allocator.destroy(path_buf); + + var actual_argv0: [:0]const u8 = ""; + + if (argv0 == null) { + const resolved = Which.which(path_buf, PATH, cwd, arg0.slice()) orelse { + return throwCommandNotFound(globalThis, arg0.slice()); + }; + actual_argv0 = try allocator.dupeZ(u8, resolved); + } else { + const resolved = Which.which(path_buf, PATH, cwd, bun.sliceTo(argv0.?, 0)) orelse { + return throwCommandNotFound(globalThis, arg0.slice()); + }; + actual_argv0 = try allocator.dupeZ(u8, resolved); + } + + return .{ + .argv0 = actual_argv0, + .arg0 = try allocator.dupeZ(u8, arg0.slice()), + }; + } + pub fn spawnMaybeSync( globalThis: *JSC.JSGlobalObject, args_: JSValue, secondaryArgsValue: ?JSValue, comptime is_sync: bool, ) bun.JSError!JSValue { + if (comptime is_sync) { + // We skip this on Windows due to test failures. + if (comptime !Environment.isWindows) { + // Since the event loop is recursively called, we need to check if it's safe to recurse. + if (!bun.StackCheck.init().isSafeToRecurse()) { + globalThis.throwStackOverflow(); + return error.JSError; + } + } + } + var arena = bun.ArenaAllocator.init(bun.default_allocator); defer arena.deinit(); - var allocator = arena.allocator(); + const allocator = arena.allocator(); var override_env = false; var env_array = std.ArrayListUnmanaged(?[*:0]const u8){}; @@ -1801,33 +1844,16 @@ pub const Subprocess = struct { return globalThis.throwInvalidArguments("cmd must not be empty", .{}); } - { - var first_cmd = cmds_array.next().?; - var arg0 = try first_cmd.toSliceOrNullWithAllocator(globalThis, allocator); - defer arg0.deinit(); - - if (argv0 == null) { - var path_buf: bun.PathBuffer = undefined; - const resolved = Which.which(&path_buf, PATH, cwd, arg0.slice()) orelse { - return throwCommandNotFound(globalThis, arg0.slice()); - }; - argv0 = try allocator.dupeZ(u8, resolved); - } else { - var path_buf: bun.PathBuffer = undefined; - const resolved = Which.which(&path_buf, PATH, cwd, bun.sliceTo(argv0.?, 0)) orelse { - return throwCommandNotFound(globalThis, arg0.slice()); - }; - argv0 = try allocator.dupeZ(u8, resolved); - } - - argv.appendAssumeCapacity(try allocator.dupeZ(u8, arg0.slice())); - } + const argv0_result = try getArgv0(globalThis, PATH, cwd, argv0, cmds_array.next().?, allocator); + argv0 = argv0_result.argv0.ptr; + argv.appendAssumeCapacity(argv0_result.arg0.ptr); while (cmds_array.next()) |value| { - const arg = value.getZigString(globalThis); + const arg = try value.toBunString2(globalThis); + defer arg.deref(); // if the string is empty, ignore it, don't add it to the argv - if (arg.len == 0) { + if (arg.isEmpty()) { continue; } argv.appendAssumeCapacity(try arg.toOwnedSliceZ(allocator)); diff --git a/src/bun.js/bindings/BunString.cpp b/src/bun.js/bindings/BunString.cpp index 17200b35c3..3190415941 100644 --- a/src/bun.js/bindings/BunString.cpp +++ b/src/bun.js/bindings/BunString.cpp @@ -13,6 +13,7 @@ #include "ZigGlobalObject.h" #include "IDLTypes.h" +#include #include #include #include @@ -34,6 +35,7 @@ #include "GCDefferalContext.h" #include "wtf/text/StringImpl.h" +#include "wtf/text/StringToIntegerConversion.h" extern "C" void mi_free(void* ptr); @@ -90,6 +92,22 @@ extern "C" BunString BunString__tryCreateAtom(const char* bytes, size_t length) return { BunStringTag::Dead, {} }; } +// int64_t max to say "not a number" +extern "C" int64_t BunString__toInt32(BunString* bunString) +{ + if (bunString->tag == BunStringTag::Empty || bunString->tag == BunStringTag::Dead) { + return std::numeric_limits::max(); + } + + String str = bunString->toWTFString(); + auto val = WTF::parseIntegerAllowingTrailingJunk(str); + if (val) { + return val.value(); + } + + return std::numeric_limits::max(); +} + namespace Bun { JSC::JSValue toJS(JSC::JSGlobalObject* globalObject, BunString bunString) { diff --git a/src/bun.js/bindings/ErrorCode.ts b/src/bun.js/bindings/ErrorCode.ts index d04c096ae6..a4b5417054 100644 --- a/src/bun.js/bindings/ErrorCode.ts +++ b/src/bun.js/bindings/ErrorCode.ts @@ -95,4 +95,7 @@ export default [ ["ERR_ASYNC_TYPE", TypeError], ["ERR_INVALID_ASYNC_ID", RangeError], ["ERR_ASYNC_CALLBACK", TypeError], + + // Postgres + ["ERR_POSTGRES_ERROR_RESPONSE", Error, "PostgresError"], ] as ErrorCodeMapping; diff --git a/src/bun.js/bindings/JSPropertyIterator.cpp b/src/bun.js/bindings/JSPropertyIterator.cpp index e386c6cc5a..8d4657f469 100644 --- a/src/bun.js/bindings/JSPropertyIterator.cpp +++ b/src/bun.js/bindings/JSPropertyIterator.cpp @@ -1,7 +1,8 @@ - - #include "root.h" +#include "BunClientData.h" +#include "ZigGlobalObject.h" +#include "JavaScriptCore/JSType.h" #include "JavaScriptCore/EnumerationMode.h" #include "JavaScriptCore/ExceptionScope.h" #include "JavaScriptCore/ThrowScope.h" @@ -11,6 +12,7 @@ #include "wtf/Assertions.h" #include "wtf/FastMalloc.h" #include "headers-handwritten.h" +#include "ObjectBindings.h" namespace Bun { using namespace JSC; @@ -25,6 +27,7 @@ public: RefPtr properties; Ref vm; + bool isSpecialProxy = false; static JSPropertyIterator* create(JSC::VM& vm, RefPtr data) { return new JSPropertyIterator(vm, data); @@ -33,7 +36,7 @@ public: WTF_MAKE_FAST_ALLOCATED; }; -extern "C" JSPropertyIterator* Bun__JSPropertyIterator__create(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue, size_t* count) +extern "C" JSPropertyIterator* Bun__JSPropertyIterator__create(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue, size_t* count, bool own_properties_only, bool only_non_index_properties) { JSC::VM& vm = globalObject->vm(); JSC::JSValue value = JSValue::decode(encodedValue); @@ -41,7 +44,42 @@ extern "C" JSPropertyIterator* Bun__JSPropertyIterator__create(JSC::JSGlobalObje auto scope = DECLARE_THROW_SCOPE(vm); JSC::PropertyNameArray array(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude); - object->getPropertyNames(globalObject, array, DontEnumPropertiesMode::Exclude); + +#if OS(WINDOWS) + if (UNLIKELY(object->type() == JSC::ProxyObjectType)) { + // Check if we're actually iterating through the JSEnvironmentVariableMap's proxy. + auto* zigGlobal = defaultGlobalObject(globalObject); + if (zigGlobal->m_processEnvObject.isInitialized()) { + if (object == zigGlobal->m_processEnvObject.get(zigGlobal)) { + object->methodTable()->getOwnPropertyNames( + object, + globalObject, + array, + DontEnumPropertiesMode::Exclude); + RETURN_IF_EXCEPTION(scope, nullptr); + + *count = array.size(); + if (array.size() == 0) { + return nullptr; + } + + auto* iter = JSPropertyIterator::create(vm, array.releaseData()); + iter->isSpecialProxy = true; + return iter; + } + } + } +#endif + + if (own_properties_only) { + if (only_non_index_properties) { + object->getOwnNonIndexPropertyNames(globalObject, array, DontEnumPropertiesMode::Exclude); + } else { + object->getOwnPropertyNames(object, globalObject, array, DontEnumPropertiesMode::Exclude); + } + } else { + object->getPropertyNames(globalObject, array, DontEnumPropertiesMode::Exclude); + } RETURN_IF_EXCEPTION(scope, nullptr); *count = array.size(); @@ -52,13 +90,79 @@ extern "C" JSPropertyIterator* Bun__JSPropertyIterator__create(JSC::JSGlobalObje return JSPropertyIterator::create(vm, array.releaseData()); } +extern "C" size_t Bun__JSPropertyIterator__getLongestPropertyName(JSPropertyIterator* iter, JSC::JSGlobalObject* globalObject, JSC::JSObject* object) +{ + size_t longest = 0; + for (const auto& prop : iter->properties->propertyNameVector()) { + if (prop.length() > longest) { + longest = prop.length(); + } + } + + return longest; +} + +static EncodedJSValue getOwnProxyObject(JSPropertyIterator* iter, JSObject* object, const JSC::Identifier& prop, BunString* propertyName) +{ + auto& vm = iter->vm; + auto scope = DECLARE_THROW_SCOPE(vm); + + PropertySlot slot(object, PropertySlot::InternalMethodType::GetOwnProperty, nullptr); + auto* globalObject = object->globalObject(); + if (!object->methodTable()->getOwnPropertySlot(object, globalObject, prop, slot)) { + return {}; + } + RETURN_IF_EXCEPTION(scope, {}); + + JSValue result = slot.getValue(globalObject, prop); + RETURN_IF_EXCEPTION(scope, {}); + + *propertyName = Bun::toString(prop.impl()); + return JSValue::encode(result); +} + extern "C" EncodedJSValue Bun__JSPropertyIterator__getNameAndValue(JSPropertyIterator* iter, JSC::JSGlobalObject* globalObject, JSC::JSObject* object, BunString* propertyName, size_t i) { const auto& prop = iter->properties->propertyNameVector()[i]; + if (UNLIKELY(iter->isSpecialProxy)) { + return getOwnProxyObject(iter, object, prop, propertyName); + } - auto scope = DECLARE_THROW_SCOPE(iter->vm); - JSValue result = object->get(globalObject, prop); + auto& vm = iter->vm; + auto scope = DECLARE_THROW_SCOPE(vm); + PropertySlot slot(object, PropertySlot::InternalMethodType::GetOwnProperty); + if (!object->getOwnPropertySlot(object, globalObject, prop, slot)) { + return {}; + } + RETURN_IF_EXCEPTION(scope, {}); + JSValue result = slot.getValue(globalObject, prop); + RETURN_IF_EXCEPTION(scope, {}); + + *propertyName = Bun::toString(prop.impl()); + return JSValue::encode(result); +} + +extern "C" EncodedJSValue Bun__JSPropertyIterator__getNameAndValueNonObservable(JSPropertyIterator* iter, JSC::JSGlobalObject* globalObject, JSC::JSObject* object, BunString* propertyName, size_t i) +{ + const auto& prop = iter->properties->propertyNameVector()[i]; + if (UNLIKELY(iter->isSpecialProxy)) { + return getOwnProxyObject(iter, object, prop, propertyName); + } + auto& vm = iter->vm; + auto scope = DECLARE_THROW_SCOPE(vm); + + PropertySlot slot(object, PropertySlot::InternalMethodType::VMInquiry, vm.ptr()); + if (!object->getNonIndexPropertySlot(globalObject, prop, slot)) { + return {}; + } + RETURN_IF_EXCEPTION(scope, {}); + + if (slot.isAccessor() || slot.isCustom()) { + return {}; + } + + JSValue result = slot.getPureResult(); RETURN_IF_EXCEPTION(scope, {}); *propertyName = Bun::toString(prop.impl()); diff --git a/src/bun.js/bindings/JSPropertyIterator.zig b/src/bun.js/bindings/JSPropertyIterator.zig index f5361cc3ae..ff4a4e77f6 100644 --- a/src/bun.js/bindings/JSPropertyIterator.zig +++ b/src/bun.js/bindings/JSPropertyIterator.zig @@ -2,14 +2,19 @@ const bun = @import("root").bun; const JSC = bun.JSC; //extern "C" EncodedJSValue Bun__JSPropertyIterator__getNameAndValue(JSPropertyIterator* iter, JSC::JSGlobalObject* globalObject, JSC::JSObject* object, BunString* propertyName, size_t i) -extern "C" fn Bun__JSPropertyIterator__create(globalObject: *JSC.JSGlobalObject, encodedValue: JSC.JSValue, *usize) ?*anyopaque; +extern "C" fn Bun__JSPropertyIterator__create(globalObject: *JSC.JSGlobalObject, encodedValue: JSC.JSValue, *usize, own_properties_only: bool, only_non_index_properties: bool) ?*anyopaque; extern "C" fn Bun__JSPropertyIterator__getNameAndValue(iter: ?*anyopaque, globalObject: *JSC.JSGlobalObject, object: *anyopaque, propertyName: *bun.String, i: usize) JSC.JSValue; +extern "C" fn Bun__JSPropertyIterator__getNameAndValueNonObservable(iter: ?*anyopaque, globalObject: *JSC.JSGlobalObject, object: *anyopaque, propertyName: *bun.String, i: usize) JSC.JSValue; extern "C" fn Bun__JSPropertyIterator__getName(iter: ?*anyopaque, propertyName: *bun.String, i: usize) void; extern "C" fn Bun__JSPropertyIterator__deinit(iter: ?*anyopaque) void; +extern "C" fn Bun__JSPropertyIterator__getLongestPropertyName(iter: ?*anyopaque, globalObject: *JSC.JSGlobalObject, object: *anyopaque) usize; pub const JSPropertyIteratorOptions = struct { skip_empty_name: bool, include_value: bool, + own_properties_only: bool = true, + observable: bool = true, + only_non_index_properties: bool = false, }; pub fn JSPropertyIterator(comptime options: JSPropertyIteratorOptions) type { @@ -23,6 +28,11 @@ pub fn JSPropertyIterator(comptime options: JSPropertyIteratorOptions) type { object: *JSC.JSCell = undefined, value: JSC.JSValue = .zero, + pub fn getLongestPropertyName(this: *@This()) usize { + if (this.impl == null) return 0; + return Bun__JSPropertyIterator__getLongestPropertyName(this.impl, this.globalObject, this.object); + } + pub fn deinit(this: *@This()) void { if (this.impl) |impl| { Bun__JSPropertyIterator__deinit(impl); @@ -36,7 +46,7 @@ pub fn JSPropertyIterator(comptime options: JSPropertyIteratorOptions) type { .globalObject = globalObject, }; - iter.impl = Bun__JSPropertyIterator__create(globalObject, object, &iter.len); + iter.impl = Bun__JSPropertyIterator__create(globalObject, object, &iter.len, options.own_properties_only, options.only_non_index_properties); return iter; } @@ -57,7 +67,8 @@ pub fn JSPropertyIterator(comptime options: JSPropertyIteratorOptions) type { this.iter_i += 1; var name = bun.String.dead; if (comptime options.include_value) { - const current = Bun__JSPropertyIterator__getNameAndValue(this.impl, this.globalObject, this.object, &name, i); + const FnToUse = if (options.observable) Bun__JSPropertyIterator__getNameAndValue else Bun__JSPropertyIterator__getNameAndValueNonObservable; + const current = FnToUse(this.impl, this.globalObject, this.object, &name, i); if (current == .zero) { return this.next(); } diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index cb1a0446df..45fb786707 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -1,5 +1,7 @@ + #include "root.h" +#include "JavaScriptCore/CatchScope.h" #include "JavaScriptCore/Exception.h" #include "ErrorCode+List.h" #include "ErrorCode.h" @@ -64,6 +66,7 @@ #include "wtf/Assertions.h" #include "wtf/Compiler.h" +#include "wtf/StackCheck.h" #include "wtf/text/ExternalStringImpl.h" #include "wtf/text/OrdinalNumber.h" #include "wtf/text/StringCommon.h" @@ -126,6 +129,8 @@ #include "ErrorStackTrace.h" #include "ObjectBindings.h" +#include + #if OS(DARWIN) #if BUN_DEBUG #include @@ -5362,6 +5367,12 @@ bool JSC__JSValue__toBoolean(JSC__JSValue JSValue0) return JSValue::decode(JSValue0).pureToBoolean() != TriState::False; } +extern "C" void JSGlobalObject__throwStackOverflow(JSC__JSGlobalObject* globalObject) +{ + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + throwStackOverflowError(globalObject, scope); +} + template static void JSC__JSValue__forEachPropertyImpl(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, void* arg2, void (*iter)(JSC__JSGlobalObject* arg0, void* ctx, ZigString* arg2, JSC__JSValue JSValue3, bool isSymbol, bool isPrivateSymbol)) { @@ -5372,9 +5383,15 @@ static void JSC__JSValue__forEachPropertyImpl(JSC__JSValue JSValue0, JSC__JSGlob return; JSC::VM& vm = globalObject->vm(); - auto scope = DECLARE_CATCH_SCOPE(vm); + auto throwScope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(!vm.isSafeToRecurse())) { + throwStackOverflowError(globalObject, throwScope); + return; + } size_t prototypeCount = 0; + auto scope = DECLARE_CATCH_SCOPE(vm); JSC::Structure* structure = object->structure(); bool fast = !nonIndexedOnly && canPerformFastPropertyEnumerationForIterationBun(structure); @@ -5383,6 +5400,7 @@ static void JSC__JSValue__forEachPropertyImpl(JSC__JSValue JSValue0, JSC__JSGlob if (fast) { if (structure->outOfLineSize() == 0 && structure->inlineSize() == 0) { fast = false; + if (JSValue proto = object->getPrototype(vm, globalObject)) { if ((structure = proto.structureOrNull())) { prototypeObject = proto; @@ -5434,6 +5452,7 @@ restart: propertyValue = objectToUse->getIfPropertyExists(globalObject, prop); } + // Ignore exceptions due to getters. if (scope.exception()) scope.clearException(); @@ -5449,14 +5468,21 @@ restart: return true; iter(globalObject, arg2, &key, JSC::JSValue::encode(propertyValue), prop->isSymbol(), isPrivate); + // Propagate exceptions from callbacks. + if (UNLIKELY(scope.exception())) { + return false; + } return true; }); + + // Propagate exceptions from callbacks. if (scope.exception()) { - scope.clearException(); + return; } if (anyHits) { if (prototypeCount++ < 5) { + if (JSValue proto = prototypeObject.getPrototype(globalObject)) { if (!(proto == globalObject->objectPrototype() || proto == globalObject->functionPrototype() || (proto.inherits() && jsCast(proto)->target() != globalObject))) { if ((structure = proto.structureOrNull())) { @@ -5466,6 +5492,10 @@ restart: } } } + // Ignore exceptions from Proxy "getPrototype" trap. + if (UNLIKELY(scope.exception())) { + scope.clearException(); + } } return; } @@ -5484,7 +5514,7 @@ restart: iterating->methodTable()->getOwnPropertyNames(iterating, globalObject, properties, DontEnumPropertiesMode::Include); } - RETURN_IF_EXCEPTION(scope, ); + RETURN_IF_EXCEPTION(scope, void()); for (auto& property : properties) { if (UNLIKELY(property.isEmpty() || property.isNull())) continue; @@ -5502,6 +5532,10 @@ restart: JSC::PropertySlot slot(object, PropertySlot::InternalMethodType::Get); if (!object->getPropertySlot(globalObject, property, slot)) continue; + // Ignore exceptions from "Get" proxy traps. + if (scope.exception()) { + scope.clearException(); + } if ((slot.attributes() & PropertyAttribute::DontEnum) != 0) { if (property == propertyNames->underscoreProto @@ -5548,6 +5582,7 @@ restart: propertyValue = slot.getValue(globalObject, property); } + // Ignore exceptions from getters. if (scope.exception()) { scope.clearException(); propertyValue = jsUndefined(); @@ -5561,6 +5596,9 @@ restart: continue; iter(globalObject, arg2, &key, JSC::JSValue::encode(propertyValue), property.isSymbol(), isPrivate); + + // Propagate exceptions from callbacks. + RETURN_IF_EXCEPTION(scope, void()); } if constexpr (nonIndexedOnly) { break; diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index e79bf9799f..94a0698a29 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -3039,7 +3039,10 @@ pub const JSGlobalObject = opaque { pub fn allocator(this: *JSGlobalObject) std.mem.Allocator { return this.bunVM().allocator; } - + extern fn JSGlobalObject__throwStackOverflow(this: *JSGlobalObject) void; + pub fn throwStackOverflow(this: *JSGlobalObject) void { + JSGlobalObject__throwStackOverflow(this); + } extern fn JSGlobalObject__throwOutOfMemoryError(this: *JSGlobalObject) void; pub fn throwOutOfMemory(this: *JSGlobalObject) bun.JSError { JSGlobalObject__throwOutOfMemoryError(this); @@ -5798,10 +5801,10 @@ pub const JSValue = enum(i64) { formatter: *Exports.ConsoleObject.Formatter, ) Exports.ConsoleObject.Formatter.ZigFormatter { formatter.remaining_values = &[_]JSValue{}; - if (formatter.map_node) |node| { - node.release(); - formatter.map_node = null; + if (formatter.map_node != null) { + formatter.deinit(); } + formatter.stack_check.update(); return Exports.ConsoleObject.Formatter.ZigFormatter{ .formatter = formatter, @@ -6809,6 +6812,21 @@ pub fn toJSHostFunction(comptime Function: JSHostZigFunction) JSC.JSHostFunction error.JSError => .zero, error.OutOfMemory => globalThis.throwOutOfMemoryValue(), }; + if (comptime bun.Environment.isDebug) { + if (value != .zero) { + if (globalThis.hasException()) { + bun.Output.prettyErrorln( + \\Assertion failed: Native function returned a non-zero JSValue while an exception is pending + \\ + \\Did you forget to check if an exception is pending? + \\ + \\ if (globalThis.hasException()) return .zero; + \\ + , .{}); + Output.flush(); + } + } + } bun.assert((value == .zero) == globalThis.hasException()); return value; } diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index 586f325178..b7374f2705 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -48,6 +48,10 @@ pub const ZigGlobalObject = extern struct { worker_ptr: ?*anyopaque, ) *JSGlobalObject { const global = shim.cppFn("create", .{ console, context_id, mini_mode, eval_mode, worker_ptr }); + + // JSC might mess with the stack size. + bun.StackCheck.configureThread(); + return global; } diff --git a/src/bun.js/bindings/wtf-bindings.cpp b/src/bun.js/bindings/wtf-bindings.cpp index 52de7d5a7c..d33725bbae 100644 --- a/src/bun.js/bindings/wtf-bindings.cpp +++ b/src/bun.js/bindings/wtf-bindings.cpp @@ -1,6 +1,7 @@ #include "root.h" #include "wtf-bindings.h" - +#include +#include #include #include #include @@ -237,4 +238,16 @@ size_t toISOString(JSC::VM& vm, double date, char in[64]) return charactersWritten; } +static thread_local WTF::StackBounds stackBoundsForCurrentThread = WTF::StackBounds::emptyBounds(); + +extern "C" void Bun__StackCheck__initialize() +{ + stackBoundsForCurrentThread = WTF::StackBounds::currentThreadStackBounds(); +} + +extern "C" void* Bun__StackCheck__getMaxStack() +{ + return stackBoundsForCurrentThread.end(); +} + } diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 5db69ffbf2..b5a2aa7048 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -2916,10 +2916,17 @@ pub const VirtualMachine = struct { writer: Writer, comptime allow_side_effects: bool, ) void { + var formatter = ConsoleObject.Formatter{ + .globalThis = this.global, + .quote_strings = false, + .single_line = false, + .stack_check = bun.StackCheck.init(), + }; + defer formatter.deinit(); if (Output.enable_ansi_colors) { - this.printErrorlikeObject(exception.value(), exception, exception_list, Writer, writer, true, allow_side_effects); + this.printErrorlikeObject(exception.value(), exception, exception_list, &formatter, Writer, writer, true, allow_side_effects); } else { - this.printErrorlikeObject(exception.value(), exception, exception_list, Writer, writer, false, allow_side_effects); + this.printErrorlikeObject(exception.value(), exception, exception_list, &formatter, Writer, writer, false, allow_side_effects); } } @@ -2949,7 +2956,6 @@ pub const VirtualMachine = struct { if (result.isException(this.global.vm())) { const exception = @as(*Exception, @ptrCast(result.asVoid())); - this.printException( exception, exception_list, @@ -2957,10 +2963,17 @@ pub const VirtualMachine = struct { writer, true, ); - } else if (Output.enable_ansi_colors) { - this.printErrorlikeObject(result, null, exception_list, @TypeOf(writer), writer, true, true); } else { - this.printErrorlikeObject(result, null, exception_list, @TypeOf(writer), writer, false, true); + var formatter = ConsoleObject.Formatter{ + .globalThis = this.global, + .quote_strings = false, + .single_line = false, + .stack_check = bun.StackCheck.init(), + }; + defer formatter.deinit(); + switch (Output.enable_ansi_colors) { + inline else => |enable_colors| this.printErrorlikeObject(result, null, exception_list, &formatter, @TypeOf(writer), writer, enable_colors, true), + } } } @@ -3265,14 +3278,8 @@ pub const VirtualMachine = struct { return promise; } - pub fn printErrorLikeObjectSimple(this: *VirtualMachine, value: JSValue, writer: anytype, comptime escape_codes: bool) void { - this.printErrorlikeObject(value, null, null, @TypeOf(writer), writer, escape_codes, false); - } - pub fn printErrorLikeObjectToConsole(this: *VirtualMachine, value: JSValue) void { - switch (Output.enable_ansi_colors_stderr) { - inline else => |colors| this.printErrorLikeObjectSimple(value, Output.errorWriter(), colors), - } + this.runErrorHandler(value, null); } // When the Error-like object is one of our own, it's best to rely on the object directly instead of serializing it to a ZigException. @@ -3287,6 +3294,7 @@ pub const VirtualMachine = struct { value: JSValue, exception: ?*Exception, exception_list: ?*ExceptionList, + formatter: *ConsoleObject.Formatter, comptime Writer: type, writer: Writer, comptime allow_ansi_color: bool, @@ -3324,6 +3332,7 @@ pub const VirtualMachine = struct { const AggregateErrorIterator = struct { writer: Writer, current_exception_list: ?*ExceptionList = null, + formatter: *ConsoleObject.Formatter, pub fn iteratorWithColor(_vm: [*c]VM, globalObject: *JSGlobalObject, ctx: ?*anyopaque, nextValue: JSValue) callconv(.C) void { iterator(_vm, globalObject, nextValue, ctx.?, true); @@ -3333,10 +3342,10 @@ pub const VirtualMachine = struct { } inline fn iterator(_: [*c]VM, _: *JSGlobalObject, nextValue: JSValue, ctx: ?*anyopaque, comptime color: bool) void { const this_ = @as(*@This(), @ptrFromInt(@intFromPtr(ctx))); - VirtualMachine.get().printErrorlikeObject(nextValue, null, this_.current_exception_list, Writer, this_.writer, color, allow_side_effects); + VirtualMachine.get().printErrorlikeObject(nextValue, null, this_.current_exception_list, this_.formatter, Writer, this_.writer, color, allow_side_effects); } }; - var iter = AggregateErrorIterator{ .writer = writer, .current_exception_list = exception_list }; + var iter = AggregateErrorIterator{ .writer = writer, .current_exception_list = exception_list, .formatter = formatter }; if (comptime allow_ansi_color) { value.getErrorsProperty(this.global).forEach(this.global, &iter, AggregateErrorIterator.iteratorWithColor); } else { @@ -3348,6 +3357,7 @@ pub const VirtualMachine = struct { was_internal = this.printErrorFromMaybePrivateData( value, exception_list, + formatter, Writer, writer, allow_ansi_color, @@ -3355,10 +3365,11 @@ pub const VirtualMachine = struct { ); } - pub fn printErrorFromMaybePrivateData( + fn printErrorFromMaybePrivateData( this: *VirtualMachine, value: JSC.JSValue, exception_list: ?*ExceptionList, + formatter: *ConsoleObject.Formatter, comptime Writer: type, writer: Writer, comptime allow_ansi_color: bool, @@ -3407,6 +3418,7 @@ pub const VirtualMachine = struct { this.printErrorInstance( value, exception_list, + formatter, Writer, writer, allow_ansi_color, @@ -3748,7 +3760,7 @@ pub const VirtualMachine = struct { } } - pub fn printErrorInstance(this: *VirtualMachine, error_instance: JSValue, exception_list: ?*ExceptionList, comptime Writer: type, writer: Writer, comptime allow_ansi_color: bool, comptime allow_side_effects: bool) anyerror!void { + fn printErrorInstance(this: *VirtualMachine, error_instance: JSValue, exception_list: ?*ExceptionList, formatter: *ConsoleObject.Formatter, comptime Writer: type, writer: Writer, comptime allow_ansi_color: bool, comptime allow_side_effects: bool) anyerror!void { var exception_holder = ZigException.Holder.init(); var exception = exception_holder.zigException(); defer exception_holder.deinit(this); @@ -3920,32 +3932,6 @@ pub const VirtualMachine = struct { try this.printErrorNameAndMessage(name, message, Writer, writer, allow_ansi_color); } - var add_extra_line = false; - - const Show = struct { - system_code: bool = false, - syscall: bool = false, - errno: bool = false, - path: bool = false, - fd: bool = false, - }; - - const show = Show{ - .system_code = !exception.system_code.eql(name) and !exception.system_code.isEmpty(), - .syscall = !exception.syscall.isEmpty(), - .errno = exception.errno != 0, - .path = !exception.path.isEmpty(), - .fd = exception.fd != -1, - }; - - const extra_fields = .{ - "url", - "info", - "pkg", - "errors", - "cause", - }; - // This is usually unsafe to do, but we are protecting them each time first var errors_to_append = std.ArrayList(JSC.JSValue).init(this.allocator); defer { @@ -3955,82 +3941,146 @@ pub const VirtualMachine = struct { errors_to_append.deinit(); } - if (error_instance != .zero and error_instance.isCell() and error_instance.jsType().canGet()) { - inline for (extra_fields) |field| { - if (try error_instance.getTruthyComptime(this.global, field)) |value| { - const kind = value.jsType(); - if (kind.isStringLike()) { - if (value.toStringOrNull(this.global)) |str| { - var zig_str = str.toSlice(this.global, bun.default_allocator); - defer zig_str.deinit(); - try writer.print(comptime Output.prettyFmt(" {s}: \"{s}\"\n", allow_ansi_color), .{ field, zig_str.slice() }); - add_extra_line = true; + var saw_cause = false; + if (error_instance != .zero) { + const error_instance_type = error_instance.jsType(); + if (error_instance_type == .ErrorInstance) { + const Iterator = JSC.JSPropertyIterator(.{ + .include_value = true, + .skip_empty_name = true, + .own_properties_only = true, + .observable = false, + .only_non_index_properties = true, + }); + var iterator = Iterator.init(this.global, error_instance); + defer iterator.deinit(); + const longest_name = @min(iterator.getLongestPropertyName(), 10); + var is_first_property = true; + while (iterator.next()) |field| { + const value = iterator.value; + if (field.eqlComptime("message") or field.eqlComptime("name") or field.eqlComptime("stack")) { + continue; + } + + // We special-case the code property. Let's avoid printing it twice. + if (field.eqlComptime("code")) { + if (value.isString()) { + const str = value.toBunString(this.global); + if (!str.isEmpty()) { + if (str.eql(name)) { + continue; + } + } } - } else if (kind == .ErrorInstance and + } + + const kind = value.jsType(); + if (kind == .ErrorInstance and // avoid infinite recursion !prev_had_errors) { + if (field.eqlComptime("cause")) { + saw_cause = true; + } value.protect(); try errors_to_append.append(value); - } else if (kind.isObject() or kind.isArray()) { + } else if (kind.isObject() or kind.isArray() or value.isPrimitive() or kind.isStringLike()) { var bun_str = bun.String.empty; defer bun_str.deref(); - value.jsonStringify(this.global, 2, &bun_str); //2 - try writer.print(comptime Output.prettyFmt(" {s}: {}\n", allow_ansi_color), .{ field, bun_str }); - add_extra_line = true; + const prev_disable_inspect_custom = formatter.disable_inspect_custom; + const prev_quote_strings = formatter.quote_strings; + const prev_max_depth = formatter.max_depth; + formatter.depth += 1; + defer { + formatter.depth -= 1; + formatter.max_depth = prev_max_depth; + formatter.quote_strings = prev_quote_strings; + formatter.disable_inspect_custom = prev_disable_inspect_custom; + } + formatter.max_depth = 1; + formatter.quote_strings = true; + formatter.disable_inspect_custom = true; + + const pad_left = longest_name -| field.length(); + is_first_property = false; + try writer.writeByteNTimes(' ', pad_left); + + try writer.print(comptime Output.prettyFmt(" {}: ", allow_ansi_color), .{field}); + + // When we're printing errors for a top-level uncaught eception / rejection, suppress further errors here. + if (allow_side_effects) { + if (this.global.hasException()) { + this.global.clearException(); + } + } + + formatter.format( + JSC.Formatter.Tag.getAdvanced( + value, + this.global, + .{ .disable_inspect_custom = true, .hide_global = true }, + ), + Writer, + writer, + value, + this.global, + allow_ansi_color, + ); + + if (allow_side_effects) { + // When we're printing errors for a top-level uncaught eception / rejection, suppress further errors here. + if (this.global.hasException()) { + this.global.clearException(); + } + } else if (this.global.hasException() or formatter.failed) { + return; + } + + try writer.writeAll(comptime Output.prettyFmt(",\n", allow_ansi_color)); + } + } + + if (!is_first_property) { + try writer.writeAll("\n"); + } + } else { + // If you do reportError([1,2,3]] we should still show something at least. + const tag = JSC.Formatter.Tag.getAdvanced( + error_instance, + this.global, + .{ .disable_inspect_custom = true, .hide_global = true }, + ); + if (tag.tag != .NativeCode) { + formatter.format( + tag, + Writer, + writer, + error_instance, + this.global, + allow_ansi_color, + ); + + // Always include a newline in this case + try writer.writeAll("\n"); + } + } + + // "cause" is not enumerable, so the above loop won't see it. + if (!saw_cause and error_instance_type == .ErrorInstance) { + if (error_instance.getOwn(this.global, "cause")) |cause| { + if (cause.jsType() == .ErrorInstance) { + cause.protect(); + try errors_to_append.append(cause); } } } } - if (show.errno) { - if (show.syscall) { - try writer.writeAll(" "); - } - try writer.print(comptime Output.prettyFmt(" errno: {d}\n", allow_ansi_color), .{exception.errno}); - add_extra_line = true; - } - - if (show.system_code) { - if (show.syscall) { - try writer.writeAll(" "); - } else if (show.errno) { - try writer.writeAll(" "); - } - try writer.print(comptime Output.prettyFmt(" code: \"{}\"\n", allow_ansi_color), .{exception.system_code}); - add_extra_line = true; - } - - if (show.syscall) { - try writer.print(comptime Output.prettyFmt(" syscall: \"{}\"\n", allow_ansi_color), .{exception.syscall}); - add_extra_line = true; - } - - if (show.path) { - if (show.syscall) { - try writer.writeAll(" "); - } else if (show.errno) { - try writer.writeAll(" "); - } - try writer.print(comptime Output.prettyFmt(" path: \"{}\"\n", allow_ansi_color), .{exception.path}); - } - - if (show.fd) { - if (show.syscall) { - try writer.writeAll(" "); - } else if (show.errno) { - try writer.writeAll(" "); - } - try writer.print(comptime Output.prettyFmt(" fd: {d}\n", allow_ansi_color), .{exception.fd}); - } - - if (add_extra_line) try writer.writeAll("\n"); - try printStackTrace(@TypeOf(writer), writer, exception.stack, allow_ansi_color); for (errors_to_append.items) |err| { try writer.writeAll("\n"); - try this.printErrorInstance(err, exception_list, Writer, writer, allow_ansi_color, allow_side_effects); + try this.printErrorInstance(err, exception_list, formatter, Writer, writer, allow_ansi_color, allow_side_effects); } } diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig index dab9d40b98..8086084209 100644 --- a/src/bun.js/node/node_fs.zig +++ b/src/bun.js/node/node_fs.zig @@ -3557,10 +3557,12 @@ pub const NodeFS = struct { return Maybe(Return.CopyFile).todo(); } - var src_buf: bun.WPathBuffer = undefined; - var dest_buf: bun.WPathBuffer = undefined; - const src = strings.toWPathNormalizeAutoExtend(&src_buf, args.src.sliceZ(&this.sync_error_buf)); - const dest = strings.toWPathNormalizeAutoExtend(&dest_buf, args.dest.sliceZ(&this.sync_error_buf)); + const src_buf = bun.OSPathBufferPool.get(); + defer bun.OSPathBufferPool.put(src_buf); + const dest_buf = bun.OSPathBufferPool.get(); + defer bun.OSPathBufferPool.put(dest_buf); + const src = strings.toWPathNormalizeAutoExtend(src_buf, args.src.sliceZ(&this.sync_error_buf)); + const dest = strings.toWPathNormalizeAutoExtend(dest_buf, args.dest.sliceZ(&this.sync_error_buf)); if (windows.CopyFileW(src.ptr, dest.ptr, if (args.mode.shouldntOverwrite()) 1 else 0) == windows.FALSE) { if (ret.errnoSysP(0, .copyfile, args.src.slice())) |rest| { return shouldIgnoreEbusy(args.src, args.dest, rest); @@ -3766,11 +3768,12 @@ pub const NodeFS = struct { // TODO: verify this works correctly with unicode codepoints pub fn mkdirRecursiveImpl(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor, comptime Ctx: type, ctx: Ctx) Maybe(Return.Mkdir) { _ = flavor; - var buf: bun.OSPathBuffer = undefined; + const buf = bun.OSPathBufferPool.get(); + defer bun.OSPathBufferPool.put(buf); const path: bun.OSPathSliceZ = if (Environment.isWindows) - strings.toNTPath(&buf, args.path.slice()) + strings.toNTPath(buf, args.path.slice()) else - args.path.osPath(&buf); + args.path.osPath(buf); // TODO: remove and make it always a comptime argument return switch (args.always_return_none) { @@ -5673,7 +5676,8 @@ pub const NodeFS = struct { pub fn osPathIntoSyncErrorBufOverlap(this: *NodeFS, slice: anytype) []const u8 { if (Environment.isWindows) { - var tmp: bun.WPathBuffer = undefined; + const tmp = bun.OSPathBufferPool.get(); + defer bun.OSPathBufferPool.put(tmp); @memcpy(tmp[0..slice.len], slice); return bun.strings.fromWPath(&this.sync_error_buf, tmp[0..slice.len]); } else {} @@ -6184,8 +6188,9 @@ pub const NodeFS = struct { .err => |err| return .{ .err = err }, .result => |src_fd| src_fd, }; - var wbuf: bun.WPathBuffer = undefined; - const len = bun.windows.GetFinalPathNameByHandleW(handle.cast(), &wbuf, wbuf.len, 0); + const wbuf = bun.OSPathBufferPool.get(); + defer bun.OSPathBufferPool.put(wbuf); + const len = bun.windows.GetFinalPathNameByHandleW(handle.cast(), wbuf, wbuf.len, 0); if (len == 0) { return ret.errnoSysP(0, .copyfile, this.osPathIntoSyncErrorBuf(dest)) orelse dst_enoent_maybe; } diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index fda45fe94b..72232be196 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -1123,7 +1123,7 @@ pub const ArgumentsSlice = struct { arena: bun.ArenaAllocator = bun.ArenaAllocator.init(bun.default_allocator), all: []const JSC.JSValue, threw: bool = false, - protected: std.bit_set.IntegerBitSet(32) = std.bit_set.IntegerBitSet(32).initEmpty(), + protected: bun.bit_set.IntegerBitSet(32) = bun.bit_set.IntegerBitSet(32).initEmpty(), will_be_async: bool = false, pub fn unprotect(this: *ArgumentsSlice) void { @@ -1132,7 +1132,7 @@ pub const ArgumentsSlice = struct { while (iter.next()) |i| { JSC.C.JSValueUnprotect(ctx, this.all[i].asObjectRef()); } - this.protected = std.bit_set.IntegerBitSet(32).initEmpty(); + this.protected = bun.bit_set.IntegerBitSet(32).initEmpty(); } pub fn deinit(this: *ArgumentsSlice) void { @@ -2137,10 +2137,14 @@ pub const Process = struct { pub fn Bun__Process__editWindowsEnvVar(k: bun.String, v: bun.String) callconv(.C) void { if (k.tag == .Empty) return; const wtf1 = k.value.WTFStringImpl; - var buf1: [32768]u16 = undefined; - var buf2: [32768]u16 = undefined; + var fixed_stack_allocator = std.heap.stackFallback(1025, bun.default_allocator); + const allocator = fixed_stack_allocator.get(); + var buf1 = allocator.alloc(u16, k.utf16ByteLength() + 1) catch bun.outOfMemory(); + defer allocator.free(buf1); + var buf2 = allocator.alloc(u16, v.utf16ByteLength() + 1) catch bun.outOfMemory(); + defer allocator.free(buf2); const len1: usize = switch (wtf1.is8Bit()) { - true => bun.strings.copyLatin1IntoUTF16([]u16, &buf1, []const u8, wtf1.latin1Slice()).written, + true => bun.strings.copyLatin1IntoUTF16([]u16, buf1, []const u8, wtf1.latin1Slice()).written, false => b: { @memcpy(buf1[0..wtf1.length()], wtf1.utf16Slice()); break :b wtf1.length(); @@ -2151,7 +2155,7 @@ pub const Process = struct { if (v.tag == .Empty) break :str (&[_]u16{0})[0..0 :0]; const wtf2 = v.value.WTFStringImpl; const len2: usize = switch (wtf2.is8Bit()) { - true => bun.strings.copyLatin1IntoUTF16([]u16, &buf2, []const u8, wtf2.latin1Slice()).written, + true => bun.strings.copyLatin1IntoUTF16([]u16, buf2, []const u8, wtf2.latin1Slice()).written, false => b: { @memcpy(buf2[0..wtf2.length()], wtf2.utf16Slice()); break :b wtf2.length(); diff --git a/src/bun.js/web_worker.zig b/src/bun.js/web_worker.zig index 6fcb6eed62..506d818dc3 100644 --- a/src/bun.js/web_worker.zig +++ b/src/bun.js/web_worker.zig @@ -513,15 +513,18 @@ pub const WebWorker = struct { if (loop) |loop_| { loop_.internal_loop_data.jsc_vm = null; } + bun.uws.onThreadExit(); this.deinit(); if (vm_to_deinit) |vm| { vm.deinit(); // NOTE: deinit here isn't implemented, so freeing workers will leak the vm. } + bun.deleteAllPoolsForThreadExit(); if (arena) |*arena_| { arena_.deinit(); } + bun.exitThread(); } diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index 165190e6be..d4f61a5c14 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -1996,7 +1996,7 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type { // TODO: make this JSGlobalObject local // for better security -const ByteListPool = ObjectPool( +pub const ByteListPool = ObjectPool( bun.ByteList, null, true, @@ -2588,7 +2588,12 @@ pub fn HTTPServerWritable(comptime ssl: bool) type { if (this.pooled_buffer) |pooled| { this.buffer.len = 0; + if (this.buffer.cap > 64 * 1024) { + this.buffer.deinitWithAllocator(bun.default_allocator); + this.buffer = bun.ByteList.init(""); + } pooled.data = this.buffer; + this.buffer = bun.ByteList.init(""); this.pooled_buffer = null; pooled.release(); diff --git a/src/bun.zig b/src/bun.zig index 9c37bf8854..b96006c618 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -3229,6 +3229,19 @@ pub fn exitThread() noreturn { } } +pub fn deleteAllPoolsForThreadExit() void { + const pools_to_delete = .{ + JSC.WebCore.ByteListPool, + bun.WPathBufferPool, + bun.PathBufferPool, + bun.JSC.ConsoleObject.Formatter.Visited.Pool, + bun.js_parser.StringVoidMap.Pool, + }; + inline for (pools_to_delete) |pool| { + pool.deleteAll(); + } +} + pub const Tmpfile = @import("./tmp.zig").Tmpfile; pub const io = @import("./io/io.zig"); @@ -4122,3 +4135,81 @@ pub inline fn isComptimeKnown(x: anytype) bool { pub inline fn itemOrNull(comptime T: type, slice: []const T, index: usize) ?T { return if (index < slice.len) slice[index] else null; } + +/// To handle stack overflows: +/// 1. StackCheck.init() +/// 2. .isSafeToRecurse() +pub const StackCheck = struct { + cached_stack_end: usize = 0, + + extern fn Bun__StackCheck__initialize() void; + pub fn configureThread() void { + Bun__StackCheck__initialize(); + } + + extern "C" fn Bun__StackCheck__getMaxStack() usize; + fn getStackEnd() usize { + return Bun__StackCheck__getMaxStack(); + } + + pub fn init() StackCheck { + return StackCheck{ .cached_stack_end = getStackEnd() }; + } + + pub fn update(this: *StackCheck) void { + this.cached_stack_end = getStackEnd(); + } + + /// Is there at least 128 KB of stack space available? + pub fn isSafeToRecurse(this: StackCheck) bool { + const stack_ptr: usize = @frameAddress(); + const remaining_stack = stack_ptr -| this.cached_stack_end; + return remaining_stack > 1024 * if (Environment.isWindows) 256 else 128; + } +}; + +// Workaround for lack of branch hints. +pub noinline fn throwStackOverflow() StackOverflow!void { + @setCold(true); + return error.StackOverflow; +} +const StackOverflow = error{StackOverflow}; + +// This pool exists because on Windows, each path buffer costs 64 KB. +// This makes the stack memory usage very unpredictable, which means we can't really know how much stack space we have left. +// This pool is a workaround to make the stack memory usage more predictable. +// We keep up to 4 path buffers alive per thread at a time. +pub fn PathBufferPoolT(comptime T: type) type { + return struct { + const Pool = ObjectPool(PathBuf, null, true, 4); + pub const PathBuf = struct { + bytes: T, + + pub fn deinit(this: *PathBuf) void { + var node: *Pool.Node = @alignCast(@fieldParentPtr("data", this)); + node.release(); + } + }; + + pub fn get() *T { + // use a threadlocal allocator so mimalloc deletes it on thread deinit. + return &Pool.get(bun.threadlocalAllocator()).data.bytes; + } + + pub fn put(buffer: *T) void { + var path_buf: *PathBuf = @alignCast(@fieldParentPtr("bytes", buffer)); + path_buf.deinit(); + } + + pub fn deleteAll() void { + Pool.deleteAll(); + } + }; +} + +pub const PathBufferPool = PathBufferPoolT(bun.PathBuffer); +pub const WPathBufferPool = if (Environment.isWindows) PathBufferPoolT(bun.WPathBuffer) else struct { + // So it can be used in code that deletes all the pools. + pub fn deleteAll() void {} +}; +pub const OSPathBufferPool = if (Environment.isWindows) WPathBufferPool else PathBufferPool; diff --git a/src/hive_array.zig b/src/hive_array.zig index c3479da816..fd9085b035 100644 --- a/src/hive_array.zig +++ b/src/hive_array.zig @@ -11,7 +11,7 @@ pub fn HiveArray(comptime T: type, comptime capacity: u16) type { return struct { const Self = @This(); buffer: [capacity]T = undefined, - available: std.bit_set.IntegerBitSet(capacity) = std.bit_set.IntegerBitSet(capacity).initFull(), + available: bun.bit_set.IntegerBitSet(capacity) = bun.bit_set.IntegerBitSet(capacity).initFull(), pub const size = capacity; pub fn init() Self { diff --git a/src/http/websocket_http_client.zig b/src/http/websocket_http_client.zig index 36fbf8d445..d93e2aff46 100644 --- a/src/http/websocket_http_client.zig +++ b/src/http/websocket_http_client.zig @@ -204,12 +204,6 @@ const CppWebSocket = opaque { } }; -const body_buf_len = 16384 - 16; -const BodyBufBytes = [body_buf_len]u8; - -const BodyBufPool = ObjectPool(BodyBufBytes, null, true, 4); -const BodyBuf = BodyBufPool.Node; - pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { return struct { pub const Socket = uws.NewSocketHandler(ssl); diff --git a/src/install/semver.zig b/src/install/semver.zig index e371344c66..d03e65ae78 100644 --- a/src/install/semver.zig +++ b/src/install/semver.zig @@ -2241,7 +2241,7 @@ pub const Query = struct { }; } - pub const FlagsBitSet = std.bit_set.IntegerBitSet(3); + pub const FlagsBitSet = bun.bit_set.IntegerBitSet(3); pub fn isExact(this: *const Group) bool { return this.head.next == null and this.head.head.next == null and !this.head.head.range.hasRight() and this.head.head.range.left.op == .eql; diff --git a/src/js/builtins/shell.ts b/src/js/builtins/shell.ts index 28774036ac..2c3a1db28e 100644 --- a/src/js/builtins/shell.ts +++ b/src/js/builtins/shell.ts @@ -25,18 +25,25 @@ export function createBunShellTemplateFunction(createShellInterpreter, createPar this.#output = output; this.name = "ShellError"; - // Maybe we should just print all the properties on the Error instance - // instead of speical ones - this.info = { - exitCode: code, - stderr: output.stderr, - stdout: output.stdout, - }; + // We previously added this so that errors would display the "info" property + // We fixed that, but now it displays both. + Object.defineProperty(this, "info", { + value: { + exitCode: code, + stderr: output.stderr, + stdout: output.stdout, + }, + writable: true, + enumerable: false, + configurable: true, + }); this.info.stdout.toJSON = lazyBufferToHumanReadableString; this.info.stderr.toJSON = lazyBufferToHumanReadableString; - Object.assign(this, this.info); + this.stdout = output.stdout; + this.stderr = output.stderr; + this.exitCode = code; } text(encoding) { diff --git a/src/js_lexer.zig b/src/js_lexer.zig index de7cfc2283..a052e9ef05 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -2143,7 +2143,7 @@ fn NewLexer_( const flag_characters = "dgimsuvy"; const min_flag = comptime std.mem.min(u8, flag_characters); const max_flag = comptime std.mem.max(u8, flag_characters); - const RegexpFlags = std.bit_set.IntegerBitSet((max_flag - min_flag) + 1); + const RegexpFlags = bun.bit_set.IntegerBitSet((max_flag - min_flag) + 1); var flags = RegexpFlags.initEmpty(); while (isIdentifierContinue(lexer.code_point)) { switch (lexer.code_point) { diff --git a/src/js_lexer/identifier_data.zig b/src/js_lexer/identifier_data.zig index d82751e620..1c98ac2503 100644 --- a/src/js_lexer/identifier_data.zig +++ b/src/js_lexer/identifier_data.zig @@ -57,8 +57,9 @@ const id_end_range: [2]i32 = brk: { const id_end_count = id_end_range[1] - id_end_range[0] + 1; -pub const IDStartType = std.bit_set.StaticBitSet(id_start_count + 1); -pub const IDContinueType = std.bit_set.StaticBitSet(id_end_count + 1); +// Do not use std.bit_set. +pub const IDStartType = @import("../bit_set.zig").StaticBitSet(id_start_count + 1); +pub const IDContinueType = @import("../bit_set.zig").StaticBitSet(id_end_count + 1); pub const id_start: IDStartType = brk: { var bits: IDStartType = IDStartType.initEmpty(); diff --git a/src/js_parser.zig b/src/js_parser.zig index d225194424..cc8fec29c6 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -197,17 +197,6 @@ const MacroRefData = struct { const MacroRefs = std.AutoArrayHashMap(Ref, MacroRefData); -pub const AllocatedNamesPool = ObjectPool( - std.ArrayList(string), - struct { - pub fn init(allocator: std.mem.Allocator) anyerror!std.ArrayList(string) { - return std.ArrayList(string).init(allocator); - } - }.init, - true, - 4, -); - const Substitution = union(enum) { success: Expr, failure: Expr, @@ -2611,7 +2600,7 @@ const StmtList = ListManaged(Stmt); // This hash table is used every time we parse function args // Rather than allocating a new hash table each time, we can just reuse the previous allocation -const StringVoidMap = struct { +pub const StringVoidMap = struct { allocator: Allocator, map: bun.StringHashMapUnmanaged(void) = bun.StringHashMapUnmanaged(void){}, @@ -2980,7 +2969,14 @@ pub const Parser = struct { // Which makes sense. // June 4: "Parsing took: 18028000" // June 4: "Rest of this took: 8003000" - _ = try p.parseStmtsUpTo(js_lexer.T.t_end_of_file, &opts); + _ = p.parseStmtsUpTo(js_lexer.T.t_end_of_file, &opts) catch |err| { + if (err == error.StackOverflow) { + // The lexer location won't be totally accurate, but it's kind of helpful. + try p.log.addError(p.source, p.lexer.loc(), "Maximum call stack size exceeded"); + return; + } + return err; + }; // if (comptime ParserType.parser_features.typescript) { @@ -3255,7 +3251,18 @@ pub const Parser = struct { // Which makes sense. // June 4: "Parsing took: 18028000" // June 4: "Rest of this took: 8003000" - const stmts = try p.parseStmtsUpTo(js_lexer.T.t_end_of_file, &opts); + const stmts = p.parseStmtsUpTo(js_lexer.T.t_end_of_file, &opts) catch |err| { + parse_tracer.end(); + if (err == error.StackOverflow) { + // The lexer location won't be totally accurate, but it's kind of helpful. + try p.log.addError(p.source, p.lexer.loc(), "Maximum call stack size exceeded"); + + // Return a SyntaxError so that we reuse existing code for handling erorrs. + return error.SyntaxError; + } + + return err; + }; parse_tracer.end(); @@ -4812,6 +4819,8 @@ fn NewParser_( /// Used by commonjs_at_runtime has_commonjs_export_names: bool = false, + stack_check: bun.StackCheck, + /// When this flag is enabled, we attempt to fold all expressions that /// TypeScript would consider to be "constant expressions". This flag is /// enabled inside each enum body block since TypeScript requires numeric @@ -9495,6 +9504,10 @@ fn NewParser_( } fn parseStmt(p: *P, opts: *ParseStatementOptions) anyerror!Stmt { + if (!p.stack_check.isSafeToRecurse()) { + try bun.throwStackOverflow(); + } + const loc = p.lexer.loc(); switch (p.lexer.token) { @@ -13035,7 +13048,11 @@ fn NewParser_( return try p.parseExprCommon(level, null, flags); } - pub fn parseExprCommon(p: *P, level: Level, errors: ?*DeferredErrors, flags: Expr.EFlags) anyerror!Expr { + fn parseExprCommon(p: *P, level: Level, errors: ?*DeferredErrors, flags: Expr.EFlags) anyerror!Expr { + if (!p.stack_check.isSafeToRecurse()) { + try bun.throwStackOverflow(); + } + const had_pure_comment_before = p.lexer.has_pure_comment_before and !p.options.ignore_dce_annotations; var expr = try p.parsePrefix(level, errors, flags); @@ -23717,6 +23734,7 @@ fn NewParser_( .named_imports = undefined, .named_exports = .{}, .log = log, + .stack_check = bun.StackCheck.init(), .allocator = allocator, .options = opts, .then_catch_chain = ThenCatchChain{ .next_target = nullExprData }, diff --git a/src/main.zig b/src/main.zig index 9c4df6072f..d3b73b7ee5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -44,7 +44,7 @@ pub fn main() void { if (Environment.isX64 and Environment.enableSIMD and Environment.isPosix) { bun_warn_avx_missing(@import("./cli/upgrade_command.zig").Version.Bun__githubBaselineURL.ptr); } - + bun.StackCheck.configureThread(); bun.CLI.Cli.start(bun.default_allocator); bun.Global.exit(0); } diff --git a/src/output.zig b/src/output.zig index ec0b60ac21..29fb3019d2 100644 --- a/src/output.zig +++ b/src/output.zig @@ -88,6 +88,7 @@ pub const Source = struct { if (source_set) return; bun.debugAssert(stdout_stream_set); source = Source.init(stdout_stream, stderr_stream); + bun.StackCheck.configureThread(); } pub fn configureNamedThread(name: StringTypes.stringZ) void { diff --git a/src/patch.zig b/src/patch.zig index 55b5780a3b..363184f47e 100644 --- a/src/patch.zig +++ b/src/patch.zig @@ -915,7 +915,7 @@ const PatchLinesParser = struct { fn parseHunkHeaderLineImpl(text_: []const u8) ParseErr!struct { line_nr: u32, line_count: u32, rest: []const u8 } { var text = text_; const DIGITS = brk: { - var set = std.bit_set.IntegerBitSet(256).initEmpty(); + var set = bun.bit_set.IntegerBitSet(256).initEmpty(); for ('0'..'9' + 1) |c| set.set(c); break :brk set; }; @@ -1026,8 +1026,8 @@ const PatchLinesParser = struct { const delimiter_start = std.mem.indexOf(u8, line, "..") orelse return null; - const VALID_CHARS: std.bit_set.IntegerBitSet(256) = comptime brk: { - var bitset = std.bit_set.IntegerBitSet(256).initEmpty(); + const VALID_CHARS: bun.bit_set.IntegerBitSet(256) = comptime brk: { + var bitset = bun.bit_set.IntegerBitSet(256).initEmpty(); // TODO: the regex uses \w which is [a-zA-Z0-9_] for ('0'..'9' + 1) |c| bitset.set(c); for ('a'..'z' + 1) |c| bitset.set(c); diff --git a/src/pool.zig b/src/pool.zig index 7d994c752f..30e5d3e31f 100644 --- a/src/pool.zig +++ b/src/pool.zig @@ -233,5 +233,21 @@ pub fn ObjectPool( data().list = LinkedList{ .first = node }; data().loaded = true; } + + pub fn deleteAll() void { + var dat = data(); + if (!dat.loaded) { + return; + } + dat.loaded = false; + dat.count = 0; + var next = dat.list.first; + dat.list.first = null; + while (next) |node| { + next = node.next; + if (std.meta.hasFn(Type, "deinit")) node.data.deinit(); + node.allocator.destroy(node); + } + } }; } diff --git a/src/shell/interpreter.zig b/src/shell/interpreter.zig index 76b94c04d0..58a3a915f7 100644 --- a/src/shell/interpreter.zig +++ b/src/shell/interpreter.zig @@ -1323,8 +1323,10 @@ pub const Interpreter = struct { break :brk export_env; }; - var pathbuf: bun.PathBuffer = undefined; - const cwd: [:0]const u8 = switch (Syscall.getcwdZ(&pathbuf)) { + // Avoid the large stack allocation on Windows. + const pathbuf = bun.default_allocator.create(bun.PathBuffer) catch bun.outOfMemory(); + defer bun.default_allocator.destroy(pathbuf); + const cwd: [:0]const u8 = switch (Syscall.getcwdZ(pathbuf)) { .result => |cwd| cwd, .err => |err| { return .{ .err = .{ .sys = err.toSystemError() } }; @@ -4883,8 +4885,9 @@ pub const Interpreter = struct { return; } - var path_buf: bun.PathBuffer = undefined; - const resolved = which(&path_buf, spawn_args.PATH, spawn_args.cwd, first_arg_real) orelse blk: { + const path_buf = bun.PathBufferPool.get(); + defer bun.PathBufferPool.put(path_buf); + const resolved = which(path_buf, spawn_args.PATH, spawn_args.cwd, first_arg_real) orelse blk: { if (bun.strings.eqlComptime(first_arg_real, "bun") or bun.strings.eqlComptime(first_arg_real, "bun-debug")) blk2: { break :blk bun.selfExePath() catch break :blk2; } @@ -7158,12 +7161,13 @@ pub const Interpreter = struct { } if (this.bltn.stdout.needsIO() == null) { - var path_buf: bun.PathBuffer = undefined; + const path_buf = bun.PathBufferPool.get(); + defer bun.PathBufferPool.put(path_buf); const PATH = this.bltn.parentCmd().base.shell.export_env.get(EnvStr.initSlice("PATH")) orelse EnvStr.initSlice(""); var had_not_found = false; for (args) |arg_raw| { const arg = arg_raw[0..std.mem.len(arg_raw)]; - const resolved = which(&path_buf, PATH.slice(), this.bltn.parentCmd().base.shell.cwdZ(), arg) orelse { + const resolved = which(path_buf, PATH.slice(), this.bltn.parentCmd().base.shell.cwdZ(), arg) orelse { had_not_found = true; const buf = this.bltn.fmtErrorArena(.which, "{s} not found\n", .{arg}); _ = this.bltn.writeNoIO(.stdout, buf); @@ -7198,10 +7202,11 @@ pub const Interpreter = struct { const arg_raw = multiargs.args_slice[multiargs.arg_idx]; const arg = arg_raw[0..std.mem.len(arg_raw)]; - var path_buf: bun.PathBuffer = undefined; + const path_buf = bun.PathBufferPool.get(); + defer bun.PathBufferPool.put(path_buf); const PATH = this.bltn.parentCmd().base.shell.export_env.get(EnvStr.initSlice("PATH")) orelse EnvStr.initSlice(""); - const resolved = which(&path_buf, PATH.slice(), this.bltn.parentCmd().base.shell.cwdZ(), arg) orelse { + const resolved = which(path_buf, PATH.slice(), this.bltn.parentCmd().base.shell.cwdZ(), arg) orelse { multiargs.had_not_found = true; if (this.bltn.stdout.needsIO()) |safeguard| { multiargs.state = .waiting_write; diff --git a/src/shell/shell.zig b/src/shell/shell.zig index cd63bf4201..ae35c27140 100644 --- a/src/shell/shell.zig +++ b/src/shell/shell.zig @@ -3987,8 +3987,8 @@ pub const ShellSrcBuilder = struct { /// Characters that need to escaped const SPECIAL_CHARS = [_]u8{ '~', '[', ']', '#', ';', '\n', '*', '{', ',', '}', '`', '$', '=', '(', ')', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '|', '>', '<', '&', '\'', '"', ' ', '\\' }; -const SPECIAL_CHARS_TABLE: std.bit_set.IntegerBitSet(256) = brk: { - var table = std.bit_set.IntegerBitSet(256).initEmpty(); +const SPECIAL_CHARS_TABLE: bun.bit_set.IntegerBitSet(256) = brk: { + var table = bun.bit_set.IntegerBitSet(256).initEmpty(); for (SPECIAL_CHARS) |c| { table.set(c); } diff --git a/src/string.zig b/src/string.zig index e4497381d1..30bc054a53 100644 --- a/src/string.zig +++ b/src/string.zig @@ -197,6 +197,14 @@ pub const WTFStringImplStruct = extern struct { return this.is8Bit() and bun.strings.isAllASCII(this.latin1Slice()); } + pub fn utf16ByteLength(this: WTFStringImpl) usize { + if (this.is8Bit()) { + return this.length() * 2; + } else { + return this.length(); + } + } + pub fn utf8ByteLength(this: WTFStringImpl) usize { if (this.is8Bit()) { const input = this.latin1Slice(); @@ -207,11 +215,6 @@ pub const WTFStringImplStruct = extern struct { } } - pub fn utf16ByteLength(this: WTFStringImpl) usize { - // All latin1 characters fit in a single UTF-16 code unit. - return this.length() * 2; - } - pub fn latin1ByteLength(this: WTFStringImpl) usize { // Not all UTF-16 characters fit are representable in latin1. // Those get truncated? diff --git a/src/string_immutable.zig b/src/string_immutable.zig index 2517480e98..ab1d796490 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -1949,9 +1949,10 @@ pub fn toWPathNormalizeAutoExtend(wbuf: []u16, utf8: []const u8) [:0]const u16 { } pub fn toWPathNormalized(wbuf: []u16, utf8: []const u8) [:0]const u16 { - var renormalized: bun.PathBuffer = undefined; + const renormalized = bun.PathBufferPool.get(); + defer bun.PathBufferPool.put(renormalized); - var path_to_use = normalizeSlashesOnly(&renormalized, utf8, '\\'); + var path_to_use = normalizeSlashesOnly(renormalized, utf8, '\\'); // is there a trailing slash? Let's remove it before converting to UTF-16 if (path_to_use.len > 3 and bun.path.isSepAny(path_to_use[path_to_use.len - 1])) { @@ -1961,9 +1962,10 @@ pub fn toWPathNormalized(wbuf: []u16, utf8: []const u8) [:0]const u16 { return toWPath(wbuf, path_to_use); } pub fn toPathNormalized(buf: []u8, utf8: []const u8) [:0]const u8 { - var renormalized: bun.PathBuffer = undefined; + const renormalized = bun.PathBufferPool.get(); + defer bun.PathBufferPool.put(renormalized); - var path_to_use = normalizeSlashesOnly(&renormalized, utf8, '\\'); + var path_to_use = normalizeSlashesOnly(renormalized, utf8, '\\'); // is there a trailing slash? Let's remove it before converting to UTF-16 if (path_to_use.len > 3 and bun.path.isSepAny(path_to_use[path_to_use.len - 1])) { @@ -1991,17 +1993,20 @@ pub fn normalizeSlashesOnly(buf: []u8, utf8: []const u8, comptime desired_slash: } pub fn toWDirNormalized(wbuf: []u16, utf8: []const u8) [:0]const u16 { - var renormalized: bun.PathBuffer = undefined; + var renormalized: ?*bun.PathBuffer = null; + defer if (renormalized) |r| bun.PathBufferPool.put(r); + var path_to_use = utf8; if (bun.strings.containsChar(utf8, '/')) { - @memcpy(renormalized[0..utf8.len], utf8); - for (renormalized[0..utf8.len]) |*c| { + renormalized = bun.PathBufferPool.get(); + @memcpy(renormalized.?[0..utf8.len], utf8); + for (renormalized.?[0..utf8.len]) |*c| { if (c.* == '/') { c.* = '\\'; } } - path_to_use = renormalized[0..utf8.len]; + path_to_use = renormalized.?[0..utf8.len]; } return toWDirPath(wbuf, path_to_use); diff --git a/src/sys.zig b/src/sys.zig index 179ed41fec..33e98c14de 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -466,8 +466,9 @@ pub fn getcwdZ(buf: *bun.PathBuffer) Maybe([:0]const u8) { buf[0] = 0; if (comptime Environment.isWindows) { - var wbuf: bun.WPathBuffer = undefined; - const len: windows.DWORD = kernel32.GetCurrentDirectoryW(wbuf.len, &wbuf); + var wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); + const len: windows.DWORD = kernel32.GetCurrentDirectoryW(wbuf.len, wbuf); if (Result.errnoSys(len, .getcwd)) |err| return err; return Result{ .result = bun.strings.fromWPath(buf, wbuf[0..len]) }; } @@ -555,8 +556,9 @@ pub fn chdir(destination: anytype) Maybe(void) { return chdirOSPath(@as(bun.OSPathSliceZ, destination)); } - var wbuf: bun.WPathBuffer = undefined; - return chdirOSPath(bun.strings.toWDirPath(&wbuf, destination)); + const wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); + return chdirOSPath(bun.strings.toWDirPath(wbuf, destination)); } return Maybe(void).todo(); @@ -626,8 +628,9 @@ pub fn fstat(fd: bun.FileDescriptor) Maybe(bun.Stat) { } pub fn mkdiratA(dir_fd: bun.FileDescriptor, file_path: []const u8) Maybe(void) { - var buf: bun.WPathBuffer = undefined; - return mkdiratW(dir_fd, bun.strings.toWPathNormalized(&buf, file_path)); + const buf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(buf); + return mkdiratW(dir_fd, bun.strings.toWPathNormalized(buf, file_path)); } pub fn mkdiratZ(dir_fd: bun.FileDescriptor, file_path: [*:0]const u8, mode: mode_t) Maybe(void) { @@ -688,9 +691,10 @@ pub fn mkdir(file_path: [:0]const u8, flags: bun.Mode) Maybe(void) { .linux => Maybe(void).errnoSysP(syscall.mkdir(file_path, flags), .mkdir, file_path) orelse Maybe(void).success, .windows => { - var wbuf: bun.WPathBuffer = undefined; + const wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); return Maybe(void).errnoSysP( - kernel32.CreateDirectoryW(bun.strings.toWPath(&wbuf, file_path).ptr, null), + kernel32.CreateDirectoryW(bun.strings.toWPath(wbuf, file_path).ptr, null), .mkdir, file_path, ) orelse Maybe(void).success; @@ -720,8 +724,9 @@ pub fn mkdirA(file_path: []const u8, flags: bun.Mode) Maybe(void) { } if (comptime Environment.isWindows) { - var wbuf: bun.WPathBuffer = undefined; - const wpath = bun.strings.toWPath(&wbuf, file_path); + const wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); + const wpath = bun.strings.toWPath(wbuf, file_path); assertIsValidWindowsPath(u16, wpath); return Maybe(void).errnoSysP( kernel32.CreateDirectoryW(wpath.ptr, null), @@ -792,8 +797,9 @@ pub fn normalizePathWindows( if (comptime T != u8 and T != u16) { @compileError("normalizePathWindows only supports u8 and u16 character types"); } - var wbuf: if (T == u16) void else bun.WPathBuffer = undefined; - var path = if (T == u16) path_ else bun.strings.convertUTF8toUTF16InBuffer(&wbuf, path_); + const wbuf = if (T != u16) bun.WPathBufferPool.get() else {}; + defer if (T != u16) bun.WPathBufferPool.put(wbuf); + var path = if (T == u16) path_ else bun.strings.convertUTF8toUTF16InBuffer(wbuf, path_); if (std.fs.path.isAbsoluteWindowsWTF16(path)) { // handle the special "nul" device @@ -845,7 +851,8 @@ pub fn normalizePathWindows( path = path[2..]; } - var buf1: bun.WPathBuffer = undefined; + const buf1 = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(buf1); @memcpy(buf1[0..base_path.len], base_path); buf1[base_path.len] = '\\'; @memcpy(buf1[base_path.len + 1 .. base_path.len + 1 + path.len], path); @@ -964,9 +971,10 @@ fn openDirAtWindowsT( path: []const T, options: WindowsOpenDirOptions, ) Maybe(bun.FileDescriptor) { - var wbuf: bun.WPathBuffer = undefined; + const wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); - const norm = switch (normalizePathWindows(T, dirFd, path, &wbuf)) { + const norm = switch (normalizePathWindows(T, dirFd, path, wbuf)) { .err => |err| return .{ .err = err }, .result => |norm| norm, }; @@ -1157,9 +1165,10 @@ pub fn openFileAtWindowsT( disposition: w.ULONG, options: w.ULONG, ) Maybe(bun.FileDescriptor) { - var wbuf: bun.WPathBuffer = undefined; + const wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); - const norm = switch (normalizePathWindows(T, dirFd, path, &wbuf)) { + const norm = switch (normalizePathWindows(T, dirFd, path, wbuf)) { .err => |err| return .{ .err = err }, .result => |norm| norm, }; @@ -1974,14 +1983,18 @@ pub fn renameat2(from_dir: bun.FileDescriptor, from: [:0]const u8, to_dir: bun.F pub fn renameat(from_dir: bun.FileDescriptor, from: [:0]const u8, to_dir: bun.FileDescriptor, to: [:0]const u8) Maybe(void) { if (Environment.isWindows) { - var w_buf_from: bun.WPathBuffer = undefined; - var w_buf_to: bun.WPathBuffer = undefined; + const w_buf_from = bun.WPathBufferPool.get(); + const w_buf_to = bun.WPathBufferPool.get(); + defer { + bun.WPathBufferPool.put(w_buf_from); + bun.WPathBufferPool.put(w_buf_to); + } const rc = bun.C.renameAtW( from_dir, - bun.strings.toNTPath(&w_buf_from, from), + bun.strings.toNTPath(w_buf_from, from), to_dir, - bun.strings.toNTPath(&w_buf_to, to), + bun.strings.toNTPath(w_buf_to, to), true, ); @@ -2053,10 +2066,14 @@ pub fn symlinkOrJunction(dest: [:0]const u8, target: [:0]const u8) Maybe(void) { if (comptime !Environment.isWindows) @compileError("symlinkOrJunction is windows only"); if (!WindowsSymlinkOptions.has_failed_to_create_symlink) { - var sym16: bun.WPathBuffer = undefined; - var target16: bun.WPathBuffer = undefined; - const sym_path = bun.strings.toWPathNormalizeAutoExtend(&sym16, dest); - const target_path = bun.strings.toWPathNormalizeAutoExtend(&target16, target); + const sym16 = bun.WPathBufferPool.get(); + const target16 = bun.WPathBufferPool.get(); + defer { + bun.WPathBufferPool.put(sym16); + bun.WPathBufferPool.put(target16); + } + const sym_path = bun.strings.toWPathNormalizeAutoExtend(sym16, dest); + const target_path = bun.strings.toWPathNormalizeAutoExtend(target16, target); switch (symlinkW(sym_path, target_path, .{ .directory = true })) { .result => { return Maybe(void).success; @@ -2163,8 +2180,9 @@ pub fn unlinkW(from: [:0]const u16) Maybe(void) { pub fn unlink(from: [:0]const u8) Maybe(void) { if (comptime Environment.isWindows) { - var w_buf: bun.WPathBuffer = undefined; - return unlinkW(bun.strings.toNTPath(&w_buf, from)); + const w_buf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(w_buf); + return unlinkW(bun.strings.toNTPath(w_buf, from)); } while (true) { @@ -2185,8 +2203,9 @@ pub fn rmdirat(dirfd: bun.FileDescriptor, to: anytype) Maybe(void) { pub fn unlinkatWithFlags(dirfd: bun.FileDescriptor, to: anytype, flags: c_uint) Maybe(void) { if (Environment.isWindows) { if (comptime std.meta.Elem(@TypeOf(to)) == u8) { - var w_buf: bun.WPathBuffer = undefined; - return unlinkatWithFlags(dirfd, bun.strings.toNTPath(&w_buf, bun.span(to)), flags); + const w_buf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(w_buf); + return unlinkatWithFlags(dirfd, bun.strings.toNTPath(w_buf, bun.span(to)), flags); } return bun.windows.DeleteFileBun(to, .{ @@ -2599,8 +2618,9 @@ pub fn getFileAttributes(path: anytype) ?WindowsFileAttributes { const attributes: WindowsFileAttributes = @bitCast(dword); return attributes; } else { - var wbuf: bun.WPathBuffer = undefined; - const path_to_use = bun.strings.toWPath(&wbuf, path); + const wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); + const path_to_use = bun.strings.toWPath(wbuf, path); return getFileAttributes(path_to_use); } } @@ -2678,8 +2698,9 @@ pub fn faccessat(dir_: anytype, subpath: anytype) JSC.Maybe(bool) { pub fn directoryExistsAt(dir_: anytype, subpath: anytype) JSC.Maybe(bool) { const dir_fd = bun.toFD(dir_); if (comptime Environment.isWindows) { - var wbuf: bun.WPathBuffer = undefined; - const path = bun.strings.toNTPath(&wbuf, subpath); + const wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); + const path = bun.strings.toNTPath(wbuf, subpath); const path_len_bytes: u16 = @truncate(path.len * 2); var nt_name = w.UNICODE_STRING{ .Length = path_len_bytes, @@ -2745,8 +2766,9 @@ pub fn existsAt(fd: bun.FileDescriptor, subpath: [:0]const u8) bool { } if (comptime Environment.isWindows) { - var wbuf: bun.WPathBuffer = undefined; - const path = bun.strings.toNTPath(&wbuf, subpath); + const wbuf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(wbuf); + const path = bun.strings.toNTPath(wbuf, subpath); const path_len_bytes: u16 = @truncate(path.len * 2); var nt_name = w.UNICODE_STRING{ .Length = path_len_bytes, diff --git a/src/url.zig b/src/url.zig index 3e7260aa8a..5dafcac0c7 100644 --- a/src/url.zig +++ b/src/url.zig @@ -488,7 +488,7 @@ pub const QueryStringMap = struct { pub const Iterator = struct { // Assume no query string param map will exceed 2048 keys // Browsers typically limit URL lengths to around 64k - const VisitedMap = std.bit_set.ArrayBitSet(usize, 2048); + const VisitedMap = bun.bit_set.ArrayBitSet(usize, 2048); i: usize = 0, map: *const QueryStringMap, diff --git a/src/which.zig b/src/which.zig index 093b141c4f..0470af9d61 100644 --- a/src/which.zig +++ b/src/which.zig @@ -20,8 +20,9 @@ pub fn which(buf: *bun.PathBuffer, path: []const u8, cwd: []const u8, bin: []con bun.Output.scoped(.which, true)("path={s} cwd={s} bin={s}", .{ path, cwd, bin }); if (bun.Environment.os == .windows) { - var convert_buf: bun.WPathBuffer = undefined; - const result = whichWin(&convert_buf, path, cwd, bin) orelse return null; + const convert_buf = bun.WPathBufferPool.get(); + defer bun.WPathBufferPool.put(convert_buf); + const result = whichWin(convert_buf, path, cwd, bin) orelse return null; const result_converted = bun.strings.convertUTF16toUTF8InBuffer(buf, result) catch unreachable; buf[result_converted.len] = 0; bun.assert(result_converted.ptr == buf.ptr); @@ -132,13 +133,14 @@ fn searchBinInPath(buf: *bun.WPathBuffer, path_buf: *bun.PathBuffer, path: []con /// It is similar to Get-Command in powershell. pub fn whichWin(buf: *bun.WPathBuffer, path: []const u8, cwd: []const u8, bin: []const u8) ?[:0]const u16 { if (bin.len == 0) return null; - var path_buf: bun.PathBuffer = undefined; + const path_buf = bun.PathBufferPool.get(); + defer bun.PathBufferPool.put(path_buf); const check_windows_extensions = !endsWithExtension(bin); // handle absolute paths if (std.fs.path.isAbsolute(bin)) { - const normalized_bin = PosixToWinNormalizer.resolveCWDWithExternalBuf(&path_buf, bin) catch return null; + const normalized_bin = PosixToWinNormalizer.resolveCWDWithExternalBuf(path_buf, bin) catch return null; const bin_utf16 = bun.strings.convertUTF8toUTF16InBuffer(buf, normalized_bin); buf[bin_utf16.len] = 0; return searchBin(buf, bin_utf16.len, check_windows_extensions); @@ -148,7 +150,7 @@ pub fn whichWin(buf: *bun.WPathBuffer, path: []const u8, cwd: []const u8, bin: [ if (bun.strings.containsChar(bin, '/') or bun.strings.containsChar(bin, '\\')) { if (searchBinInPath( buf, - &path_buf, + path_buf, cwd, bun.strings.withoutPrefixComptime(bin, "./"), check_windows_extensions, @@ -163,7 +165,7 @@ pub fn whichWin(buf: *bun.WPathBuffer, path: []const u8, cwd: []const u8, bin: [ // iterate over system path delimiter var path_iter = std.mem.tokenizeScalar(u8, path, ';'); while (path_iter.next()) |segment_part| { - if (searchBinInPath(buf, &path_buf, segment_part, bin, check_windows_extensions)) |bin_path| { + if (searchBinInPath(buf, path_buf, segment_part, bin, check_windows_extensions)) |bin_path| { return bin_path; } } diff --git a/test/bundler/transpiler/fixtures/lots-of-for-loop.js b/test/bundler/transpiler/fixtures/lots-of-for-loop.js new file mode 100644 index 0000000000..096ff28911 --- /dev/null +++ b/test/bundler/transpiler/fixtures/lots-of-for-loop.js @@ -0,0 +1,713 @@ +let counter = 0; +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) + +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) + +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) + +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) + +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) + +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) + +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) + +for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) for (let i = 0; i < 1; i++) counter++; +console.log(counter); \ No newline at end of file diff --git a/test/bundler/transpiler/transpiler.test.js b/test/bundler/transpiler/transpiler.test.js index 8757b968ae..0b0103848f 100644 --- a/test/bundler/transpiler/transpiler.test.js +++ b/test/bundler/transpiler/transpiler.test.js @@ -3441,3 +3441,19 @@ it("does not crash with 9 comments and typescript type skipping", () => { expect(stdout.toString()).toContain("success!"); expect(exitCode).toBe(0); }); + +it("runtime transpiler stack overflows", async () => { + expect(async () => await import("./fixtures/lots-of-for-loop.js")).toThrow(`Maximum call stack size exceeded`); +}); + +it("Bun.Transpiler.transformSync stack overflows", async () => { + const code = await Bun.file(join(import.meta.dir, "fixtures", "lots-of-for-loop.js")).text(); + const transpiler = new Bun.Transpiler(); + expect(() => transpiler.transformSync(code)).toThrow(`Maximum call stack size exceeded`); +}); + +it("Bun.Transpiler.transform stack overflows", async () => { + const code = await Bun.file(join(import.meta.dir, "fixtures", "lots-of-for-loop.js")).text(); + const transpiler = new Bun.Transpiler(); + expect(async () => await transpiler.transform(code)).toThrow(`Maximum call stack size exceeded`); +}); diff --git a/test/js/bun/test/stack.test.ts b/test/js/bun/test/stack.test.ts index ac3fde49c0..dd32267d49 100644 --- a/test/js/bun/test/stack.test.ts +++ b/test/js/bun/test/stack.test.ts @@ -93,11 +93,16 @@ test("throwing inside an error suppresses the error and prints the stack", async const { stderr, exitCode } = result; - expect(stderr.toString().trim()).toStartWith( - `error: My custom error message - at http://example.com/test.js:42 - `.trim(), - ); + expect(stderr.toString().trim().split("\n").slice(0, -1).join("\n").trim()).toMatchInlineSnapshot(` +"error: My custom error message +{ + message: "My custom error message", + name: [Getter], + line: 42, + sourceURL: "http://example.com/test.js", +} + at http://example.com/test.js:42" +`); expect(exitCode).toBe(1); }); @@ -108,8 +113,10 @@ test("throwing inside an error suppresses the error and continues printing prope const { stderr, exitCode } = result; - expect(stderr.toString().trim()).toStartWith( - 'ENOENT: No such file or directory\n errno: -2\n syscall: "open"\n path: "this-file-path-is-bad"'.trim(), - ); + expect(stderr.toString().trim()).toStartWith(`ENOENT: No such file or directory + path: "this-file-path-is-bad", + syscall: "open", + errno: -2, +`); expect(exitCode).toBe(1); }); diff --git a/test/js/bun/util/error-gc-test.test.js b/test/js/bun/util/error-gc-test.test.js index da1cfecb02..19bb1210b9 100644 --- a/test/js/bun/util/error-gc-test.test.js +++ b/test/js/bun/util/error-gc-test.test.js @@ -50,9 +50,12 @@ test("error gc test #3", () => { // - The test failure message gets a non-sensical error test("error gc test #4", () => { const tmp = tmpdirSync(); - for (let i = 0; i < 1000; i++) { + const base = Buffer.from(join(tmp, "does", "not", "exist").repeat(10)); + + function iterate() { // Use a long-enough string for it to be obvious if we leak memory - let path = join(tmp, join("does", "not", "exist").repeat(10)); + // Use .toString() on the Buffer to ensure we clone the string every time. + let path = base.toString(); try { readFileSync(path); throw new Error("unreachable"); @@ -61,8 +64,14 @@ test("error gc test #4", () => { throw e; } - const inspected = Bun.inspect(e); + path = path.replaceAll("\\", "/"); + if (e.path) { + e.path = e.path.replaceAll("\\", "/"); + } + + let inspected = Bun.inspect(e); Bun.gc(true); + inspected = inspected.replaceAll("\\", "/"); // Deliberately avoid using .toContain() directly to avoid // BunString shenanigins. @@ -80,4 +89,8 @@ test("error gc test #4", () => { Bun.gc(true); } } + + for (let i = 0; i < 1000; i++) { + iterate(); + } }); diff --git a/test/js/bun/util/reportError.test.ts b/test/js/bun/util/reportError.test.ts index 14f0466af3..f1e6008991 100644 --- a/test/js/bun/util/reportError.test.ts +++ b/test/js/bun/util/reportError.test.ts @@ -18,5 +18,49 @@ test("reportError", () => { // remove bun version from output output = output.split("\n").slice(0, -2).join("\n"); - expect(output).toMatchSnapshot(); + expect(output.replaceAll("\\", "/").replaceAll("/reportError.ts", "[file]")).toMatchInlineSnapshot( + ` +"1 | reportError(new Error("reportError Test!")); + ^ +error: reportError Test! + at [file]:1:13 +error: true +true +error: false +false +error: null +null +error: 123 +123 +error: Infinity +Infinity +error: NaN +NaN +error: NaN +NaN +error + +error +Uint8Array(1) [ 0 ] +error +Uint8Array(0) [ ] +error +ArrayBuffer(0) [ ] +error +ArrayBuffer(1) [ 0 ] +error: string +string +error +[] +error +[ 123, null ] +error +{} +error +[ + {} +] +" +`, + ); }); diff --git a/test/js/node/util/bun-inspect.test.ts b/test/js/node/util/bun-inspect.test.ts index 57151a7b5b..115ad1c500 100644 --- a/test/js/node/util/bun-inspect.test.ts +++ b/test/js/node/util/bun-inspect.test.ts @@ -47,18 +47,46 @@ describe("Bun.inspect", () => { expect(() => Bun.inspect({}, { depth: -1 })).toThrow(); expect(() => Bun.inspect({}, { depth: -13210 })).toThrow(); }); - it("depth = Infinity works", () => { - function createRecursiveObject(n: number): any { - if (n === 0) return { hi: true }; - return { a: createRecursiveObject(n - 1) }; + for (let base of [new Error("hi"), { a: "hi" }]) { + it(`depth = Infinity works for ${base.constructor.name}`, () => { + function createRecursiveObject(n: number): any { + if (n === 0) { + return { a: base }; + } + return { a: createRecursiveObject(n - 1) }; + } + + const obj = createRecursiveObject(512); + expect(Bun.inspect(obj, { depth: Infinity })).toContain("hi"); + // this gets converted to u16, which if just truncating, will turn into 0 + expect(Bun.inspect(obj, { depth: 0x0fff0000 })).toContain("hi"); + }); + } + + it("stack overflow is thrown when it should be for objects", () => { + var object = { a: { b: { c: { d: 1 } } } }; + for (let i = 0; i < 16 * 1024; i++) { + object = { a: object }; } - const obj = createRecursiveObject(1000); - - expect(Bun.inspect(obj, { depth: Infinity })).toContain("hi"); - // this gets converted to u16, which if just truncating, will turn into 0 - expect(Bun.inspect(obj, { depth: 0x0fff0000 })).toContain("hi"); + expect(() => Bun.inspect(object, { depth: Infinity })).toThrowErrorMatchingInlineSnapshot( + `"Maximum call stack size exceeded."`, + ); }); + + it("stack overflow is thrown when it should be for Error", () => { + var object = { a: { b: { c: { d: 1 } } } }; + for (let i = 0; i < 16 * 1024; i++) { + const err = new Error("hello"); + err.object = object; + object = err; + } + + expect(() => Bun.inspect(object, { depth: Infinity })).toThrowErrorMatchingInlineSnapshot( + `"Maximum call stack size exceeded."`, + ); + }); + it("depth = 0", () => { expect(Bun.inspect({ a: { b: { c: { d: 1 } } } }, { depth: 0 })).toEqual("{\n a: [Object ...],\n}"); }); From 379c79ee2ed69ba9c52b7fcdb29ff66bd20dccf4 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 25 Dec 2024 22:35:52 -0800 Subject: [PATCH 095/125] Fix typo --- src/cli/add_completions.txt | 2 +- src/cli/add_completions.zig | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cli/add_completions.txt b/src/cli/add_completions.txt index 4f7de89059..b7c7b6a1f6 100644 --- a/src/cli/add_completions.txt +++ b/src/cli/add_completions.txt @@ -2218,7 +2218,7 @@ elm-hot elm-hot-webpack-loader elm-test elm-webpack-loader -elsysia +elysia email-validator emailjs-base64 emailjs-imap-client diff --git a/src/cli/add_completions.zig b/src/cli/add_completions.zig index a07c3a8b5b..70d7e497d9 100644 --- a/src/cli/add_completions.zig +++ b/src/cli/add_completions.zig @@ -6,6 +6,7 @@ // If you update add_completions.txt, then you should run this script again. // // This used to be a comptime block, but it made the build too slow. +// Compressing the completions list saves about 100 KB of binary size. const std = @import("std"); const bun = @import("root").bun; const zstd = bun.zstd; @@ -40,9 +41,9 @@ pub const FirstLetter = enum(u8) { z = 'z', }; -const compressed_data = [_]u8{ 40, 181, 47, 253, 164, 157, 121, 2, 0, 156, 101, 6, 158, 128, 75, 130, 29, 50, 176, 110, 136, 168, 13, 197, 255, 138, 8, 111, 46, 215, 144, 108, 221, 73, 168, 182, 179, 179, 179, 179, 179, 179, 51, 237, 133, 67, 129, 22, 40, 149, 155, 13, 77, 238, 238, 175, 34, 93, 183, 136, 45, 12, 248, 199, 52, 72, 79, 1, 55, 29, 153, 29, 167, 29, 235, 37, 92, 124, 219, 151, 239, 224, 193, 181, 73, 119, 101, 17, 191, 237, 69, 28, 40, 90, 23, 246, 210, 75, 200, 80, 249, 38, 68, 112, 232, 47, 107, 117, 80, 218, 229, 37, 108, 104, 236, 17, 254, 137, 39, 108, 176, 212, 110, 10, 196, 195, 108, 211, 246, 97, 118, 226, 9, 27, 38, 158, 208, 49, 241, 132, 10, 152, 126, 158, 112, 225, 61, 161, 130, 79, 135, 226, 158, 112, 225, 158, 176, 193, 216, 61, 225, 2, 187, 39, 84, 240, 134, 111, 218, 233, 144, 178, 116, 7, 148, 108, 39, 125, 178, 111, 202, 94, 211, 137, 94, 27, 180, 246, 223, 2, 14, 11, 126, 189, 100, 84, 49, 80, 154, 90, 78, 84, 54, 224, 150, 205, 61, 225, 162, 45, 115, 127, 45, 35, 238, 9, 25, 223, 152, 113, 79, 216, 144, 176, 177, 48, 78, 238, 9, 23, 205, 139, 147, 123, 122, 169, 139, 123, 194, 7, 4, 247, 132, 142, 79, 135, 178, 214, 50, 79, 99, 135, 188, 35, 222, 202, 73, 175, 126, 173, 191, 237, 233, 100, 63, 27, 106, 204, 180, 116, 190, 217, 241, 214, 138, 109, 42, 225, 111, 245, 78, 55, 209, 76, 241, 73, 151, 186, 39, 108, 124, 82, 197, 173, 85, 146, 210, 77, 128, 56, 32, 97, 118, 180, 57, 33, 135, 239, 130, 144, 164, 246, 130, 180, 237, 242, 8, 114, 223, 95, 72, 4, 181, 69, 238, 9, 31, 216, 113, 152, 120, 167, 89, 165, 56, 88, 79, 3, 39, 189, 246, 63, 208, 138, 117, 244, 141, 153, 111, 204, 32, 247, 132, 12, 215, 109, 125, 19, 144, 123, 194, 137, 214, 111, 118, 148, 43, 169, 66, 238, 9, 25, 184, 178, 108, 14, 174, 154, 41, 143, 74, 60, 161, 4, 114, 79, 216, 224, 158, 80, 193, 90, 234, 60, 161, 68, 115, 5, 156, 123, 66, 5, 247, 132, 141, 102, 104, 42, 225, 111, 218, 170, 150, 77, 225, 120, 58, 15, 136, 43, 226, 164, 138, 19, 106, 165, 18, 69, 48, 131, 235, 218, 198, 187, 167, 19, 46, 124, 211, 73, 4, 136, 219, 10, 228, 158, 147, 134, 219, 138, 246, 38, 34, 220, 185, 31, 147, 166, 13, 119, 238, 132, 18, 30, 105, 180, 58, 199, 157, 112, 209, 236, 160, 13, 221, 9, 31, 141, 59, 161, 130, 183, 254, 202, 180, 191, 157, 84, 103, 66, 191, 74, 59, 33, 4, 51, 52, 119, 107, 83, 231, 221, 115, 37, 9, 231, 18, 125, 74, 109, 136, 37, 61, 247, 143, 41, 156, 75, 244, 21, 109, 15, 109, 43, 203, 32, 41, 153, 243, 112, 60, 29, 101, 217, 76, 171, 163, 5, 141, 247, 153, 57, 56, 42, 41, 210, 79, 237, 132, 143, 8, 18, 82, 39, 132, 68, 144, 128, 82, 39, 100, 72, 157, 80, 65, 42, 150, 157, 144, 161, 65, 118, 66, 200, 227, 18, 42, 168, 184, 132, 10, 158, 75, 8, 105, 151, 80, 65, 196, 181, 132, 24, 151, 80, 66, 215, 50, 200, 37, 92, 248, 90, 141, 245, 150, 150, 239, 139, 208, 193, 243, 155, 144, 126, 190, 55, 64, 68, 64, 252, 72, 2, 98, 95, 244, 72, 120, 227, 180, 168, 201, 197, 160, 167, 243, 83, 161, 7, 162, 56, 161, 167, 191, 61, 174, 80, 182, 143, 84, 75, 228, 186, 253, 237, 113, 194, 6, 232, 219, 83, 201, 14, 44, 115, 78, 156, 144, 193, 155, 19, 42, 168, 69, 141, 155, 19, 58, 168, 236, 198, 61, 7, 84, 170, 147, 234, 158, 71, 30, 209, 230, 135, 246, 115, 16, 228, 17, 164, 141, 84, 155, 19, 62, 164, 125, 231, 214, 228, 42, 8, 14, 193, 117, 13, 160, 77, 254, 174, 9, 206, 64, 39, 173, 222, 180, 237, 116, 252, 129, 206, 197, 223, 231, 187, 3, 138, 238, 100, 81, 10, 106, 32, 109, 227, 165, 136, 208, 218, 212, 49, 210, 181, 12, 3, 11, 156, 75, 180, 192, 178, 203, 121, 31, 78, 122, 101, 82, 219, 65, 173, 102, 10, 226, 181, 212, 65, 206, 53, 120, 200, 9, 171, 230, 132, 11, 215, 181, 204, 4, 226, 71, 95, 97, 208, 171, 80, 132, 196, 243, 27, 143, 123, 80, 133, 30, 199, 9, 33, 30, 199, 9, 21, 124, 161, 107, 25, 199, 55, 245, 198, 233, 43, 175, 161, 5, 16, 14, 13, 157, 17, 132, 14, 231, 151, 130, 62, 237, 167, 93, 172, 245, 28, 84, 169, 168, 131, 190, 117, 194, 30, 65, 252, 104, 105, 170, 232, 2, 247, 132, 190, 37, 244, 215, 50, 236, 203, 24, 63, 56, 192, 183, 117, 252, 219, 46, 119, 160, 117, 97, 218, 128, 54, 39, 111, 64, 82, 87, 0, 2, 236, 74, 11, 48, 126, 6, 58, 215, 107, 90, 162, 7, 208, 202, 198, 251, 77, 39, 141, 19, 50, 200, 102, 120, 94, 174, 2, 253, 184, 241, 254, 2, 186, 150, 124, 109, 89, 106, 127, 131, 36, 229, 187, 51, 90, 159, 92, 218, 188, 30, 211, 120, 63, 187, 89, 138, 111, 202, 22, 172, 199, 68, 180, 123, 30, 130, 158, 231, 183, 95, 82, 23, 128, 175, 66, 19, 184, 112, 62, 29, 242, 6, 102, 218, 162, 118, 240, 85, 188, 173, 14, 41, 109, 155, 255, 192, 63, 189, 126, 103, 60, 204, 58, 133, 46, 199, 109, 191, 229, 59, 168, 103, 66, 223, 242, 35, 152, 224, 147, 23, 131, 152, 182, 14, 37, 92, 233, 167, 218, 9, 253, 84, 187, 216, 91, 62, 132, 134, 125, 142, 214, 111, 219, 14, 233, 90, 242, 23, 52, 188, 34, 28, 45, 238, 6, 185, 216, 91, 167, 67, 237, 49, 3, 165, 16, 255, 88, 217, 190, 86, 236, 210, 55, 65, 253, 65, 69, 155, 4, 81, 60, 173, 111, 194, 114, 108, 29, 53, 46, 66, 253, 165, 83, 204, 36, 24, 180, 46, 209, 211, 252, 190, 78, 3, 142, 231, 98, 26, 180, 159, 55, 165, 104, 88, 229, 167, 122, 112, 192, 133, 175, 92, 120, 53, 8, 53, 109, 253, 49, 141, 19, 62, 200, 212, 44, 211, 222, 147, 161, 102, 153, 150, 78, 66, 16, 100, 96, 26, 39, 84, 152, 112, 109, 187, 40, 218, 144, 122, 83, 213, 56, 97, 132, 166, 150, 170, 249, 209, 146, 233, 68, 63, 155, 62, 220, 37, 115, 126, 41, 12, 26, 92, 50, 228, 64, 6, 138, 238, 4, 241, 183, 213, 127, 14, 156, 173, 66, 250, 47, 226, 174, 189, 64, 227, 135, 174, 101, 221, 181, 33, 77, 62, 114, 215, 118, 215, 134, 248, 164, 145, 229, 57, 82, 237, 65, 48, 97, 150, 131, 154, 29, 124, 83, 135, 180, 101, 42, 81, 171, 75, 168, 175, 126, 14, 77, 149, 242, 142, 219, 61, 252, 182, 58, 223, 116, 18, 225, 164, 84, 213, 118, 65, 21, 93, 206, 225, 109, 43, 203, 144, 123, 58, 136, 198, 235, 173, 147, 7, 95, 253, 90, 39, 76, 221, 97, 45, 77, 72, 233, 2, 196, 96, 45, 77, 16, 93, 77, 75, 132, 13, 173, 173, 170, 105, 35, 73, 39, 123, 208, 202, 232, 85, 141, 202, 50, 218, 14, 57, 159, 78, 162, 225, 133, 26, 55, 180, 93, 80, 227, 236, 141, 48, 248, 182, 171, 105, 197, 190, 227, 125, 25, 227, 132, 139, 138, 54, 218, 13, 14, 241, 77, 25, 227, 132, 144, 197, 252, 72, 219, 174, 8, 127, 223, 138, 34, 213, 28, 92, 223, 202, 9, 82, 154, 140, 113, 66, 6, 17, 32, 212, 131, 75, 38, 225, 109, 23, 198, 9, 29, 30, 102, 27, 123, 139, 19, 54, 250, 49, 186, 206, 59, 218, 186, 100, 12, 213, 249, 26, 197, 32, 137, 176, 104, 126, 228, 210, 52, 106, 246, 78, 247, 120, 223, 133, 148, 101, 123, 80, 150, 13, 194, 48, 171, 28, 223, 58, 105, 156, 80, 243, 226, 132, 13, 191, 190, 19, 8, 151, 12, 53, 94, 7, 143, 64, 112, 104, 147, 173, 19, 78, 104, 2, 19, 244, 73, 215, 74, 244, 73, 215, 226, 9, 253, 117, 40, 72, 221, 229, 90, 156, 144, 162, 45, 39, 116, 52, 156, 80, 193, 195, 108, 163, 65, 149, 97, 56, 33, 131, 219, 95, 204, 143, 42, 238, 96, 237, 63, 84, 225, 69, 181, 116, 85, 156, 208, 1, 109, 210, 49, 188, 181, 81, 120, 29, 127, 141, 207, 134, 230, 110, 157, 64, 170, 56, 97, 132, 175, 205, 70, 141, 57, 113, 66, 200, 210, 253, 148, 36, 78, 216, 120, 146, 235, 74, 78, 200, 248, 77, 10, 226, 132, 11, 245, 135, 56, 33, 67, 246, 87, 20, 57, 131, 56, 225, 131, 113, 51, 136, 19, 58, 180, 50, 170, 16, 39, 100, 32, 78, 216, 120, 20, 47, 136, 19, 46, 56, 225, 163, 178, 204, 179, 131, 216, 58, 142, 20, 75, 248, 160, 88, 194, 134, 214, 247, 183, 18, 58, 236, 91, 9, 21, 42, 190, 18, 42, 180, 166, 236, 111, 228, 43, 225, 67, 169, 132, 217, 65, 190, 18, 58, 144, 175, 132, 144, 167, 179, 45, 107, 102, 114, 49, 14, 255, 166, 19, 125, 80, 120, 169, 199, 43, 225, 195, 90, 6, 189, 171, 179, 58, 175, 132, 11, 103, 240, 207, 247, 135, 122, 99, 231, 14, 78, 85, 65, 180, 241, 74, 184, 144, 120, 37, 84, 216, 183, 43, 225, 194, 3, 121, 28, 39, 228, 160, 58, 121, 113, 187, 18, 54, 24, 102, 87, 194, 5, 111, 188, 238, 234, 232, 155, 62, 56, 175, 150, 210, 164, 191, 134, 126, 166, 246, 250, 95, 62, 36, 172, 132, 14, 230, 219, 182, 163, 232, 78, 180, 29, 74, 40, 209, 250, 204, 12, 154, 112, 215, 110, 16, 178, 75, 39, 191, 11, 163, 41, 36, 41, 255, 241, 234, 13, 72, 179, 220, 57, 24, 109, 244, 219, 52, 172, 126, 45, 117, 37, 116, 240, 8, 67, 196, 90, 143, 65, 174, 15, 141, 194, 10, 81, 228, 167, 210, 230, 132, 90, 173, 132, 13, 87, 150, 205, 225, 17, 8, 239, 187, 124, 151, 196, 103, 130, 208, 216, 35, 104, 129, 7, 95, 251, 239, 193, 64, 107, 196, 251, 46, 135, 47, 67, 53, 253, 138, 34, 196, 229, 74, 168, 32, 193, 167, 212, 126, 240, 198, 251, 217, 14, 68, 208, 104, 254, 85, 42, 73, 200, 104, 236, 145, 132, 11, 173, 21, 93, 200, 35, 9, 33, 252, 173, 202, 110, 253, 166, 137, 65, 154, 70, 81, 51, 131, 26, 123, 100, 193, 211, 185, 94, 234, 77, 184, 128, 122, 46, 8, 31, 223, 54, 161, 130, 171, 77, 168, 160, 54, 161, 195, 59, 39, 8, 109, 66, 136, 133, 35, 104, 19, 54, 76, 154, 162, 77, 200, 160, 24, 36, 237, 57, 9, 25, 240, 8, 210, 37, 73, 235, 144, 4, 123, 203, 128, 52, 120, 223, 133, 92, 233, 231, 122, 76, 27, 240, 197, 252, 19, 85, 14, 82, 45, 44, 23, 114, 74, 34, 141, 240, 8, 74, 198, 237, 36, 108, 116, 163, 176, 147, 144, 97, 87, 66, 157, 106, 37, 236, 36, 132, 184, 166, 101, 39, 97, 68, 43, 102, 78, 66, 134, 10, 52, 124, 69, 213, 90, 39, 97, 68, 219, 124, 238, 137, 58, 9, 29, 188, 173, 234, 36, 92, 184, 183, 96, 143, 65, 161, 205, 239, 223, 116, 87, 138, 240, 102, 214, 220, 173, 72, 226, 11, 225, 186, 146, 164, 78, 66, 9, 39, 125, 82, 144, 75, 117, 18, 62, 36, 105, 37, 13, 198, 92, 49, 225, 75, 151, 92, 249, 169, 184, 181, 68, 30, 121, 164, 138, 219, 68, 243, 226, 212, 240, 77, 25, 51, 6, 30, 249, 247, 253, 78, 39, 33, 227, 213, 59, 157, 132, 11, 214, 233, 36, 92, 80, 187, 114, 210, 22, 105, 106, 218, 202, 104, 51, 0, 241, 164, 108, 116, 61, 136, 96, 177, 119, 144, 3, 215, 253, 253, 166, 168, 245, 83, 118, 58, 9, 37, 58, 157, 132, 14, 136, 138, 54, 218, 107, 25, 212, 240, 114, 240, 160, 158, 9, 105, 211, 82, 75, 39, 33, 67, 75, 39, 161, 194, 174, 212, 234, 144, 172, 116, 18, 46, 176, 108, 73, 58, 9, 23, 148, 244, 214, 28, 212, 190, 231, 186, 206, 29, 74, 191, 217, 157, 170, 66, 20, 94, 43, 29, 111, 160, 146, 93, 141, 198, 30, 137, 168, 122, 43, 85, 20, 162, 236, 169, 104, 202, 152, 161, 108, 95, 63, 85, 67, 91, 22, 190, 233, 36, 124, 72, 154, 153, 132, 11, 254, 141, 153, 132, 12, 223, 118, 161, 198, 36, 100, 76, 154, 50, 9, 23, 22, 38, 161, 2, 143, 64, 88, 120, 45, 136, 73, 232, 104, 205, 174, 68, 173, 223, 52, 33, 164, 241, 126, 126, 211, 109, 70, 107, 105, 66, 8, 253, 236, 69, 151, 38, 108, 248, 4, 36, 42, 225, 194, 87, 82, 66, 5, 100, 104, 154, 151, 132, 11, 188, 36, 108, 52, 47, 9, 21, 40, 153, 80, 129, 175, 119, 58, 159, 9, 27, 43, 159, 103, 66, 6, 198, 10, 57, 158, 9, 25, 206, 231, 122, 83, 71, 234, 153, 208, 0, 234, 153, 80, 161, 237, 226, 153, 144, 161, 117, 187, 51, 225, 130, 87, 103, 194, 133, 149, 109, 85, 103, 66, 134, 234, 165, 19, 119, 240, 41, 181, 81, 3, 255, 166, 173, 241, 210, 153, 48, 226, 183, 162, 72, 251, 61, 47, 228, 109, 243, 93, 38, 132, 172, 108, 118, 153, 112, 145, 191, 46, 19, 66, 154, 73, 203, 132, 11, 191, 12, 114, 120, 78, 24, 180, 98, 87, 166, 109, 252, 187, 32, 139, 114, 172, 75, 164, 254, 150, 177, 66, 234, 79, 210, 118, 177, 199, 81, 203, 132, 143, 39, 151, 227, 127, 137, 90, 38, 132, 104, 197, 50, 212, 51, 53, 212, 51, 161, 165, 44, 19, 58, 84, 115, 210, 70, 250, 235, 15, 106, 81, 171, 254, 186, 182, 174, 149, 9, 25, 240, 193, 1, 162, 218, 46, 104, 173, 76, 216, 112, 139, 82, 154, 137, 67, 154, 230, 26, 117, 145, 6, 102, 27, 4, 241, 86, 183, 43, 19, 50, 180, 151, 93, 153, 112, 129, 14, 250, 169, 86, 38, 92, 52, 10, 55, 116, 178, 159, 75, 81, 68, 184, 39, 97, 94, 72, 215, 146, 16, 46, 41, 238, 206, 167, 243, 85, 218, 15, 124, 149, 54, 175, 227, 233, 32, 103, 208, 130, 214, 38, 91, 178, 134, 166, 223, 56, 73, 168, 231, 130, 142, 9, 36, 12, 128, 66, 16, 33, 161, 130, 250, 82, 60, 194, 82, 251, 33, 142, 47, 35, 233, 34, 215, 127, 30, 92, 255, 89, 112, 65, 255, 89, 208, 161, 21, 235, 13, 231, 155, 166, 11, 233, 63, 11, 62, 244, 159, 5, 21, 180, 237, 122, 22, 100, 240, 8, 114, 75, 89, 112, 241, 240, 226, 111, 65, 6, 254, 237, 126, 11, 46, 52, 101, 191, 66, 220, 80, 69, 49, 190, 224, 249, 215, 118, 46, 61, 114, 60, 223, 27, 94, 19, 45, 159, 124, 218, 91, 144, 193, 73, 159, 148, 199, 82, 237, 45, 216, 208, 222, 130, 10, 146, 173, 183, 224, 66, 54, 237, 68, 107, 189, 5, 29, 107, 189, 5, 21, 156, 225, 170, 56, 33, 127, 223, 246, 215, 38, 107, 172, 253, 71, 209, 90, 255, 211, 225, 3, 165, 153, 183, 224, 194, 218, 127, 190, 144, 164, 116, 146, 100, 30, 97, 52, 74, 58, 71, 74, 29, 154, 43, 79, 219, 201, 3, 255, 2, 103, 235, 56, 68, 189, 117, 162, 253, 244, 77, 128, 168, 91, 167, 234, 36, 214, 90, 230, 49, 129, 59, 188, 65, 217, 62, 250, 150, 43, 223, 4, 93, 64, 29, 148, 73, 111, 15, 77, 36, 94, 43, 81, 43, 195, 188, 5, 33, 15, 179, 186, 150, 183, 32, 67, 127, 23, 74, 254, 5, 27, 201, 191, 160, 66, 99, 95, 80, 65, 146, 212, 73, 19, 144, 192, 23, 108, 76, 64, 2, 95, 80, 161, 213, 57, 125, 71, 190, 160, 163, 249, 147, 70, 218, 162, 87, 231, 182, 57, 242, 5, 39, 92, 221, 38, 109, 228, 11, 58, 124, 193, 134, 36, 229, 251, 174, 132, 220, 181, 221, 147, 144, 3, 73, 202, 247, 86, 167, 64, 190, 105, 147, 173, 254, 208, 251, 46, 111, 117, 138, 239, 122, 44, 187, 42, 30, 102, 23, 180, 102, 253, 33, 189, 27, 123, 4, 105, 147, 146, 148, 174, 193, 202, 135, 217, 137, 149, 223, 148, 105, 167, 182, 232, 97, 214, 25, 212, 224, 170, 208, 195, 108, 171, 227, 54, 161, 135, 89, 71, 241, 48, 235, 144, 164, 116, 237, 73, 18, 47, 228, 75, 126, 196, 62, 148, 218, 227, 186, 235, 119, 57, 111, 88, 196, 143, 88, 106, 191, 235, 90, 82, 165, 118, 3, 202, 246, 219, 65, 12, 36, 41, 29, 68, 21, 55, 212, 44, 65, 173, 132, 183, 170, 84, 167, 93, 107, 211, 150, 153, 152, 52, 125, 124, 210, 87, 229, 224, 173, 78, 225, 109, 202, 195, 195, 236, 106, 222, 59, 133, 75, 214, 234, 173, 255, 174, 204, 182, 100, 72, 215, 243, 222, 128, 162, 239, 13, 142, 167, 131, 182, 93, 181, 31, 81, 120, 185, 75, 134, 220, 211, 221, 91, 139, 187, 105, 235, 200, 61, 189, 179, 251, 166, 11, 48, 211, 22, 169, 226, 22, 209, 218, 94, 2, 90, 43, 118, 37, 107, 110, 104, 1, 237, 164, 232, 82, 106, 153, 174, 101, 22, 52, 111, 81, 229, 208, 224, 51, 53, 78, 15, 238, 9, 181, 212, 149, 90, 215, 58, 111, 217, 255, 64, 127, 155, 194, 96, 226, 18, 75, 91, 123, 12, 82, 44, 209, 46, 78, 137, 123, 193, 9, 103, 122, 65, 5, 213, 76, 105, 184, 167, 163, 111, 203, 78, 146, 218, 11, 62, 56, 175, 82, 123, 65, 135, 247, 76, 189, 32, 131, 68, 57, 114, 82, 203, 94, 208, 177, 40, 5, 169, 246, 183, 205, 94, 176, 193, 25, 26, 175, 183, 236, 5, 31, 116, 41, 197, 12, 53, 230, 22, 124, 52, 188, 239, 114, 110, 65, 6, 111, 156, 182, 194, 11, 50, 154, 86, 120, 193, 5, 137, 170, 240, 130, 144, 79, 234, 21, 94, 176, 161, 149, 226, 17, 135, 82, 120, 65, 136, 182, 126, 188, 32, 195, 167, 54, 4, 105, 188, 244, 227, 5, 23, 106, 223, 163, 240, 71, 37, 232, 151, 49, 242, 181, 255, 30, 52, 222, 207, 102, 39, 217, 208, 163, 18, 119, 93, 15, 60, 157, 170, 61, 110, 14, 143, 232, 250, 231, 5, 25, 142, 55, 47, 184, 224, 142, 23, 84, 112, 210, 39, 197, 81, 225, 229, 125, 215, 202, 167, 80, 4, 12, 244, 77, 26, 116, 53, 13, 127, 171, 218, 229, 233, 14, 15, 179, 207, 13, 194, 27, 167, 125, 208, 79, 69, 241, 172, 198, 200, 93, 162, 85, 146, 214, 53, 47, 78, 104, 129, 203, 126, 111, 84, 120, 121, 230, 5, 23, 76, 225, 97, 22, 23, 186, 120, 65, 5, 73, 226, 5, 177, 88, 5, 61, 60, 138, 23, 124, 60, 138, 23, 84, 72, 170, 120, 193, 133, 102, 196, 11, 62, 218, 130, 1, 240, 8, 114, 108, 65, 6, 199, 211, 233, 183, 22, 100, 44, 199, 30, 34, 129, 98, 143, 133, 215, 130, 248, 145, 231, 164, 101, 66, 142, 173, 190, 181, 32, 131, 167, 95, 27, 169, 222, 69, 223, 90, 208, 225, 169, 124, 34, 135, 210, 69, 132, 6, 8, 58, 172, 253, 215, 248, 69, 236, 224, 216, 163, 133, 215, 99, 225, 181, 96, 3, 195, 172, 66, 146, 182, 107, 65, 199, 178, 253, 141, 19, 82, 234, 174, 107, 193, 7, 143, 168, 36, 215, 130, 139, 247, 93, 146, 148, 107, 193, 198, 90, 48, 0, 191, 11, 54, 210, 54, 102, 218, 24, 196, 178, 11, 105, 187, 99, 212, 150, 211, 239, 130, 15, 93, 74, 45, 229, 209, 239, 130, 143, 9, 38, 112, 187, 224, 2, 5, 36, 184, 93, 112, 33, 2, 9, 64, 224, 118, 65, 6, 151, 77, 89, 184, 106, 191, 99, 47, 210, 240, 166, 173, 82, 236, 188, 50, 20, 89, 24, 194, 97, 173, 68, 170, 237, 130, 140, 221, 228, 217, 118, 65, 198, 68, 226, 208, 208, 44, 211, 56, 161, 230, 238, 101, 20, 17, 234, 153, 208, 227, 233, 108, 187, 32, 67, 196, 163, 245, 215, 50, 200, 155, 92, 12, 154, 192, 4, 181, 93, 112, 66, 146, 210, 161, 182, 11, 50, 60, 2, 161, 217, 5, 33, 202, 246, 63, 27, 53, 187, 224, 162, 217, 5, 29, 141, 61, 130, 154, 93, 144, 209, 218, 232, 183, 69, 205, 46, 248, 240, 8, 90, 181, 11, 46, 244, 233, 155, 0, 113, 62, 221, 68, 115, 236, 248, 85, 47, 17, 115, 13, 194, 19, 43, 212, 250, 175, 11, 70, 184, 173, 120, 215, 5, 23, 75, 221, 117, 65, 6, 109, 90, 54, 146, 32, 129, 211, 5, 31, 223, 116, 65, 5, 73, 39, 115, 82, 211, 5, 27, 173, 191, 116, 65, 134, 86, 167, 186, 32, 131, 46, 216, 88, 118, 33, 180, 28, 66, 234, 185, 32, 4, 193, 4, 69, 0, 69, 192, 17, 66, 78, 66, 42, 73, 186, 160, 2, 34, 72, 112, 146, 46, 200, 208, 57, 65, 79, 69, 46, 164, 212, 130, 16, 143, 48, 60, 162, 138, 27, 106, 120, 247, 116, 90, 144, 193, 35, 170, 56, 45, 11, 50, 36, 112, 69, 206, 231, 130, 140, 198, 251, 235, 12, 209, 180, 85, 42, 221, 67, 219, 166, 147, 57, 252, 227, 39, 151, 218, 110, 144, 123, 114, 111, 94, 28, 90, 179, 43, 145, 123, 114, 79, 238, 185, 224, 194, 61, 211, 248, 151, 40, 173, 231, 130, 18, 11, 175, 6, 57, 158, 11, 54, 86, 191, 8, 38, 104, 168, 141, 96, 130, 8, 38, 136, 96, 2, 138, 134, 45, 138, 96, 130, 8, 38, 136, 48, 129, 58, 132, 70, 211, 8, 18, 42, 12, 18, 207, 215, 230, 119, 135, 55, 184, 254, 227, 78, 233, 92, 89, 54, 7, 247, 73, 83, 134, 68, 179, 76, 155, 80, 103, 199, 24, 242, 224, 174, 137, 219, 161, 93, 9, 169, 51, 38, 77, 103, 35, 130, 9, 144, 122, 46, 184, 72, 219, 223, 52, 61, 157, 11, 46, 236, 74, 40, 155, 174, 92, 208, 161, 169, 229, 202, 5, 29, 212, 173, 107, 114, 193, 133, 54, 217, 52, 185, 160, 195, 251, 46, 228, 170, 153, 162, 114, 193, 134, 182, 141, 202, 5, 25, 60, 226, 248, 29, 142, 231, 114, 73, 202, 5, 27, 30, 169, 52, 98, 24, 8, 47, 56, 151, 232, 153, 108, 165, 255, 218, 120, 59, 25, 132, 255, 245, 103, 201, 5, 194, 4, 171, 246, 26, 188, 162, 205, 21, 49, 208, 198, 139, 36, 229, 130, 12, 39, 229, 242, 44, 185, 96, 163, 241, 122, 150, 92, 112, 241, 48, 203, 144, 36, 117, 210, 90, 153, 220, 246, 4, 78, 250, 164, 60, 36, 43, 41, 234, 158, 71, 227, 149, 170, 229, 59, 68, 131, 195, 155, 188, 9, 3, 17, 32, 64, 218, 228, 59, 133, 115, 57, 65, 225, 229, 145, 133, 153, 52, 237, 126, 175, 174, 189, 150, 121, 22, 59, 120, 238, 202, 244, 214, 201, 182, 167, 150, 39, 136, 31, 73, 146, 58, 9, 41, 237, 92, 73, 85, 123, 15, 180, 190, 111, 163, 29, 65, 115, 107, 182, 162, 223, 56, 33, 237, 125, 19, 18, 144, 203, 105, 55, 64, 89, 54, 109, 213, 158, 2, 18, 224, 174, 162, 141, 118, 3, 180, 249, 81, 63, 167, 169, 31, 51, 75, 29, 85, 60, 242, 233, 24, 39, 3, 44, 128, 1, 147, 166, 72, 21, 183, 150, 186, 152, 151, 4, 52, 109, 215, 178, 14, 1, 2, 9, 174, 84, 34, 157, 236, 191, 164, 222, 56, 185, 237, 119, 68, 225, 197, 40, 96, 1, 16, 36, 60, 64, 130, 4, 170, 56, 109, 123, 12, 171, 123, 222, 1, 16, 168, 104, 163, 141, 30, 73, 218, 247, 6, 44, 160, 213, 61, 87, 76, 89, 54, 196, 48, 106, 102, 30, 149, 32, 253, 76, 187, 220, 83, 77, 219, 126, 170, 28, 160, 244, 159, 99, 12, 129, 171, 123, 174, 212, 180, 117, 128, 82, 199, 201, 145, 36, 241, 90, 34, 144, 0, 130, 8, 68, 112, 69, 8, 64, 0, 1, 20, 128, 90, 157, 203, 166, 32, 166, 239, 143, 35, 143, 36, 197, 239, 17, 104, 125, 215, 247, 100, 140, 83, 211, 118, 109, 246, 63, 192, 181, 19, 80, 241, 136, 106, 187, 32, 2, 80, 120, 49, 223, 8, 112, 188, 21, 117, 64, 1, 248, 1, 254, 244, 250, 189, 113, 66, 238, 185, 146, 163, 74, 126, 123, 12, 224, 146, 33, 10, 230, 118, 160, 189, 20, 109, 93, 236, 141, 83, 46, 109, 137, 102, 226, 186, 235, 219, 54, 109, 18, 43, 203, 134, 82, 177, 108, 137, 214, 172, 243, 115, 187, 231, 91, 29, 183, 139, 48, 223, 118, 20, 202, 178, 33, 73, 123, 78, 66, 206, 167, 107, 125, 101, 217, 233, 6, 160, 44, 219, 186, 178, 108, 72, 87, 211, 146, 13, 224, 249, 109, 203, 180, 85, 170, 58, 95, 211, 216, 183, 221, 46, 166, 241, 126, 182, 101, 187, 84, 165, 42, 6, 28, 192, 219, 254, 218, 183, 160, 135, 217, 182, 204, 153, 2, 28, 79, 197, 107, 98, 169, 98, 134, 38, 168, 226, 17, 181, 249, 169, 144, 78, 152, 105, 31, 192, 91, 151, 89, 197, 12, 85, 60, 210, 76, 220, 117, 45, 185, 157, 19, 244, 77, 89, 227, 222, 73, 83, 6, 76, 154, 62, 171, 111, 118, 108, 162, 162, 22, 66, 181, 29, 210, 182, 171, 45, 242, 206, 101, 177, 119, 154, 124, 228, 192, 35, 13, 172, 156, 68, 52, 222, 231, 92, 235, 24, 39, 180, 46, 91, 23, 166, 10, 104, 230, 160, 156, 168, 137, 42, 6, 154, 183, 232, 3, 111, 12, 210, 79, 181, 192, 221, 83, 211, 86, 45, 102, 208, 183, 100, 175, 41, 122, 111, 12, 180, 145, 178, 108, 79, 46, 231, 171, 10, 224, 74, 37, 119, 74, 214, 170, 146, 33, 239, 137, 248, 209, 202, 214, 223, 69, 241, 174, 17, 111, 112, 199, 237, 144, 54, 173, 12, 85, 60, 130, 244, 77, 6, 176, 28, 63, 154, 236, 155, 160, 200, 151, 129, 231, 183, 179, 113, 183, 139, 113, 192, 61, 87, 106, 188, 170, 120, 185, 74, 3, 242, 173, 156, 168, 75, 134, 180, 45, 163, 170, 129, 126, 54, 186, 84, 161, 181, 50, 45, 80, 241, 8, 250, 148, 218, 15, 120, 243, 103, 115, 82, 133, 30, 102, 85, 219, 5, 9, 224, 225, 219, 46, 87, 136, 182, 67, 21, 67, 236, 74, 168, 177, 116, 201, 5, 23, 150, 46, 207, 178, 228, 130, 140, 206, 37, 23, 92, 208, 223, 133, 94, 4, 19, 44, 216, 136, 96, 130, 5, 21, 52, 44, 207, 129, 252, 59, 232, 121, 39, 32, 212, 115, 65, 110, 2, 75, 244, 188, 72, 251, 85, 184, 227, 137, 170, 5, 141, 25, 227, 4, 97, 157, 72, 251, 85, 36, 74, 60, 173, 111, 2, 170, 36, 58, 252, 178, 93, 72, 63, 187, 178, 12, 122, 42, 220, 142, 173, 111, 14, 73, 98, 38, 209, 218, 52, 188, 32, 46, 97, 118, 30, 16, 13, 47, 212, 188, 69, 213, 67, 103, 68, 87, 194, 220, 96, 194, 121, 43, 137, 11, 173, 90, 209, 74, 34, 195, 121, 43, 137, 34, 112, 74, 162, 35, 2, 167, 52, 239, 236, 22, 172, 9, 254, 48, 119, 109, 87, 81, 10, 109, 78, 72, 162, 28, 61, 217, 21, 72, 107, 214, 37, 137, 25, 68, 146, 152, 73, 148, 35, 167, 36, 78, 104, 243, 59, 98, 217, 233, 144, 83, 18, 31, 36, 202, 145, 166, 157, 168, 66, 207, 18, 204, 180, 69, 78, 73, 100, 52, 127, 210, 214, 56, 33, 167, 36, 50, 240, 157, 144, 83, 18, 23, 143, 79, 169, 141, 156, 146, 24, 81, 217, 181, 148, 68, 6, 109, 236, 184, 137, 247, 92, 200, 117, 178, 216, 181, 209, 179, 26, 23, 96, 178, 159, 173, 142, 237, 2, 169, 61, 94, 84, 33, 101, 236, 74, 73, 116, 224, 84, 151, 107, 179, 227, 146, 169, 63, 188, 247, 50, 191, 73, 73, 124, 36, 159, 36, 42, 84, 242, 115, 146, 200, 224, 106, 201, 181, 12, 126, 219, 162, 156, 36, 50, 114, 146, 168, 224, 157, 102, 151, 211, 172, 131, 222, 181, 105, 222, 2, 173, 88, 127, 215, 230, 127, 137, 140, 137, 214, 202, 50, 218, 142, 255, 37, 66, 248, 95, 226, 163, 85, 210, 118, 57, 154, 70, 145, 82, 11, 250, 169, 237, 17, 8, 250, 186, 28, 227, 135, 198, 173, 101, 226, 127, 137, 142, 134, 151, 54, 45, 157, 228, 160, 218, 46, 136, 255, 37, 54, 92, 55, 237, 98, 135, 84, 51, 197, 61, 93, 131, 93, 9, 61, 188, 156, 42, 20, 1, 231, 95, 34, 132, 243, 47, 241, 177, 9, 253, 170, 151, 200, 240, 198, 235, 188, 234, 37, 66, 160, 254, 79, 124, 56, 213, 229, 144, 5, 165, 101, 252, 137, 14, 78, 209, 157, 160, 166, 14, 105, 74, 231, 136, 241, 39, 82, 232, 239, 66, 11, 127, 98, 99, 225, 79, 84, 72, 254, 68, 133, 117, 217, 212, 113, 196, 83, 34, 168, 229, 186, 231, 250, 196, 6, 110, 143, 44, 244, 115, 149, 50, 182, 175, 222, 128, 101, 167, 123, 215, 158, 240, 71, 37, 16, 214, 254, 131, 240, 251, 168, 68, 37, 187, 86, 34, 181, 199, 83, 251, 121, 251, 101, 187, 24, 118, 82, 42, 3, 39, 165, 62, 217, 157, 16, 214, 254, 163, 208, 167, 111, 2, 132, 199, 47, 219, 181, 116, 173, 236, 116, 16, 214, 126, 123, 232, 87, 223, 202, 201, 132, 190, 149, 19, 93, 255, 220, 206, 59, 40, 99, 95, 255, 234, 144, 166, 161, 167, 95, 251, 233, 215, 126, 248, 42, 109, 125, 250, 38, 160, 137, 138, 254, 99, 188, 28, 90, 127, 217, 174, 134, 21, 65, 18, 230, 182, 201, 88, 33, 9, 115, 132, 55, 72, 152, 29, 244, 91, 121, 104, 253, 95, 166, 223, 116, 34, 225, 164, 212, 198, 14, 117, 82, 38, 36, 241, 85, 16, 19, 79, 168, 145, 218, 227, 137, 11, 148, 247, 68, 5, 10, 47, 6, 185, 186, 199, 65, 189, 117, 2, 97, 205, 204, 123, 98, 131, 122, 235, 36, 251, 209, 163, 146, 54, 225, 235, 41, 134, 104, 109, 101, 218, 162, 252, 84, 206, 28, 190, 120, 97, 143, 163, 214, 172, 123, 162, 195, 2, 127, 117, 127, 208, 120, 191, 27, 239, 59, 118, 80, 197, 13, 77, 124, 171, 59, 131, 40, 116, 169, 150, 206, 131, 51, 72, 215, 194, 212, 61, 241, 209, 180, 109, 85, 77, 91, 219, 161, 215, 230, 60, 113, 34, 2, 19, 136, 32, 65, 98, 26, 121, 4, 2, 4, 205, 249, 221, 211, 137, 121, 34, 196, 19, 27, 118, 165, 221, 228, 203, 90, 153, 60, 209, 209, 233, 137, 10, 46, 61, 81, 33, 91, 122, 226, 130, 174, 37, 31, 121, 34, 195, 19, 27, 79, 118, 39, 242, 68, 134, 242, 207, 119, 212, 224, 105, 93, 107, 191, 19, 27, 223, 137, 16, 95, 57, 217, 238, 68, 198, 195, 108, 119, 34, 195, 164, 233, 78, 92, 248, 148, 142, 113, 66, 79, 191, 35, 102, 209, 195, 48, 235, 146, 77, 56, 41, 181, 185, 233, 187, 100, 159, 171, 65, 69, 85, 91, 213, 30, 64, 80, 247, 60, 63, 183, 131, 192, 96, 194, 182, 151, 154, 126, 83, 143, 120, 7, 77, 253, 248, 155, 221, 161, 105, 151, 47, 134, 121, 78, 131, 235, 182, 122, 122, 74, 91, 155, 150, 221, 169, 15, 218, 180, 236, 135, 78, 152, 185, 100, 141, 247, 92, 14, 253, 108, 253, 198, 251, 73, 189, 245, 37, 86, 238, 111, 91, 134, 43, 170, 218, 54, 253, 134, 207, 53, 81, 81, 213, 22, 65, 168, 182, 140, 163, 245, 215, 50, 14, 79, 235, 100, 229, 155, 160, 143, 86, 134, 89, 5, 145, 164, 92, 208, 147, 221, 137, 142, 198, 219, 94, 195, 37, 197, 245, 243, 185, 81, 119, 162, 131, 97, 86, 161, 238, 68, 70, 67, 207, 111, 39, 46, 158, 214, 55, 1, 229, 118, 162, 67, 169, 106, 250, 21, 69, 254, 77, 217, 107, 58, 81, 226, 201, 238, 244, 166, 19, 27, 222, 116, 162, 130, 122, 167, 107, 58, 145, 17, 161, 113, 211, 137, 12, 78, 211, 137, 10, 77, 39, 42, 80, 170, 147, 117, 79, 135, 180, 19, 27, 240, 181, 255, 144, 67, 51, 212, 61, 143, 116, 178, 78, 234, 68, 72, 46, 220, 46, 145, 193, 223, 105, 214, 219, 78, 56, 159, 14, 53, 203, 52, 78, 104, 57, 151, 216, 96, 31, 63, 14, 84, 113, 170, 64, 40, 172, 218, 126, 211, 38, 23, 165, 44, 104, 254, 100, 252, 47, 247, 45, 128, 154, 86, 236, 127, 179, 115, 207, 29, 90, 155, 230, 45, 170, 144, 62, 51, 109, 6, 17, 82, 50, 137, 148, 204, 153, 194, 57, 98, 81, 235, 144, 36, 35, 193, 238, 218, 206, 149, 129, 50, 110, 39, 77, 168, 231, 34, 209, 58, 217, 86, 11, 22, 149, 136, 189, 117, 46, 209, 161, 238, 121, 176, 102, 198, 91, 246, 67, 60, 173, 111, 2, 164, 149, 97, 222, 130, 84, 211, 6, 213, 212, 185, 196, 71, 195, 148, 115, 137, 12, 30, 241, 94, 229, 92, 98, 195, 145, 164, 237, 98, 160, 138, 155, 174, 101, 8, 224, 234, 120, 118, 196, 174, 212, 128, 154, 38, 231, 18, 27, 18, 229, 188, 56, 151, 232, 224, 239, 179, 211, 185, 196, 134, 243, 233, 26, 122, 21, 122, 230, 70, 206, 37, 66, 218, 46, 168, 85, 173, 125, 11, 114, 46, 241, 65, 130, 238, 239, 218, 127, 16, 77, 219, 148, 253, 147, 166, 77, 91, 95, 165, 221, 58, 105, 245, 7, 146, 182, 11, 181, 54, 13, 39, 83, 39, 185, 68, 115, 183, 106, 115, 66, 146, 182, 11, 194, 73, 159, 11, 146, 180, 93, 146, 182, 235, 225, 205, 221, 218, 192, 188, 133, 159, 219, 161, 166, 237, 55, 59, 109, 164, 109, 155, 166, 249, 169, 34, 212, 61, 63, 128, 39, 101, 163, 11, 81, 120, 49, 104, 129, 87, 215, 118, 232, 155, 238, 218, 213, 240, 190, 222, 234, 218, 46, 64, 20, 234, 164, 76, 42, 121, 185, 135, 38, 222, 153, 23, 8, 175, 197, 46, 209, 161, 185, 68, 5, 154, 94, 250, 186, 68, 70, 98, 181, 46, 145, 65, 157, 148, 105, 93, 34, 67, 127, 21, 183, 227, 18, 27, 21, 117, 137, 14, 9, 20, 115, 188, 123, 58, 81, 184, 59, 145, 58, 41, 93, 34, 196, 37, 6, 192, 223, 245, 209, 115, 226, 196, 55, 251, 211, 18, 23, 78, 250, 100, 79, 75, 100, 172, 165, 142, 163, 167, 37, 66, 168, 111, 75, 124, 248, 51, 34, 232, 245, 45, 145, 65, 215, 46, 204, 30, 142, 59, 161, 134, 109, 131, 71, 158, 84, 72, 125, 75, 124, 160, 190, 37, 42, 232, 155, 160, 214, 172, 171, 66, 223, 18, 29, 24, 131, 123, 21, 88, 111, 173, 170, 61, 135, 79, 169, 141, 248, 23, 123, 7, 241, 67, 88, 235, 235, 122, 222, 157, 230, 113, 59, 175, 146, 237, 119, 137, 87, 215, 118, 84, 180, 209, 214, 102, 248, 55, 101, 77, 54, 227, 174, 169, 233, 155, 160, 142, 212, 101, 114, 93, 192, 86, 49, 90, 62, 169, 225, 205, 139, 83, 243, 226, 228, 80, 139, 245, 173, 134, 36, 229, 162, 240, 90, 250, 52, 232, 175, 67, 81, 218, 142, 252, 166, 77, 50, 135, 166, 218, 13, 164, 229, 147, 244, 61, 36, 41, 215, 210, 44, 104, 189, 37, 66, 214, 91, 162, 66, 171, 183, 196, 5, 101, 217, 12, 106, 188, 14, 248, 145, 146, 112, 79, 16, 240, 209, 182, 225, 133, 86, 110, 98, 71, 149, 5, 170, 56, 245, 4, 84, 105, 73, 90, 247, 185, 24, 84, 145, 136, 224, 105, 223, 211, 254, 67, 237, 123, 40, 66, 67, 235, 123, 242, 163, 8, 18, 79, 134, 190, 162, 143, 34, 72, 168, 116, 218, 239, 179, 53, 235, 40, 66, 163, 176, 114, 220, 10, 125, 210, 165, 190, 191, 30, 67, 17, 28, 208, 165, 22, 181, 186, 106, 63, 59, 218, 247, 184, 209, 190, 8, 181, 221, 160, 125, 46, 251, 253, 153, 23, 180, 143, 226, 155, 54, 118, 140, 19, 82, 237, 31, 128, 235, 90, 6, 1, 250, 185, 188, 101, 71, 56, 233, 241, 55, 252, 46, 231, 107, 113, 39, 7, 173, 216, 223, 150, 14, 161, 255, 184, 181, 117, 45, 89, 177, 174, 237, 18, 74, 4, 57, 72, 106, 25, 69, 112, 254, 37, 79, 184, 36, 49, 115, 136, 149, 219, 250, 201, 22, 212, 180, 85, 201, 107, 93, 162, 69, 41, 232, 105, 102, 202, 80, 123, 32, 241, 100, 13, 109, 2, 16, 44, 100, 177, 119, 38, 156, 102, 157, 8, 173, 239, 106, 59, 194, 117, 53, 204, 77, 243, 80, 214, 31, 10, 202, 149, 220, 12, 131, 214, 73, 58, 210, 181, 140, 246, 187, 46, 72, 251, 158, 75, 117, 101, 226, 197, 64, 215, 146, 206, 113, 43, 212, 52, 217, 12, 184, 174, 37, 63, 63, 149, 132, 235, 74, 152, 31, 60, 2, 225, 59, 157, 78, 213, 116, 101, 130, 200, 109, 136, 126, 178, 109, 249, 128, 86, 38, 94, 40, 2, 106, 128, 11, 71, 8, 101, 205, 78, 106, 234, 160, 70, 97, 37, 233, 100, 136, 65, 179, 147, 90, 34, 131, 42, 110, 14, 142, 16, 203, 46, 55, 129, 37, 46, 220, 4, 150, 168, 224, 17, 164, 234, 61, 228, 249, 77, 188, 116, 34, 73, 204, 34, 214, 254, 251, 231, 214, 254, 99, 160, 177, 243, 143, 107, 188, 234, 241, 74, 78, 73, 212, 170, 118, 82, 0, 127, 199, 184, 221, 3, 3, 60, 162, 138, 219, 2, 20, 144, 147, 140, 36, 192, 93, 151, 74, 117, 22, 80, 247, 188, 0, 60, 177, 66, 107, 130, 227, 178, 155, 7, 16, 192, 141, 166, 100, 90, 191, 45, 34, 192, 187, 237, 228, 57, 201, 8, 3, 206, 75, 209, 250, 255, 22, 163, 150, 91, 181, 68, 170, 233, 55, 110, 198, 193, 162, 152, 101, 123, 22, 248, 92, 142, 233, 51, 160, 85, 237, 132, 219, 33, 101, 251, 237, 53, 122, 109, 207, 106, 1, 173, 109, 243, 27, 63, 208, 197, 222, 26, 28, 160, 105, 163, 138, 31, 90, 155, 134, 151, 132, 54, 39, 180, 11, 162, 43, 19, 171, 180, 93, 3, 222, 120, 63, 211, 50, 251, 220, 30, 104, 253, 182, 14, 52, 109, 223, 217, 113, 192, 218, 80, 52, 222, 79, 237, 49, 158, 246, 159, 149, 45, 209, 211, 220, 232, 103, 90, 160, 249, 115, 61, 182, 142, 82, 123, 252, 129, 115, 137, 30, 102, 151, 99, 137, 143, 230, 79, 181, 43, 39, 104, 177, 119, 28, 75, 140, 104, 188, 222, 58, 65, 170, 165, 183, 58, 150, 24, 161, 77, 186, 43, 67, 142, 37, 62, 28, 75, 84, 160, 109, 25, 85, 76, 177, 68, 135, 71, 208, 243, 251, 77, 213, 34, 254, 109, 13, 39, 212, 184, 34, 89, 226, 2, 79, 106, 170, 154, 58, 85, 40, 209, 34, 150, 24, 177, 54, 31, 249, 147, 148, 149, 248, 240, 136, 182, 117, 43, 145, 161, 46, 29, 127, 84, 116, 57, 198, 9, 165, 227, 86, 98, 195, 202, 55, 65, 209, 59, 179, 149, 8, 81, 141, 217, 74, 100, 240, 8, 132, 103, 173, 196, 133, 182, 93, 170, 37, 99, 156, 144, 246, 91, 43, 81, 226, 43, 250, 168, 53, 187, 18, 29, 238, 140, 118, 37, 46, 90, 221, 82, 7, 81, 56, 169, 83, 61, 119, 113, 179, 18, 27, 60, 242, 48, 251, 173, 43, 209, 161, 180, 211, 113, 164, 141, 43, 86, 166, 149, 8, 33, 73, 233, 24, 155, 76, 1, 8, 34, 16, 225, 153, 108, 133, 22, 248, 39, 107, 102, 208, 36, 146, 248, 240, 230, 110, 69, 147, 72, 162, 99, 87, 66, 147, 72, 226, 226, 93, 223, 4, 109, 84, 201, 72, 34, 68, 215, 146, 223, 155, 200, 240, 8, 132, 135, 157, 196, 133, 75, 152, 157, 68, 134, 166, 18, 126, 132, 178, 185, 73, 148, 208, 201, 174, 116, 170, 18, 7, 245, 92, 208, 55, 109, 18, 29, 169, 154, 54, 137, 12, 106, 187, 65, 77, 226, 226, 249, 109, 143, 49, 78, 200, 191, 211, 73, 168, 73, 156, 144, 96, 2, 8, 80, 107, 203, 36, 54, 214, 122, 14, 210, 182, 12, 147, 248, 240, 8, 114, 77, 100, 104, 125, 247, 116, 82, 133, 92, 19, 27, 82, 123, 156, 105, 226, 162, 249, 179, 181, 105, 131, 150, 93, 223, 116, 87, 66, 76, 19, 27, 184, 173, 64, 76, 37, 46, 34, 72, 64, 173, 75, 37, 50, 90, 85, 242, 66, 46, 153, 166, 126, 236, 232, 253, 69, 84, 98, 3, 119, 109, 165, 18, 27, 88, 106, 191, 35, 165, 18, 29, 186, 158, 119, 196, 143, 42, 14, 41, 149, 248, 224, 173, 78, 250, 100, 72, 169, 68, 136, 183, 46, 236, 53, 164, 109, 23, 82, 42, 17, 162, 181, 233, 251, 46, 244, 77, 39, 138, 24, 43, 164, 84, 34, 3, 73, 74, 183, 40, 5, 45, 246, 14, 122, 117, 79, 164, 84, 162, 3, 74, 37, 42, 232, 92, 175, 105, 137, 86, 170, 68, 136, 54, 217, 252, 222, 208, 252, 153, 252, 49, 11, 163, 202, 68, 235, 187, 84, 137, 150, 42, 102, 72, 39, 20, 191, 146, 197, 252, 205, 159, 218, 9, 249, 131, 174, 37, 83, 227, 253, 148, 248, 200, 79, 137, 10, 174, 253, 62, 149, 73, 251, 249, 206, 128, 4, 109, 242, 93, 177, 243, 202, 22, 248, 55, 101, 186, 84, 63, 39, 219, 174, 1, 149, 218, 206, 209, 39, 141, 44, 60, 209, 252, 217, 233, 212, 81, 218, 86, 246, 154, 42, 110, 142, 111, 202, 90, 179, 238, 137, 86, 166, 109, 120, 57, 144, 172, 164, 160, 138, 71, 28, 242, 149, 69, 120, 227, 253, 86, 247, 100, 219, 64, 165, 58, 173, 140, 165, 195, 184, 25, 228, 13, 125, 179, 171, 104, 219, 230, 45, 135, 36, 224, 10, 241, 205, 142, 45, 74, 203, 178, 61, 138, 194, 213, 210, 101, 144, 123, 174, 36, 241, 109, 155, 93, 80, 107, 78, 137, 16, 143, 160, 166, 237, 183, 199, 139, 249, 81, 171, 227, 165, 19, 85, 232, 249, 93, 187, 172, 3, 238, 154, 82, 98, 131, 47, 90, 189, 211, 33, 109, 242, 53, 45, 23, 98, 240, 78, 83, 74, 100, 104, 20, 86, 75, 39, 186, 208, 167, 236, 247, 37, 81, 194, 249, 116, 72, 255, 45, 246, 37, 177, 193, 151, 68, 5, 107, 45, 243, 44, 118, 168, 117, 45, 238, 111, 156, 190, 121, 73, 116, 176, 216, 17, 63, 218, 37, 209, 209, 170, 56, 169, 66, 187, 36, 62, 150, 92, 18, 21, 214, 74, 166, 245, 147, 130, 82, 123, 28, 37, 66, 232, 106, 90, 110, 63, 106, 118, 65, 137, 14, 136, 10, 120, 8, 235, 160, 227, 89, 144, 210, 86, 10, 59, 164, 106, 29, 124, 136, 32, 65, 61, 23, 180, 14, 54, 30, 117, 208, 241, 84, 212, 65, 5, 181, 92, 81, 7, 25, 214, 254, 107, 52, 188, 156, 89, 236, 74, 136, 43, 234, 32, 35, 151, 166, 35, 84, 212, 65, 70, 82, 21, 161, 162, 14, 46, 114, 105, 26, 241, 163, 138, 58, 248, 88, 154, 70, 21, 117, 112, 81, 81, 7, 31, 180, 162, 16, 223, 180, 97, 37, 244, 36, 220, 234, 112, 187, 5, 144, 43, 107, 117, 176, 65, 91, 29, 84, 80, 13, 124, 80, 134, 220, 82, 7, 23, 206, 29, 109, 147, 177, 114, 231, 78, 72, 226, 149, 45, 117, 144, 65, 162, 188, 129, 215, 82, 7, 37, 90, 155, 134, 87, 132, 71, 214, 74, 197, 86, 29, 132, 120, 90, 70, 72, 171, 14, 50, 158, 73, 170, 131, 11, 142, 61, 229, 82, 29, 100, 56, 5, 143, 64, 96, 204, 221, 208, 12, 212, 51, 33, 124, 168, 131, 1, 136, 44, 140, 92, 215, 58, 192, 239, 235, 160, 86, 14, 66, 60, 42, 81, 14, 46, 248, 226, 160, 2, 9, 37, 29, 84, 208, 182, 222, 58, 73, 7, 27, 159, 14, 42, 88, 253, 60, 157, 236, 231, 233, 160, 227, 61, 29, 116, 76, 188, 167, 98, 136, 127, 177, 119, 16, 127, 4, 37, 187, 65, 210, 118, 33, 9, 163, 71, 241, 130, 124, 31, 60, 159, 14, 3, 165, 74, 233, 194, 20, 121, 58, 40, 209, 180, 109, 199, 211, 65, 134, 75, 182, 112, 124, 155, 182, 143, 198, 203, 224, 119, 225, 84, 161, 102, 6, 57, 158, 14, 66, 218, 46, 158, 14, 50, 180, 206, 71, 223, 202, 73, 67, 21, 167, 109, 175, 201, 231, 175, 160, 38, 31, 241, 35, 79, 7, 39, 42, 200, 211, 65, 10, 167, 170, 80, 163, 48, 242, 116, 16, 242, 172, 198, 200, 39, 236, 32, 79, 7, 27, 143, 133, 87, 211, 236, 208, 228, 98, 60, 29, 148, 112, 79, 7, 31, 46, 97, 118, 80, 106, 143, 63, 172, 183, 68, 158, 14, 50, 60, 29, 84, 240, 73, 23, 163, 141, 158, 198, 172, 211, 193, 7, 138, 79, 71, 117, 58, 184, 208, 70, 170, 211, 65, 135, 116, 176, 161, 211, 65, 135, 36, 165, 123, 156, 75, 7, 27, 188, 16, 216, 185, 116, 144, 1, 89, 208, 84, 194, 143, 90, 59, 117, 89, 151, 14, 50, 88, 151, 14, 42, 120, 68, 21, 55, 228, 116, 45, 249, 141, 125, 237, 63, 136, 119, 141, 60, 184, 132, 178, 108, 230, 1, 239, 92, 28, 77, 91, 231, 17, 66, 252, 45, 87, 129, 103, 233, 96, 163, 105, 171, 58, 29, 71, 207, 210, 193, 6, 143, 180, 50, 150, 14, 50, 60, 178, 88, 58, 200, 224, 173, 77, 191, 133, 165, 131, 14, 143, 32, 9, 14, 46, 72, 112, 48, 0, 174, 238, 105, 40, 170, 68, 112, 16, 18, 129, 35, 56, 168, 208, 234, 220, 86, 52, 184, 216, 138, 6, 27, 186, 60, 201, 144, 219, 138, 246, 26, 132, 52, 188, 22, 206, 47, 115, 253, 109, 231, 16, 220, 86, 108, 82, 246, 159, 43, 114, 136, 192, 48, 76, 137, 192, 252, 35, 183, 158, 191, 190, 203, 103, 104, 243, 123, 51, 241, 102, 226, 223, 152, 105, 38, 30, 193, 27, 167, 93, 192, 252, 71, 104, 38, 148, 116, 90, 177, 222, 88, 75, 29, 255, 182, 11, 185, 167, 187, 167, 191, 126, 52, 207, 113, 115, 83, 199, 109, 89, 43, 99, 136, 135, 170, 140, 52, 168, 243, 104, 125, 102, 6, 162, 107, 153, 10, 131, 252, 134, 3, 183, 108, 238, 109, 153, 187, 123, 66, 159, 169, 241, 131, 54, 94, 134, 67, 75, 93, 234, 204, 17, 74, 155, 150, 14, 68, 45, 93, 114, 113, 56, 37, 145, 91, 175, 193, 7, 183, 94, 131, 10, 239, 182, 147, 218, 215, 224, 131, 187, 190, 6, 33, 77, 37, 252, 13, 50, 56, 227, 43, 250, 18, 109, 89, 51, 241, 111, 187, 116, 61, 255, 208, 40, 233, 124, 45, 117, 252, 209, 94, 55, 60, 204, 62, 67, 180, 105, 17, 173, 20, 109, 78, 98, 214, 171, 36, 108, 89, 6, 13, 47, 244, 164, 108, 116, 37, 235, 148, 60, 18, 43, 143, 36, 173, 168, 99, 210, 212, 73, 159, 148, 230, 185, 167, 183, 55, 97, 194, 93, 151, 71, 34, 190, 173, 227, 145, 182, 76, 155, 100, 187, 108, 177, 95, 224, 157, 139, 131, 182, 204, 253, 113, 156, 208, 103, 106, 20, 12, 90, 234, 74, 104, 217, 254, 137, 198, 105, 87, 106, 60, 204, 66, 44, 93, 114, 121, 72, 248, 183, 215, 13, 54, 88, 148, 226, 82, 195, 200, 79, 149, 175, 12, 37, 215, 13, 82, 36, 215, 13, 42, 60, 12, 139, 194, 221, 224, 130, 62, 125, 19, 144, 210, 6, 111, 58, 145, 123, 220, 13, 58, 156, 65, 18, 146, 196, 171, 169, 118, 131, 13, 109, 242, 155, 166, 86, 135, 158, 252, 156, 48, 42, 118, 194, 157, 146, 65, 104, 112, 10, 90, 19, 90, 155, 124, 120, 242, 160, 212, 129, 7, 109, 25, 85, 170, 161, 105, 188, 220, 163, 221, 170, 74, 25, 212, 128, 164, 153, 65, 190, 152, 223, 117, 127, 153, 31, 173, 9, 12, 36, 233, 45, 135, 154, 124, 180, 38, 52, 249, 143, 214, 111, 187, 38, 124, 211, 215, 79, 174, 134, 92, 8, 240, 198, 187, 60, 6, 90, 153, 105, 139, 212, 59, 221, 2, 190, 109, 89, 211, 214, 185, 100, 238, 251, 128, 0, 10, 224, 224, 81, 73, 131, 84, 28, 249, 141, 60, 244, 83, 33, 246, 133, 112, 255, 78, 101, 151, 58, 13, 174, 16, 174, 150, 46, 35, 65, 0, 157, 236, 39, 221, 236, 247, 198, 13, 180, 7, 28, 212, 215, 4, 237, 156, 104, 117, 254, 57, 208, 86, 135, 242, 180, 68, 16, 107, 194, 226, 105, 120, 177, 99, 217, 197, 88, 19, 214, 65, 186, 246, 161, 245, 127, 151, 115, 164, 76, 35, 22, 115, 114, 92, 118, 131, 11, 60, 226, 234, 178, 27, 100, 36, 75, 80, 227, 91, 118, 131, 11, 142, 223, 85, 118, 131, 140, 166, 173, 174, 202, 110, 240, 97, 61, 70, 83, 118, 131, 12, 95, 151, 175, 234, 56, 63, 183, 147, 104, 117, 217, 201, 209, 147, 203, 125, 74, 237, 136, 10, 47, 46, 217, 186, 68, 238, 146, 185, 100, 143, 101, 215, 130, 74, 54, 14, 255, 198, 204, 4, 3, 23, 64, 197, 153, 129, 202, 107, 187, 28, 240, 5, 114, 146, 17, 212, 64, 235, 90, 231, 188, 82, 131, 167, 179, 95, 34, 93, 205, 132, 86, 168, 190, 9, 222, 160, 139, 189, 113, 66, 138, 185, 65, 136, 98, 110, 80, 97, 57, 114, 80, 135, 92, 87, 86, 52, 110, 240, 209, 111, 53, 168, 208, 94, 163, 111, 53, 184, 112, 167, 10, 65, 30, 102, 151, 175, 6, 23, 77, 37, 252, 13, 24, 70, 255, 56, 66, 125, 185, 57, 92, 219, 50, 170, 208, 132, 250, 114, 67, 45, 183, 81, 184, 23, 180, 242, 83, 54, 131, 150, 175, 6, 25, 104, 26, 94, 13, 46, 248, 66, 69, 155, 23, 218, 114, 228, 89, 24, 90, 43, 158, 117, 222, 225, 137, 21, 242, 133, 86, 236, 202, 166, 161, 165, 173, 189, 159, 88, 233, 192, 88, 121, 4, 173, 244, 94, 133, 86, 246, 42, 180, 82, 61, 151, 8, 11, 175, 6, 27, 142, 231, 114, 180, 240, 106, 28, 144, 71, 196, 90, 137, 22, 94, 13, 50, 22, 94, 13, 42, 248, 227, 70, 51, 203, 213, 32, 3, 203, 213, 160, 66, 132, 164, 19, 180, 26, 92, 172, 253, 167, 253, 190, 162, 95, 209, 79, 201, 244, 243, 229, 61, 75, 237, 7, 253, 124, 134, 146, 160, 34, 184, 74, 214, 57, 90, 13, 62, 32, 42, 188, 160, 213, 96, 131, 146, 208, 250, 159, 201, 209, 106, 16, 242, 249, 38, 160, 213, 224, 66, 69, 80, 143, 87, 250, 182, 236, 208, 106, 240, 65, 73, 120, 94, 238, 121, 57, 199, 181, 178, 221, 136, 64, 66, 132, 79, 134, 86, 131, 139, 93, 17, 92, 178, 79, 117, 208, 106, 16, 210, 186, 214, 53, 232, 128, 23, 6, 173, 6, 25, 148, 132, 213, 160, 67, 69, 232, 199, 15, 81, 18, 180, 113, 66, 171, 193, 134, 146, 224, 90, 73, 180, 26, 108, 172, 6, 3, 176, 250, 253, 54, 200, 208, 240, 250, 109, 54, 33, 7, 100, 96, 166, 237, 111, 131, 139, 70, 8, 10, 118, 218, 200, 129, 223, 166, 159, 123, 66, 220, 204, 132, 90, 251, 22, 200, 186, 68, 14, 100, 104, 20, 86, 191, 13, 46, 152, 151, 223, 86, 127, 173, 254, 148, 54, 74, 58, 9, 8, 210, 97, 120, 147, 143, 214, 119, 194, 0, 132, 178, 108, 204, 180, 69, 236, 26, 86, 63, 212, 182, 217, 102, 164, 207, 108, 129, 182, 93, 232, 37, 14, 169, 212, 142, 240, 95, 198, 56, 33, 74, 182, 122, 55, 180, 145, 210, 109, 144, 226, 125, 151, 36, 37, 250, 109, 208, 65, 151, 223, 6, 33, 21, 12, 206, 167, 67, 191, 13, 62, 184, 108, 10, 179, 13, 46, 60, 130, 62, 61, 102, 27, 108, 232, 74, 235, 204, 54, 200, 96, 182, 193, 71, 67, 227, 253, 109, 205, 162, 119, 118, 26, 116, 248, 182, 11, 65, 218, 74, 90, 157, 6, 23, 206, 191, 116, 26, 100, 112, 109, 210, 33, 167, 65, 198, 115, 131, 156, 6, 25, 28, 244, 77, 208, 130, 102, 244, 21, 253, 215, 6, 35, 94, 27, 108, 56, 191, 54, 184, 144, 146, 189, 54, 200, 160, 22, 233, 242, 254, 241, 227, 175, 13, 78, 248, 107, 131, 14, 14, 90, 151, 109, 242, 116, 249, 91, 253, 182, 223, 194, 155, 78, 196, 212, 121, 244, 140, 155, 65, 139, 23, 246, 16, 160, 173, 250, 70, 106, 71, 175, 13, 46, 94, 27, 140, 168, 44, 163, 237, 28, 223, 236, 216, 105, 163, 70, 2, 241, 165, 149, 117, 150, 237, 96, 166, 45, 122, 109, 16, 194, 159, 111, 117, 173, 236, 53, 69, 141, 194, 232, 181, 65, 3, 176, 211, 230, 198, 12, 189, 54, 184, 64, 27, 100, 252, 50, 164, 245, 182, 253, 109, 157, 79, 135, 84, 123, 249, 169, 144, 54, 216, 144, 159, 10, 185, 67, 30, 95, 241, 156, 52, 137, 181, 50, 161, 215, 6, 31, 92, 27, 116, 192, 48, 251, 172, 13, 46, 92, 83, 50, 175, 140, 181, 193, 137, 101, 23, 107, 131, 12, 63, 113, 168, 182, 20, 109, 135, 246, 240, 252, 66, 164, 118, 34, 214, 6, 23, 250, 187, 144, 91, 214, 6, 29, 204, 91, 88, 27, 100, 168, 120, 196, 218, 32, 67, 106, 143, 55, 109, 112, 209, 180, 193, 71, 123, 76, 211, 6, 25, 22, 179, 131, 164, 109, 208, 207, 245, 185, 92, 235, 90, 94, 154, 23, 240, 240, 149, 247, 231, 133, 91, 66, 53, 83, 220, 211, 61, 239, 128, 61, 210, 0, 70, 108, 132, 153, 54, 200, 208, 58, 217, 86, 44, 73, 218, 224, 99, 73, 246, 92, 27, 121, 106, 144, 194, 53, 53, 232, 104, 185, 238, 47, 27, 100, 104, 243, 178, 193, 133, 8, 19, 180, 0, 9, 14, 241, 149, 71, 254, 188, 176, 131, 86, 73, 51, 69, 211, 78, 90, 221, 147, 54, 253, 28, 131, 7, 237, 142, 252, 155, 54, 94, 8, 112, 117, 60, 151, 103, 63, 210, 212, 204, 28, 128, 194, 39, 112, 69, 5, 240, 220, 149, 12, 168, 226, 54, 177, 43, 161, 103, 241, 207, 6, 29, 13, 54, 36, 99, 217, 224, 130, 191, 79, 185, 178, 65, 134, 182, 93, 234, 214, 161, 6, 1, 4, 13, 54, 248, 67, 134, 163, 69, 13, 46, 52, 8, 0, 4, 121, 42, 42, 30, 131, 11, 107, 229, 82, 81, 241, 24, 100, 248, 91, 14, 61, 180, 109, 181, 178, 162, 226, 49, 232, 96, 148, 196, 65, 109, 249, 31, 131, 15, 100, 216, 126, 12, 42, 60, 21, 110, 151, 172, 213, 181, 199, 96, 131, 79, 210, 65, 78, 161, 218, 143, 148, 54, 90, 249, 64, 89, 54, 8, 202, 178, 45, 112, 204, 75, 181, 93, 16, 54, 40, 203, 182, 214, 99, 16, 242, 210, 162, 181, 30, 131, 12, 119, 207, 160, 130, 123, 6, 39, 220, 51, 168, 160, 45, 197, 25, 92, 96, 206, 32, 164, 169, 118, 114, 6, 23, 17, 156, 65, 5, 206, 167, 91, 169, 13, 193, 25, 124, 64, 112, 6, 27, 217, 95, 81, 8, 206, 32, 67, 125, 153, 254, 54, 5, 57, 131, 20, 142, 233, 35, 103, 112, 225, 206, 96, 131, 65, 135, 191, 229, 22, 143, 74, 26, 187, 94, 37, 97, 200, 25, 132, 104, 109, 90, 25, 114, 6, 27, 146, 148, 238, 53, 130, 156, 65, 7, 68, 246, 51, 82, 123, 60, 101, 114, 20, 161, 107, 25, 244, 56, 228, 12, 66, 188, 98, 45, 238, 228, 72, 53, 53, 81, 77, 23, 208, 250, 159, 12, 125, 227, 102, 16, 242, 136, 192, 184, 25, 92, 96, 220, 12, 42, 60, 139, 111, 51, 200, 224, 184, 54, 147, 200, 225, 155, 157, 106, 51, 200, 208, 102, 208, 145, 90, 182, 164, 153, 242, 144, 218, 227, 13, 212, 13, 170, 243, 53, 202, 178, 25, 116, 120, 4, 66, 51, 248, 72, 217, 12, 42, 52, 248, 35, 199, 224, 66, 51, 82, 45, 145, 99, 176, 225, 250, 235, 16, 190, 54, 153, 70, 168, 246, 152, 193, 5, 165, 170, 147, 210, 204, 224, 131, 71, 152, 177, 15, 173, 220, 214, 79, 134, 36, 43, 33, 89, 93, 75, 170, 117, 228, 167, 82, 197, 13, 229, 167, 98, 205, 12, 54, 172, 253, 247, 104, 173, 255, 233, 208, 179, 32, 7, 79, 74, 150, 12, 106, 245, 123, 112, 88, 182, 60, 111, 192, 179, 191, 162, 19, 40, 63, 85, 196, 38, 118, 79, 196, 154, 25, 124, 240, 0, 55, 228, 175, 128, 102, 6, 31, 205, 191, 141, 217, 195, 55, 109, 18, 53, 180, 78, 22, 45, 153, 106, 143, 187, 209, 102, 6, 226, 164, 212, 102, 6, 23, 78, 85, 33, 6, 207, 183, 162, 102, 6, 35, 248, 121, 225, 70, 223, 152, 193, 136, 95, 201, 55, 102, 112, 129, 190, 49, 131, 16, 95, 204, 32, 132, 174, 124, 201, 98, 6, 25, 15, 179, 141, 86, 181, 152, 193, 135, 203, 126, 228, 47, 113, 219, 245, 111, 129, 55, 222, 119, 204, 192, 61, 238, 6, 249, 75, 204, 224, 3, 66, 99, 112, 161, 44, 27, 106, 12, 46, 42, 111, 49, 72, 81, 121, 139, 65, 5, 93, 75, 254, 54, 165, 65, 194, 29, 127, 139, 65, 7, 87, 251, 22, 131, 12, 74, 221, 243, 142, 119, 154, 93, 142, 29, 84, 203, 133, 32, 32, 174, 238, 121, 68, 225, 197, 60, 40, 218, 46, 136, 194, 139, 65, 198, 243, 98, 80, 225, 87, 178, 152, 31, 185, 93, 12, 66, 158, 95, 73, 218, 197, 32, 163, 149, 97, 158, 35, 130, 218, 110, 42, 188, 84, 116, 49, 8, 233, 214, 73, 46, 6, 23, 249, 169, 80, 69, 191, 117, 130, 38, 154, 210, 239, 247, 207, 197, 224, 194, 63, 23, 131, 15, 117, 82, 38, 71, 46, 6, 29, 62, 23, 131, 10, 222, 228, 98, 112, 193, 61, 33, 108, 88, 107, 37, 12, 46, 236, 67, 79, 69, 197, 50, 232, 16, 241, 48, 219, 239, 43, 203, 96, 35, 2, 146, 208, 181, 228, 163, 252, 84, 72, 105, 101, 25, 132, 120, 254, 151, 193, 133, 167, 213, 241, 101, 112, 241, 222, 203, 160, 4, 107, 166, 48, 124, 49, 127, 131, 182, 76, 105, 59, 190, 109, 25, 100, 68, 240, 8, 58, 40, 109, 203, 224, 66, 107, 91, 6, 185, 247, 136, 240, 187, 170, 45, 131, 12, 17, 158, 185, 37, 205, 20, 212, 58, 159, 7, 206, 47, 69, 223, 202, 137, 195, 61, 215, 181, 228, 166, 47, 224, 202, 178, 161, 119, 253, 103, 110, 120, 234, 197, 51, 55, 130, 52, 18, 70, 175, 66, 223, 180, 31, 26, 123, 4, 69, 60, 73, 65, 15, 83, 198, 14, 202, 73, 70, 28, 90, 61, 162, 162, 202, 225, 13, 174, 203, 150, 46, 80, 109, 25, 124, 168, 182, 12, 42, 56, 67, 169, 147, 30, 63, 122, 245, 6, 252, 37, 102, 32, 244, 115, 189, 180, 50, 81, 120, 4, 107, 102, 208, 202, 182, 12, 58, 34, 11, 59, 24, 43, 180, 14, 212, 161, 245, 215, 50, 8, 89, 107, 25, 180, 214, 50, 171, 237, 146, 9, 53, 109, 215, 50, 148, 79, 169, 253, 224, 17, 173, 88, 103, 188, 58, 69, 119, 162, 237, 144, 54, 201, 214, 1, 117, 207, 107, 197, 58, 82, 118, 186, 150, 193, 2, 172, 126, 200, 225, 97, 150, 101, 83, 58, 105, 245, 6, 186, 150, 193, 5, 222, 119, 49, 84, 123, 236, 120, 4, 66, 91, 78, 143, 213, 207, 249, 116, 136, 31, 109, 63, 8, 117, 207, 79, 124, 190, 86, 108, 227, 25, 78, 122, 71, 67, 30, 30, 89, 60, 157, 109, 23, 228, 219, 120, 189, 233, 59, 72, 154, 153, 230, 207, 182, 21, 169, 144, 191, 111, 229, 193, 211, 223, 20, 194, 191, 233, 90, 6, 27, 116, 45, 131, 10, 174, 253, 154, 101, 112, 241, 186, 154, 101, 144, 97, 2, 147, 10, 168, 226, 86, 1, 111, 93, 150, 65, 7, 247, 164, 146, 23, 106, 24, 116, 64, 52, 234, 24, 195, 32, 131, 126, 46, 134, 65, 134, 117, 217, 208, 50, 12, 50, 158, 126, 109, 10, 7, 253, 85, 220, 36, 36, 137, 153, 195, 53, 246, 200, 3, 31, 28, 63, 108, 103, 211, 148, 193, 197, 243, 207, 201, 145, 123, 72, 25, 82, 170, 12, 70, 40, 85, 6, 21, 210, 73, 202, 224, 194, 4, 174, 8, 37, 92, 194, 236, 32, 95, 208, 234, 124, 42, 131, 13, 189, 138, 65, 5, 197, 96, 0, 180, 241, 74, 12, 50, 252, 194, 160, 2, 135, 32, 143, 44, 12, 54, 120, 100, 97, 80, 97, 97, 176, 209, 146, 45, 12, 62, 22, 6, 3, 160, 79, 50, 232, 160, 79, 50, 168, 224, 141, 211, 78, 146, 193, 6, 19, 22, 212, 59, 221, 210, 181, 178, 211, 45, 74, 105, 218, 182, 78, 74, 211, 36, 197, 117, 45, 235, 77, 29, 61, 204, 62, 203, 105, 163, 135, 217, 135, 217, 167, 68, 148, 45, 117, 30, 197, 11, 107, 102, 90, 87, 194, 238, 218, 204, 250, 195, 236, 195, 90, 201, 244, 87, 244, 223, 117, 173, 100, 78, 128, 119, 141, 80, 7, 58, 33, 73, 187, 210, 51, 47, 207, 188, 48, 88, 133, 165, 246, 251, 231, 35, 151, 108, 229, 155, 160, 18, 233, 202, 164, 163, 247, 93, 238, 213, 145, 210, 247, 100, 40, 143, 180, 53, 245, 94, 160, 21, 203, 76, 25, 196, 29, 243, 122, 79, 102, 226, 97, 118, 45, 249, 190, 128, 147, 62, 146, 182, 149, 189, 230, 235, 176, 240, 106, 26, 204, 44, 227, 43, 223, 4, 125, 48, 204, 170, 135, 7, 19, 103, 164, 8, 18, 82, 167, 135, 36, 169, 147, 84, 219, 165, 241, 158, 12, 58, 28, 79, 135, 117, 50, 200, 208, 212, 201, 224, 66, 227, 180, 239, 249, 45, 25, 124, 188, 235, 59, 26, 94, 13, 207, 73, 203, 132, 158, 212, 146, 65, 200, 163, 190, 146, 65, 134, 165, 76, 174, 100, 112, 209, 42, 73, 6, 23, 154, 124, 198, 162, 148, 86, 36, 201, 160, 131, 63, 4, 199, 234, 109, 208, 211, 252, 41, 25, 132, 52, 164, 237, 37, 25, 100, 112, 125, 20, 21, 152, 111, 219, 206, 191, 162, 232, 80, 10, 225, 182, 226, 43, 250, 12, 72, 82, 190, 191, 99, 136, 235, 90, 166, 193, 29, 31, 11, 175, 230, 43, 138, 139, 230, 95, 229, 234, 15, 173, 140, 230, 110, 136, 8, 11, 100, 88, 57, 81, 212, 120, 31, 26, 191, 183, 165, 52, 71, 52, 222, 213, 79, 194, 93, 87, 123, 221, 192, 109, 69, 131, 210, 126, 190, 63, 204, 46, 119, 135, 135, 150, 186, 152, 151, 214, 127, 220, 200, 87, 238, 119, 186, 230, 7, 206, 178, 211, 33, 6, 52, 94, 119, 117, 180, 38, 248, 195, 22, 52, 109, 155, 134, 151, 127, 91, 118, 170, 41, 122, 223, 197, 224, 41, 145, 198, 251, 201, 17, 6, 173, 191, 150, 113, 11, 225, 254, 27, 144, 36, 117, 146, 243, 43, 213, 65, 238, 218, 203, 195, 59, 151, 7, 199, 115, 49, 154, 118, 162, 74, 255, 117, 131, 243, 47, 37, 22, 80, 224, 98, 229, 68, 81, 187, 138, 98, 227, 97, 150, 161, 238, 223, 19, 79, 136, 191, 193, 117, 45, 131, 16, 134, 97, 73, 202, 5, 173, 220, 138, 226, 132, 235, 167, 114, 15, 34, 81, 142, 90, 39, 173, 254, 72, 138, 115, 135, 198, 30, 121, 216, 149, 24, 253, 214, 210, 152, 44, 94, 221, 29, 187, 154, 182, 46, 17, 187, 138, 34, 132, 210, 5, 30, 129, 192, 43, 209, 170, 175, 206, 61, 136, 119, 154, 109, 202, 147, 203, 69, 104, 51, 123, 124, 66, 216, 232, 212, 231, 161, 106, 45, 4, 31, 176, 209, 204, 86, 20, 23, 60, 130, 152, 173, 40, 46, 124, 93, 27, 173, 40, 106, 188, 14, 142, 181, 210, 241, 5, 164, 149, 97, 222, 130, 146, 86, 20, 31, 8, 73, 70, 81, 84, 120, 84, 194, 21, 112, 19, 69, 135, 229, 181, 227, 168, 169, 118, 211, 58, 81, 124, 208, 212, 143, 31, 173, 77, 223, 119, 61, 188, 211, 228, 106, 23, 17, 248, 217, 58, 142, 94, 155, 206, 143, 88, 158, 47, 207, 65, 252, 243, 33, 28, 243, 146, 104, 114, 33, 199, 188, 248, 147, 58, 111, 139, 28, 51, 133, 254, 46, 199, 175, 164, 225, 128, 13, 75, 211, 113, 217, 72, 39, 138, 15, 157, 40, 42, 200, 137, 98, 3, 77, 20, 29, 107, 255, 183, 61, 135, 243, 138, 13, 103, 120, 93, 43, 41, 200, 35, 107, 255, 61, 36, 215, 239, 250, 223, 30, 167, 36, 177, 75, 34, 143, 56, 232, 98, 152, 164, 44, 78, 252, 220, 46, 130, 61, 109, 117, 94, 241, 161, 242, 107, 255, 161, 102, 29, 226, 188, 162, 131, 243, 138, 141, 101, 23, 114, 94, 113, 209, 192, 147, 107, 212, 216, 35, 200, 121, 197, 9, 207, 6, 57, 175, 8, 225, 164, 87, 84, 104, 242, 21, 21, 242, 21, 21, 180, 74, 86, 82, 144, 42, 226, 71, 250, 86, 78, 148, 101, 243, 125, 160, 226, 17, 164, 214, 190, 101, 129, 147, 242, 63, 209, 218, 127, 12, 44, 66, 137, 133, 65, 13, 174, 232, 96, 182, 239, 138, 12, 190, 114, 191, 169, 187, 162, 227, 117, 49, 169, 11, 109, 187, 34, 164, 117, 162, 237, 138, 11, 87, 108, 60, 173, 111, 130, 43, 46, 22, 198, 225, 32, 217, 182, 115, 231, 138, 12, 139, 194, 206, 21, 23, 12, 179, 205, 21, 25, 92, 81, 130, 185, 98, 131, 185, 162, 2, 85, 1, 134, 147, 62, 41, 19, 190, 246, 95, 3, 7, 255, 124, 117, 156, 156, 189, 7, 158, 88, 33, 93, 175, 181, 57, 121, 171, 106, 15, 41, 213, 134, 190, 177, 66, 143, 209, 98, 79, 132, 123, 133, 87, 81, 36, 30, 102, 95, 223, 68, 169, 191, 246, 56, 109, 123, 254, 168, 4, 125, 179, 163, 2, 36, 86, 62, 81, 177, 28, 98, 197, 79, 103, 47, 187, 80, 211, 246, 93, 223, 1, 101, 50, 189, 235, 75, 208, 95, 58, 89, 192, 64, 146, 212, 73, 107, 169, 243, 111, 246, 214, 133, 41, 67, 205, 62, 0, 143, 116, 54, 246, 215, 200, 35, 45, 147, 47, 224, 145, 74, 47, 208, 171, 92, 215, 235, 136, 246, 190, 9, 13, 158, 92, 77, 54, 233, 168, 242, 148, 131, 202, 83, 218, 58, 217, 207, 230, 18, 102, 231, 129, 190, 137, 74, 109, 231, 173, 140, 182, 43, 64, 197, 178, 125, 199, 173, 147, 130, 158, 213, 184, 242, 154, 42, 110, 74, 43, 246, 183, 165, 183, 135, 184, 249, 107, 39, 117, 196, 205, 129, 59, 230, 133, 184, 105, 219, 213, 22, 113, 123, 160, 210, 77, 115, 224, 89, 141, 17, 55, 148, 78, 98, 150, 78, 98, 6, 191, 235, 129, 0, 130, 68, 21, 143, 48, 72, 141, 61, 210, 180, 117, 141, 184, 70, 36, 36, 176, 140, 248, 242, 156, 223, 134, 129, 244, 232, 219, 46, 7, 62, 25, 72, 224, 234, 11, 212, 73, 217, 52, 90, 225, 87, 229, 158, 212, 181, 254, 235, 210, 114, 137, 168, 44, 195, 255, 82, 123, 76, 231, 122, 77, 75, 180, 44, 219, 26, 38, 42, 138, 53, 60, 64, 0, 85, 220, 222, 53, 194, 128, 1, 60, 119, 37, 234, 214, 127, 150, 106, 186, 205, 60, 157, 140, 61, 95, 114, 253, 54, 168, 245, 211, 171, 67, 83, 58, 71, 92, 225, 138, 99, 94, 77, 227, 126, 119, 224, 252, 82, 18, 240, 41, 181, 27, 168, 120, 4, 45, 192, 96, 153, 250, 2, 206, 101, 131, 79, 169, 45, 0, 6, 204, 174, 196, 19, 95, 209, 70, 225, 145, 133, 145, 104, 26, 141, 88, 128, 0, 212, 115, 65, 75, 91, 122, 19, 61, 240, 68, 8, 209, 94, 1, 116, 153, 85, 218, 222, 1, 218, 34, 117, 207, 51, 208, 169, 90, 190, 47, 96, 239, 32, 199, 119, 45, 207, 61, 104, 187, 34, 222, 245, 25, 120, 45, 25, 82, 7, 86, 182, 214, 175, 164, 179, 227, 118, 40, 89, 210, 1, 44, 80, 45, 123, 145, 104, 118, 215, 148, 18, 37, 86, 174, 184, 64, 29, 39, 87, 100, 120, 0, 85, 242, 219, 227, 3, 72, 219, 175, 12, 185, 162, 0, 158, 37, 215, 74, 10, 138, 104, 218, 168, 226, 228, 138, 141, 124, 50, 185, 34, 131, 42, 78, 219, 158, 131, 163, 168, 232, 231, 130, 44, 246, 206, 227, 147, 27, 164, 174, 201, 237, 206, 132, 240, 193, 73, 159, 108, 61, 84, 229, 202, 228, 138, 140, 8, 18, 144, 51, 79, 10, 36, 130, 9, 144, 115, 123, 222, 26, 193, 4, 77, 29, 75, 188, 54, 93, 17, 76, 144, 156, 211, 21, 193, 4, 238, 150, 49, 136, 96, 2, 214, 57, 193, 58, 35, 72, 64, 149, 215, 118, 65, 68, 48, 1, 82, 190, 168, 54, 35, 17, 193, 4, 172, 147, 34, 130, 9, 80, 91, 74, 167, 138, 136, 96, 2, 214, 137, 22, 168, 181, 111, 113, 197, 133, 251, 226, 133, 61, 14, 182, 142, 163, 9, 92, 145, 241, 234, 104, 2, 138, 9, 92, 241, 49, 129, 163, 9, 92, 113, 129, 38, 112, 69, 8, 154, 192, 21, 27, 216, 58, 142, 36, 112, 69, 134, 175, 101, 217, 34, 9, 92, 241, 193, 87, 20, 73, 224, 18, 92, 145, 225, 233, 156, 32, 87, 92, 232, 100, 127, 217, 182, 67, 252, 206, 214, 241, 214, 138, 46, 228, 138, 15, 142, 107, 51, 200, 21, 25, 207, 210, 10, 47, 72, 177, 243, 202, 92, 241, 129, 207, 70, 187, 105, 18, 185, 162, 132, 119, 43, 42, 184, 36, 229, 251, 67, 146, 242, 93, 34, 87, 235, 132, 27, 248, 164, 17, 132, 56, 94, 221, 138, 12, 221, 138, 10, 92, 50, 164, 43, 39, 251, 38, 40, 74, 52, 110, 210, 157, 226, 194, 35, 206, 138, 11, 173, 146, 180, 174, 165, 242, 108, 172, 72, 128, 198, 30, 65, 252, 14, 222, 15, 19, 64, 128, 26, 40, 123, 42, 154, 34, 3, 51, 109, 39, 77, 113, 241, 48, 59, 105, 58, 105, 138, 11, 166, 113, 154, 52, 197, 133, 218, 149, 139, 166, 109, 255, 164, 41, 54, 38, 77, 209, 177, 9, 77, 154, 34, 195, 195, 44, 123, 77, 113, 193, 94, 83, 84, 64, 198, 147, 221, 137, 16, 109, 126, 111, 138, 139, 102, 120, 4, 130, 246, 190, 9, 77, 209, 161, 79, 223, 132, 166, 184, 112, 201, 154, 226, 130, 242, 230, 95, 223, 9, 210, 212, 210, 225, 133, 0, 225, 107, 255, 61, 144, 193, 249, 165, 32, 87, 77, 27, 181, 92, 213, 20, 27, 190, 169, 106, 138, 12, 12, 35, 213, 20, 27, 250, 63, 145, 106, 138, 14, 173, 56, 53, 221, 231, 70, 219, 132, 186, 182, 116, 25, 137, 104, 20, 86, 168, 105, 171, 56, 53, 197, 134, 212, 20, 27, 106, 129, 12, 204, 181, 136, 94, 133, 26, 207, 59, 166, 184, 160, 205, 9, 65, 190, 213, 61, 41, 236, 152, 226, 66, 43, 214, 211, 113, 76, 177, 209, 180, 101, 234, 252, 67, 235, 164, 213, 29, 34, 26, 239, 51, 83, 92, 188, 239, 66, 254, 208, 198, 140, 101, 87, 98, 168, 104, 163, 237, 160, 158, 75, 99, 35, 204, 152, 195, 35, 140, 141, 48, 83, 132, 120, 24, 170, 147, 162, 239, 168, 245, 91, 223, 127, 153, 226, 194, 47, 83, 108, 120, 58, 221, 151, 41, 50, 150, 250, 227, 206, 132, 114, 45, 76, 209, 65, 23, 59, 172, 153, 34, 73, 204, 34, 92, 50, 73, 42, 197, 251, 121, 58, 175, 239, 232, 93, 223, 51, 105, 47, 200, 8, 106, 38, 222, 160, 235, 121, 95, 253, 144, 3, 77, 253, 216, 27, 183, 245, 8, 212, 250, 143, 251, 31, 247, 131, 252, 84, 104, 2, 9, 64, 144, 152, 110, 38, 123, 226, 183, 189, 9, 168, 149, 194, 174, 213, 57, 118, 144, 39, 85, 74, 214, 233, 250, 125, 164, 77, 58, 8, 118, 198, 202, 129, 82, 150, 141, 129, 166, 203, 147, 204, 91, 43, 86, 37, 175, 6, 141, 247, 83, 34, 149, 240, 164, 237, 250, 182, 76, 91, 138, 238, 4, 181, 213, 110, 128, 31, 49, 218, 206, 107, 227, 164, 127, 120, 147, 139, 65, 19, 44, 43, 234, 218, 182, 105, 218, 224, 141, 215, 87, 189, 58, 184, 67, 228, 167, 114, 142, 39, 53, 142, 96, 236, 158, 90, 149, 101, 67, 106, 87, 78, 152, 105, 223, 118, 33, 95, 9, 103, 235, 184, 195, 111, 123, 19, 208, 174, 244, 180, 182, 67, 187, 146, 3, 238, 233, 157, 29, 218, 149, 156, 79, 71, 177, 203, 95, 221, 217, 58, 142, 118, 37, 109, 178, 151, 161, 133, 216, 149, 10, 64, 225, 197, 72, 154, 41, 72, 130, 63, 80, 107, 223, 242, 240, 130, 104, 64, 27, 164, 138, 39, 34, 9, 173, 90, 251, 28, 240, 7, 208, 50, 104, 210, 161, 199, 65, 90, 247, 92, 169, 129, 0, 30, 210, 122, 46, 20, 252, 47, 162, 217, 5, 46, 145, 120, 210, 22, 189, 74, 82, 246, 130, 90, 23, 166, 168, 0, 9, 48, 255, 32, 46, 189, 4, 69, 178, 157, 64, 30, 113, 104, 198, 135, 92, 127, 124, 41, 46, 216, 82, 148, 120, 215, 71, 108, 41, 131, 103, 7, 177, 165, 184, 96, 75, 209, 145, 246, 25, 90, 177, 238, 118, 45, 197, 134, 71, 36, 75, 113, 129, 101, 66, 204, 82, 92, 168, 246, 63, 148, 254, 190, 212, 155, 208, 211, 89, 128, 125, 19, 165, 168, 88, 111, 224, 224, 111, 57, 136, 171, 147, 62, 217, 131, 3, 247, 92, 9, 97, 67, 107, 107, 235, 28, 125, 203, 70, 151, 226, 3, 101, 66, 63, 223, 17, 133, 85, 91, 10, 123, 203, 223, 17, 90, 177, 157, 207, 109, 162, 234, 97, 105, 74, 137, 188, 65, 203, 93, 84, 53, 102, 140, 19, 122, 224, 164, 87, 198, 33, 98, 61, 90, 215, 98, 224, 53, 101, 104, 65, 227, 254, 164, 75, 145, 225, 216, 83, 15, 85, 220, 32, 152, 75, 132, 13, 42, 188, 176, 68, 162, 216, 208, 170, 146, 29, 223, 118, 33, 143, 40, 50, 42, 218, 104, 35, 85, 111, 165, 182, 200, 35, 138, 17, 30, 81, 84, 240, 172, 144, 202, 119, 181, 52, 194, 168, 182, 147, 85, 156, 144, 64, 1, 8, 32, 112, 171, 8, 209, 234, 164, 79, 10, 106, 26, 69, 77, 163, 200, 248, 134, 180, 159, 239, 174, 235, 169, 70, 17, 210, 180, 117, 62, 93, 227, 239, 108, 144, 36, 102, 205, 159, 207, 237, 208, 52, 218, 52, 138, 15, 218, 140, 199, 38, 212, 52, 138, 12, 109, 23, 212, 52, 138, 139, 111, 220, 140, 34, 67, 243, 39, 101, 24, 69, 70, 195, 11, 169, 34, 195, 123, 47, 131, 84, 145, 209, 186, 255, 218, 14, 241, 35, 7, 8, 241, 198, 251, 171, 20, 25, 77, 91, 165, 248, 120, 223, 133, 158, 212, 52, 101, 68, 37, 226, 71, 174, 141, 82, 108, 208, 234, 164, 246, 114, 33, 109, 148, 98, 131, 78, 250, 165, 8, 74, 145, 161, 147, 126, 73, 145, 193, 117, 73, 146, 178, 147, 20, 25, 204, 32, 197, 69, 91, 60, 130, 82, 82, 100, 48, 109, 81, 124, 44, 182, 40, 58, 22, 91, 20, 21, 158, 138, 84, 124, 168, 98, 143, 167, 190, 67, 146, 242, 221, 37, 123, 196, 227, 169, 206, 209, 250, 120, 42, 54, 56, 175, 150, 210, 114, 61, 223, 83, 209, 193, 61, 33, 111, 218, 122, 42, 62, 190, 105, 227, 84, 116, 248, 151, 58, 21, 25, 218, 73, 169, 184, 224, 142, 219, 33, 39, 165, 162, 67, 157, 27, 21, 94, 22, 243, 67, 188, 179, 35, 177, 50, 241, 66, 139, 226, 6, 234, 158, 82, 133, 210, 178, 108, 143, 66, 7, 253, 93, 217, 30, 133, 140, 86, 198, 22, 229, 68, 97, 163, 173, 82, 73, 219, 245, 224, 200, 35, 239, 79, 161, 131, 55, 26, 239, 103, 63, 133, 140, 86, 73, 82, 39, 45, 224, 97, 86, 66, 132, 70, 43, 3, 85, 116, 185, 167, 144, 194, 61, 133, 10, 36, 233, 41, 84, 80, 247, 188, 194, 5, 228, 175, 176, 225, 213, 21, 42, 40, 100, 104, 227, 10, 199, 173, 144, 225, 17, 8, 216, 112, 215, 245, 204, 182, 194, 6, 210, 181, 150, 146, 173, 208, 193, 196, 17, 37, 91, 97, 131, 54, 45, 91, 33, 67, 171, 36, 101, 63, 106, 178, 21, 66, 26, 94, 12, 143, 60, 120, 4, 66, 171, 3, 57, 107, 192, 118, 177, 119, 208, 55, 187, 138, 82, 120, 4, 130, 201, 86, 216, 160, 36, 112, 202, 86, 184, 96, 202, 41, 84, 120, 102, 29, 111, 248, 231, 59, 82, 201, 235, 153, 27, 169, 202, 110, 26, 133, 21, 58, 60, 217, 157, 254, 187, 32, 93, 203, 99, 133, 15, 221, 127, 254, 93, 206, 159, 21, 62, 126, 155, 103, 133, 16, 101, 210, 31, 15, 170, 165, 171, 104, 195, 174, 132, 28, 200, 224, 19, 208, 179, 66, 6, 93, 75, 254, 99, 108, 145, 227, 150, 112, 220, 206, 191, 211, 53, 26, 123, 132, 21, 50, 158, 21, 42, 80, 198, 105, 41, 5, 45, 185, 152, 23, 102, 133, 17, 173, 191, 73, 97, 172, 84, 106, 51, 86, 200, 120, 152, 237, 231, 24, 43, 108, 112, 91, 198, 10, 25, 154, 177, 211, 84, 81, 198, 10, 33, 234, 158, 103, 172, 208, 65, 226, 249, 15, 116, 144, 128, 177, 66, 133, 8, 24, 43, 84, 240, 213, 15, 49, 86, 200, 208, 38, 25, 43, 132, 60, 90, 43, 118, 229, 182, 58, 98, 172, 208, 65, 91, 46, 215, 88, 118, 49, 86, 248, 224, 190, 96, 172, 176, 33, 57, 255, 131, 104, 205, 174, 68, 140, 21, 54, 212, 223, 178, 66, 134, 117, 217, 176, 66, 6, 95, 251, 207, 161, 205, 9, 85, 36, 86, 216, 168, 72, 172, 80, 161, 43, 137, 21, 54, 84, 18, 43, 84, 104, 205, 186, 162, 214, 172, 191, 196, 10, 29, 26, 239, 103, 195, 55, 101, 47, 177, 194, 7, 174, 238, 249, 196, 10, 25, 146, 102, 6, 61, 157, 205, 142, 233, 35, 109, 219, 159, 88, 97, 131, 196, 159, 88, 33, 195, 174, 132, 30, 102, 31, 30, 129, 224, 164, 78, 245, 196, 10, 33, 239, 56, 177, 66, 6, 85, 220, 96, 170, 152, 65, 214, 50, 18, 234, 172, 146, 196, 10, 29, 20, 50, 190, 242, 200, 155, 194, 197, 171, 36, 177, 35, 111, 10, 29, 78, 122, 101, 180, 29, 242, 166, 144, 162, 91, 39, 140, 188, 41, 100, 160, 154, 74, 82, 46, 104, 127, 61, 166, 154, 66, 134, 98, 10, 21, 76, 150, 66, 5, 173, 173, 89, 71, 108, 37, 10, 31, 147, 136, 66, 5, 169, 61, 174, 180, 105, 157, 172, 66, 198, 186, 68, 149, 237, 79, 134, 86, 225, 132, 175, 77, 166, 72, 215, 146, 232, 32, 95, 23, 228, 17, 8, 15, 235, 18, 169, 230, 228, 171, 48, 98, 211, 73, 232, 249, 94, 133, 142, 231, 129, 102, 100, 240, 163, 94, 133, 13, 189, 10, 31, 252, 232, 115, 105, 218, 42, 148, 240, 8, 4, 110, 109, 171, 176, 241, 174, 205, 42, 108, 72, 237, 49, 171, 94, 99, 217, 215, 197, 48, 171, 112, 209, 146, 173, 165, 14, 210, 101, 152, 85, 232, 176, 150, 100, 152, 85, 216, 176, 216, 59, 17, 24, 102, 21, 54, 156, 244, 233, 16, 195, 172, 66, 8, 134, 89, 133, 10, 45, 149, 61, 126, 212, 42, 116, 172, 90, 229, 104, 120, 229, 42, 124, 104, 218, 254, 42, 69, 159, 180, 87, 161, 7, 30, 65, 44, 187, 201, 85, 232, 240, 199, 210, 214, 210, 73, 8, 37, 92, 50, 228, 224, 142, 92, 133, 141, 85, 24, 0, 150, 221, 40, 92, 72, 70, 161, 2, 221, 138, 42, 92, 64, 134, 39, 117, 14, 241, 8, 210, 180, 19, 85, 40, 209, 40, 172, 40, 236, 76, 120, 218, 95, 176, 214, 190, 9, 72, 153, 246, 255, 183, 108, 208, 68, 21, 66, 168, 147, 50, 121, 68, 75, 71, 143, 111, 77, 19, 85, 184, 208, 183, 114, 162, 10, 23, 107, 189, 134, 38, 170, 144, 225, 22, 77, 84, 33, 67, 133, 95, 21, 46, 80, 76, 224, 138, 116, 178, 13, 78, 122, 252, 19, 191, 30, 190, 217, 45, 72, 203, 174, 71, 211, 182, 181, 74, 190, 161, 116, 173, 124, 111, 11, 241, 92, 227, 208, 181, 204, 131, 194, 139, 105, 157, 112, 131, 164, 175, 10, 29, 214, 230, 171, 66, 7, 75, 190, 42, 92, 232, 119, 85, 174, 220, 248, 192, 35, 16, 92, 21, 50, 168, 194, 198, 202, 55, 65, 21, 50, 124, 179, 35, 119, 238, 84, 161, 163, 241, 62, 40, 186, 147, 247, 93, 72, 39, 251, 217, 6, 192, 237, 16, 133, 210, 207, 164, 237, 84, 161, 67, 181, 255, 193, 113, 217, 205, 190, 150, 120, 16, 66, 57, 85, 78, 21, 50, 156, 42, 108, 52, 109, 209, 243, 235, 77, 21, 74, 60, 204, 170, 226, 166, 10, 27, 250, 240, 203, 118, 169, 66, 7, 111, 232, 103, 163, 75, 21, 50, 244, 115, 61, 164, 216, 149, 208, 82, 133, 139, 165, 10, 21, 44, 188, 26, 85, 200, 208, 252, 217, 218, 180, 81, 133, 143, 199, 168, 66, 5, 103, 84, 125, 46, 70, 21, 58, 30, 134, 81, 133, 11, 141, 194, 74, 105, 183, 106, 51, 248, 81, 43, 163, 10, 33, 190, 105, 147, 168, 213, 159, 218, 247, 22, 187, 182, 47, 240, 36, 69, 63, 155, 7, 181, 8, 37, 180, 105, 101, 13, 199, 83, 125, 218, 254, 136, 111, 246, 86, 127, 86, 182, 68, 234, 56, 249, 132, 63, 42, 65, 202, 178, 105, 67, 252, 81, 9, 114, 201, 26, 92, 50, 223, 197, 167, 237, 119, 36, 49, 129, 43, 82, 109, 70, 53, 253, 202, 163, 85, 53, 163, 167, 37, 106, 13, 32, 86, 62, 199, 154, 160, 12, 134, 89, 133, 156, 170, 194, 134, 219, 10, 7, 183, 21, 237, 85, 52, 16, 17, 42, 150, 136, 206, 119, 80, 133, 141, 237, 71, 193, 48, 251, 15, 85, 156, 84, 225, 0, 60, 2, 65, 209, 177, 26, 8, 146, 164, 10, 23, 239, 52, 187, 16, 132, 71, 32, 172, 100, 155, 84, 161, 195, 31, 149, 160, 7, 85, 170, 112, 209, 240, 98, 248, 227, 245, 150, 100, 144, 67, 243, 22, 85, 184, 128, 16, 169, 61, 158, 170, 112, 225, 82, 21, 42, 72, 218, 46, 149, 170, 144, 241, 77, 85, 91, 164, 10, 27, 205, 91, 20, 42, 40, 237, 116, 60, 162, 113, 13, 107, 130, 63, 12, 233, 162, 16, 194, 23, 133, 13, 165, 21, 79, 42, 100, 72, 255, 32, 60, 242, 164, 194, 5, 95, 251, 79, 105, 63, 228, 44, 241, 167, 66, 7, 60, 162, 159, 10, 25, 60, 2, 65, 63, 149, 67, 217, 126, 131, 194, 141, 225, 79, 170, 93, 236, 168, 119, 58, 111, 76, 132, 210, 214, 247, 212, 135, 186, 182, 117, 18, 68, 169, 239, 68, 27, 237, 202, 166, 233, 66, 145, 246, 149, 57, 191, 253, 160, 159, 10, 27, 182, 95, 126, 42, 92, 68, 224, 11, 250, 164, 75, 125, 65, 171, 106, 214, 166, 112, 63, 112, 143, 187, 161, 112, 171, 6, 34, 240, 5, 57, 160, 147, 125, 160, 85, 165, 58, 74, 43, 203, 188, 138, 120, 21, 193, 2, 190, 160, 7, 222, 248, 255, 49, 136, 64, 194, 23, 244, 218, 32, 68, 224, 11, 98, 96, 173, 101, 248, 95, 162, 6, 175, 13, 130, 131, 75, 150, 159, 10, 25, 158, 182, 95, 25, 106, 88, 121, 4, 97, 132, 175, 126, 13, 109, 126, 119, 172, 75, 148, 159, 10, 31, 246, 53, 16, 62, 21, 46, 158, 167, 66, 5, 143, 56, 158, 10, 25, 30, 102, 29, 79, 133, 11, 173, 216, 86, 199, 83, 97, 227, 61, 145, 227, 169, 144, 209, 169, 176, 225, 77, 75, 90, 42, 100, 180, 54, 45, 21, 50, 180, 213, 119, 188, 233, 68, 23, 122, 217, 202, 82, 225, 132, 71, 22, 18, 20, 98, 104, 55, 169, 112, 193, 37, 67, 77, 42, 92, 68, 48, 129, 66, 5, 203, 141, 155, 39, 72, 130, 66, 135, 99, 104, 134, 131, 178, 125, 151, 78, 218, 71, 18, 186, 50, 57, 146, 160, 144, 241, 168, 164, 165, 187, 190, 9, 142, 70, 27, 73, 80, 216, 208, 208, 167, 111, 130, 106, 191, 202, 55, 1, 73, 80, 248, 104, 220, 60, 139, 29, 146, 160, 208, 225, 124, 186, 207, 197, 78, 130, 114, 180, 93, 42, 234, 32, 9, 10, 27, 159, 172, 161, 169, 217, 73, 175, 12, 146, 160, 144, 161, 158, 138, 36, 40, 92, 76, 220, 249, 62, 217, 94, 46, 85, 72, 130, 194, 71, 63, 254, 230, 240, 198, 251, 73, 35, 220, 14, 233, 175, 179, 99, 14, 154, 23, 35, 9, 10, 27, 84, 179, 147, 144, 4, 133, 12, 223, 74, 34, 9, 10, 23, 186, 150, 68, 21, 9, 31, 42, 18, 62, 80, 151, 201, 249, 159, 74, 147, 15, 145, 164, 92, 222, 47, 105, 251, 154, 104, 126, 88, 242, 221, 129, 239, 175, 215, 192, 73, 220, 64, 191, 116, 94, 155, 44, 98, 101, 226, 229, 192, 187, 70, 158, 29, 119, 217, 28, 105, 147, 108, 25, 56, 237, 70, 169, 196, 123, 50, 104, 109, 50, 17, 186, 150, 81, 201, 171, 81, 40, 28, 28, 66, 43, 143, 95, 245, 18, 53, 224, 66, 87, 122, 18, 46, 64, 26, 57, 168, 47, 37, 225, 66, 219, 5, 185, 69, 41, 9, 27, 217, 9, 105, 197, 54, 52, 157, 124, 211, 9, 68, 83, 203, 247, 182, 136, 241, 251, 75, 184, 192, 35, 136, 2, 16, 72, 32, 65, 4, 157, 244, 75, 216, 160, 116, 169, 150, 78, 123, 232, 89, 19, 232, 183, 65, 47, 225, 17, 8, 173, 79, 225, 17, 8, 15, 79, 77, 187, 95, 66, 135, 111, 157, 4, 235, 32, 190, 121, 193, 46, 137, 84, 113, 67, 134, 42, 110, 168, 32, 73, 220, 80, 65, 157, 148, 137, 27, 46, 184, 97, 131, 27, 50, 212, 51, 33, 110, 184, 80, 237, 103, 13, 25, 60, 2, 193, 31, 149, 52, 100, 168, 111, 67, 133, 100, 108, 27, 46, 160, 99, 105, 179, 13, 23, 158, 126, 164, 105, 27, 50, 150, 109, 168, 160, 169, 132, 31, 65, 48, 88, 148, 210, 186, 242, 125, 239, 132, 194, 73, 191, 20, 127, 13, 238, 223, 65, 251, 235, 9, 224, 0, 253, 158, 252, 234, 182, 223, 81, 165, 137, 176, 75, 210, 46, 127, 93, 42, 241, 137, 181, 246, 77, 248, 182, 173, 110, 93, 195, 27, 175, 251, 178, 86, 151, 203, 39, 101, 90, 93, 227, 101, 68, 97, 183, 14, 181, 170, 102, 182, 143, 126, 129, 196, 25, 16, 221, 255, 181, 184, 147, 163, 54, 209, 176, 117, 142, 59, 161, 74, 211, 48, 194, 35, 239, 52, 187, 156, 102, 29, 84, 105, 26, 62, 48, 202, 161, 6, 144, 70, 97, 245, 237, 177, 132, 174, 132, 29, 205, 139, 33, 154, 23, 55, 184, 91, 167, 129, 42, 77, 195, 135, 191, 229, 42, 77, 67, 7, 173, 88, 231, 127, 137, 42, 77, 67, 72, 211, 176, 81, 233, 166, 97, 3, 9, 119, 211, 112, 225, 83, 106, 55, 13, 23, 77, 195, 71, 211, 240, 33, 65, 211, 208, 209, 74, 209, 157, 32, 143, 48, 202, 161, 8, 77, 219, 199, 13, 69, 104, 26, 58, 44, 200, 245, 154, 108, 37, 241, 100, 17, 174, 43, 225, 71, 235, 235, 114, 140, 27, 80, 132, 166, 161, 195, 155, 6, 93, 200, 104, 26, 62, 210, 73, 239, 50, 105, 163, 166, 33, 68, 146, 214, 161, 166, 33, 132, 75, 18, 51, 212, 52, 100, 104, 147, 236, 169, 200, 133, 154, 134, 17, 77, 67, 138, 166, 225, 195, 235, 90, 111, 65, 77, 67, 77, 195, 6, 148, 104, 120, 45, 72, 153, 58, 143, 178, 179, 191, 162, 13, 25, 188, 105, 227, 208, 250, 76, 58, 191, 20, 8, 95, 235, 24, 232, 231, 242, 150, 237, 224, 202, 212, 249, 135, 75, 166, 191, 174, 253, 146, 250, 132, 235, 63, 110, 9, 93, 75, 86, 158, 210, 78, 138, 0, 220, 117, 33, 245, 45, 145, 43, 173, 88, 182, 239, 120, 129, 182, 93, 12, 195, 21, 109, 15, 255, 198, 140, 195, 117, 37, 12, 113, 254, 53, 86, 63, 164, 255, 22, 251, 146, 232, 43, 218, 48, 226, 43, 218, 80, 193, 31, 169, 123, 158, 162, 13, 29, 217, 95, 209, 197, 222, 65, 15, 90, 50, 138, 54, 100, 88, 253, 144, 62, 247, 165, 120, 4, 169, 182, 12, 162, 104, 67, 20, 109, 200, 112, 215, 86, 42, 145, 164, 153, 242, 218, 240, 33, 245, 107, 195, 5, 137, 39, 123, 109, 184, 96, 160, 141, 90, 10, 114, 246, 192, 174, 132, 30, 102, 215, 107, 195, 199, 107, 67, 5, 172, 89, 221, 243, 13, 60, 210, 38, 0, 193, 34, 143, 232, 98, 127, 215, 134, 14, 207, 131, 210, 119, 109, 72, 209, 248, 189, 45, 5, 210, 250, 143, 31, 77, 39, 217, 232, 93, 27, 58, 190, 83, 33, 166, 181, 97, 35, 177, 98, 109, 17, 139, 23, 212, 64, 36, 2, 214, 134, 16, 214, 134, 15, 214, 134, 13, 116, 232, 82, 170, 13, 25, 86, 190, 9, 250, 169, 13, 27, 19, 79, 232, 83, 27, 50, 30, 93, 157, 218, 112, 145, 86, 241, 182, 58, 6, 239, 218, 169, 13, 27, 26, 123, 68, 53, 100, 112, 157, 148, 111, 118, 200, 2, 143, 227, 178, 27, 102, 236, 32, 137, 39, 187, 83, 53, 92, 184, 212, 80, 129, 178, 108, 169, 33, 3, 55, 59, 201, 134, 12, 250, 187, 16, 133, 246, 3, 46, 124, 177, 250, 181, 231, 112, 80, 189, 139, 190, 181, 160, 102, 9, 39, 189, 50, 8, 113, 60, 27, 42, 56, 119, 74, 134, 214, 101, 195, 135, 90, 251, 22, 180, 46, 219, 190, 163, 181, 181, 117, 222, 224, 216, 125, 50, 181, 220, 178, 33, 195, 98, 239, 48, 252, 155, 78, 212, 155, 23, 39, 135, 54, 94, 201, 223, 194, 73, 77, 23, 110, 217, 176, 241, 173, 238, 201, 45, 27, 58, 150, 231, 203, 115, 136, 91, 182, 212, 6, 238, 9, 113, 203, 134, 12, 110, 217, 80, 161, 101, 67, 5, 205, 44, 27, 46, 32, 140, 64, 74, 89, 54, 148, 88, 43, 145, 178, 108, 216, 160, 146, 145, 108, 184, 224, 218, 118, 169, 212, 70, 13, 31, 44, 187, 65, 13, 25, 26, 2, 160, 130, 97, 0, 34, 48, 172, 9, 254, 48, 92, 120, 152, 173, 232, 63, 134, 12, 182, 142, 163, 5, 15, 56, 240, 166, 237, 187, 254, 3, 182, 142, 183, 182, 136, 0, 143, 97, 196, 99, 8, 241, 254, 24, 42, 120, 68, 66, 131, 227, 233, 244, 99, 253, 24, 58, 90, 117, 9, 64, 221, 186, 79, 214, 112, 210, 39, 115, 201, 24, 218, 118, 121, 211, 114, 45, 208, 180, 149, 120, 36, 85, 156, 188, 41, 244, 158, 169, 65, 61, 151, 237, 135, 248, 81, 43, 149, 16, 173, 84, 238, 119, 58, 180, 191, 30, 67, 135, 4, 71, 173, 191, 30, 195, 134, 227, 118, 72, 242, 24, 50, 208, 62, 134, 14, 207, 176, 65, 113, 134, 10, 214, 4, 119, 134, 11, 252, 238, 233, 212, 206, 176, 209, 18, 48, 244, 119, 65, 60, 130, 36, 41, 93, 227, 12, 29, 239, 218, 200, 25, 46, 156, 97, 67, 217, 178, 102, 200, 160, 205, 9, 177, 102, 200, 216, 102, 168, 64, 178, 146, 130, 156, 42, 212, 12, 31, 255, 19, 24, 62, 252, 79, 96, 168, 48, 129, 33, 195, 155, 99, 168, 224, 24, 58, 210, 122, 46, 142, 225, 2, 46, 156, 183, 194, 12, 25, 254, 49, 67, 5, 109, 90, 58, 9, 169, 63, 102, 8, 249, 182, 236, 208, 183, 199, 12, 31, 251, 80, 227, 125, 102, 216, 112, 235, 120, 171, 243, 204, 208, 241, 206, 12, 21, 60, 2, 193, 183, 155, 25, 54, 24, 43, 199, 53, 179, 71, 203, 166, 153, 33, 131, 239, 202, 102, 134, 11, 21, 1, 105, 227, 231, 198, 12, 27, 60, 185, 84, 33, 199, 188, 16, 58, 136, 48, 65, 250, 217, 182, 73, 71, 209, 52, 110, 208, 138, 85, 231, 79, 94, 140, 131, 190, 46, 85, 232, 65, 157, 25, 30, 217, 126, 15, 109, 78, 104, 1, 180, 44, 106, 245, 67, 173, 177, 3, 141, 23, 125, 211, 93, 9, 61, 88, 22, 142, 167, 106, 112, 211, 152, 33, 228, 209, 198, 12, 23, 22, 203, 7, 113, 202, 198, 120, 80, 239, 116, 18, 219, 150, 61, 60, 34, 0, 6, 254, 164, 66, 20, 238, 218, 214, 223, 130, 30, 190, 41, 99, 134, 12, 173, 235, 37, 93, 204, 176, 177, 152, 225, 67, 123, 204, 160, 231, 198, 64, 177, 68, 238, 73, 152, 23, 69, 4, 131, 174, 76, 222, 185, 158, 98, 134, 16, 244, 48, 171, 152, 225, 67, 87, 108, 235, 6, 47, 85, 204, 144, 97, 177, 10, 114, 232, 82, 138, 25, 50, 248, 131, 150, 186, 146, 98, 134, 140, 69, 41, 40, 21, 51, 100, 224, 254, 61, 34, 73, 204, 144, 225, 105, 93, 76, 154, 34, 165, 250, 169, 218, 170, 119, 135, 107, 51, 36, 42, 218, 36, 46, 161, 68, 26, 11, 40, 36, 56, 114, 202, 3, 73, 18, 51, 148, 104, 110, 32, 66, 25, 187, 82, 36, 41, 93, 163, 193, 157, 190, 63, 156, 244, 73, 121, 167, 217, 6, 209, 250, 205, 110, 130, 194, 219, 74, 154, 70, 24, 164, 147, 152, 225, 2, 95, 251, 79, 181, 31, 85, 22, 102, 19, 149, 133, 25, 58, 42, 11, 51, 84, 104, 8, 252, 61, 164, 157, 80, 172, 93, 152, 97, 195, 59, 54, 208, 162, 24, 67, 134, 98, 12, 29, 207, 90, 12, 21, 218, 86, 146, 161, 39, 187, 19, 45, 134, 144, 94, 229, 216, 75, 24, 50, 28, 211, 151, 48, 100, 144, 48, 116, 68, 88, 52, 117, 254, 33, 129, 14, 141, 186, 8, 67, 136, 195, 87, 244, 117, 45, 249, 41, 157, 63, 86, 110, 98, 255, 148, 218, 148, 108, 180, 88, 132, 65, 44, 86, 65, 15, 157, 203, 36, 27, 68, 155, 100, 203, 221, 208, 245, 251, 186, 158, 247, 135, 8, 149, 234, 60, 248, 198, 12, 82, 169, 142, 74, 117, 40, 84, 170, 227, 30, 119, 227, 104, 85, 59, 89, 5, 209, 230, 196, 222, 226, 180, 171, 161, 241, 255, 123, 60, 138, 151, 70, 227, 85, 205, 41, 37, 90, 44, 194, 208, 97, 177, 8, 67, 5, 231, 151, 82, 89, 134, 11, 254, 202, 50, 92, 128, 88, 218, 210, 85, 150, 33, 67, 89, 101, 25, 46, 108, 101, 25, 58, 214, 185, 117, 95, 247, 101, 248, 240, 8, 50, 26, 74, 43, 214, 35, 28, 127, 203, 73, 175, 140, 3, 130, 112, 79, 167, 21, 203, 24, 74, 223, 151, 249, 66, 188, 47, 219, 182, 140, 53, 94, 155, 135, 217, 182, 12, 25, 182, 95, 51, 137, 208, 230, 135, 244, 90, 108, 91, 134, 14, 184, 105, 169, 45, 67, 134, 111, 170, 218, 162, 182, 12, 29, 108, 209, 150, 33, 196, 153, 45, 195, 133, 198, 160, 180, 108, 25, 50, 90, 217, 50, 101, 203, 176, 177, 236, 82, 182, 12, 23, 206, 150, 49, 135, 178, 101, 248, 80, 182, 12, 21, 118, 173, 101, 248, 104, 187, 100, 163, 214, 181, 150, 33, 4, 23, 143, 82, 203, 112, 65, 217, 126, 67, 43, 118, 229, 175, 203, 132, 158, 97, 119, 213, 56, 169, 67, 156, 244, 14, 87, 247, 60, 197, 242, 124, 251, 33, 180, 246, 223, 90, 137, 22, 104, 93, 6, 25, 64, 89, 54, 212, 154, 211, 3, 77, 23, 104, 163, 86, 246, 26, 82, 197, 73, 21, 4, 78, 128, 135, 89, 247, 92, 74, 37, 237, 49, 208, 245, 251, 13, 52, 165, 115, 93, 114, 53, 222, 207, 182, 239, 170, 80, 197, 35, 12, 20, 192, 249, 100, 76, 127, 37, 158, 128, 134, 0, 186, 150, 124, 7, 156, 230, 113, 59, 175, 18, 166, 65, 192, 0, 22, 146, 180, 93, 252, 47, 209, 2, 24, 211, 52, 104, 253, 79, 246, 141, 91, 0, 13, 72, 58, 89, 39, 123, 224, 15, 225, 155, 78, 84, 117, 177, 43, 49, 86, 39, 244, 240, 240, 166, 179, 209, 250, 73, 187, 57, 169, 115, 7, 220, 105, 25, 54, 108, 167, 101, 184, 192, 105, 25, 66, 92, 63, 211, 46, 94, 216, 19, 1, 161, 108, 191, 189, 134, 230, 254, 3, 8, 96, 226, 169, 112, 59, 212, 11, 180, 217, 241, 168, 4, 61, 168, 147, 50, 61, 36, 96, 128, 214, 6, 220, 175, 12, 41, 94, 83, 230, 251, 202, 176, 129, 15, 206, 43, 115, 94, 25, 50, 28, 124, 121, 223, 172, 175, 12, 35, 38, 116, 253, 190, 54, 201, 54, 162, 241, 54, 200, 87, 134, 15, 231, 151, 249, 202, 87, 134, 14, 164, 224, 86, 134, 11, 170, 253, 40, 55, 109, 127, 58, 138, 101, 23, 210, 37, 105, 101, 232, 112, 242, 217, 86, 134, 139, 111, 246, 8, 12, 250, 86, 78, 92, 181, 255, 225, 146, 33, 8, 103, 180, 29, 222, 216, 35, 11, 52, 13, 136, 63, 112, 221, 206, 198, 251, 105, 37, 220, 149, 101, 67, 238, 185, 82, 68, 211, 214, 249, 167, 37, 114, 208, 166, 149, 225, 2, 133, 149, 161, 66, 86, 176, 106, 202, 112, 161, 205, 239, 79, 187, 67, 107, 147, 14, 61, 237, 12, 122, 186, 145, 150, 217, 78, 237, 241, 132, 104, 227, 7, 70, 120, 132, 41, 195, 5, 173, 88, 166, 12, 25, 248, 145, 75, 134, 24, 57, 195, 148, 97, 1, 156, 97, 202, 152, 50, 92, 52, 56, 131, 152, 50, 100, 96, 204, 21, 136, 61, 246, 86, 41, 195, 134, 167, 245, 77, 112, 180, 186, 231, 31, 8, 249, 150, 202, 112, 161, 41, 134, 13, 174, 24, 54, 154, 98, 216, 224, 83, 106, 163, 85, 12, 27, 251, 16, 90, 197, 240, 33, 241, 83, 240, 51, 87, 228, 145, 138, 98, 20, 21, 143, 160, 138, 98, 21, 197, 30, 84, 20, 115, 62, 217, 67, 132, 174, 37, 159, 49, 13, 90, 251, 143, 49, 141, 3, 98, 220, 14, 144, 106, 137, 84, 91, 134, 1, 111, 188, 12, 62, 229, 254, 147, 112, 199, 101, 55, 217, 233, 144, 86, 168, 190, 9, 238, 128, 34, 63, 149, 239, 66, 74, 37, 122, 79, 197, 176, 65, 218, 79, 134, 24, 73, 160, 24, 62, 42, 234, 32, 9, 20, 195, 133, 174, 101, 144, 4, 138, 33, 195, 21, 73, 160, 24, 50, 48, 79, 10, 90, 137, 189, 87, 146, 33, 132, 90, 180, 101, 149, 100, 200, 224, 17, 231, 147, 65, 42, 25, 89, 13, 4, 231, 147, 225, 226, 65, 209, 252, 249, 156, 79, 134, 15, 220, 19, 210, 138, 221, 135, 246, 77, 236, 243, 198, 105, 29, 244, 119, 81, 124, 99, 166, 113, 90, 244, 128, 55, 78, 139, 90, 179, 174, 106, 193, 162, 20, 228, 13, 188, 121, 113, 122, 200, 85, 202, 32, 90, 23, 78, 149, 234, 76, 106, 45, 5, 173, 126, 18, 185, 74, 153, 227, 19, 25, 79, 55, 246, 100, 72, 226, 201, 176, 177, 210, 241, 78, 134, 139, 103, 225, 241, 183, 28, 106, 69, 173, 11, 148, 42, 149, 116, 50, 100, 208, 245, 250, 193, 174, 132, 32, 190, 237, 74, 144, 138, 71, 16, 255, 67, 3, 73, 219, 213, 128, 126, 41, 24, 70, 186, 150, 124, 7, 92, 210, 150, 1, 127, 42, 114, 57, 168, 232, 167, 68, 159, 219, 51, 51, 20, 191, 253, 159, 232, 183, 217, 73, 45, 145, 196, 239, 99, 194, 33, 60, 162, 81, 88, 73, 58, 25, 50, 60, 2, 65, 210, 201, 112, 177, 168, 220, 78, 86, 105, 218, 58, 169, 147, 33, 3, 231, 151, 121, 171, 115, 201, 240, 177, 26, 84, 225, 165, 241, 235, 59, 233, 92, 203, 214, 81, 59, 68, 22, 70, 46, 25, 46, 126, 217, 46, 228, 146, 185, 100, 232, 104, 43, 201, 150, 76, 155, 108, 201, 240, 225, 60, 51, 150, 12, 23, 220, 41, 89, 50, 92, 236, 74, 134, 10, 202, 164, 35, 151, 104, 112, 199, 237, 32, 122, 21, 82, 73, 50, 73, 50, 116, 112, 36, 25, 42, 252, 46, 231, 216, 240, 8, 106, 175, 89, 155, 12, 29, 16, 9, 19, 180, 46, 145, 99, 235, 164, 181, 201, 16, 194, 61, 199, 14, 165, 101, 182, 53, 201, 208, 97, 251, 161, 215, 214, 36, 67, 199, 174, 180, 77, 178, 180, 77, 50, 108, 60, 99, 146, 225, 2, 114, 78, 201, 176, 193, 87, 63, 36, 73, 233, 32, 52, 219, 58, 41, 217, 4, 158, 4, 134, 142, 9, 60, 9, 12, 31, 173, 223, 118, 161, 39, 129, 161, 99, 2, 204, 191, 138, 133, 12, 201, 42, 22, 42, 84, 44, 108, 84, 218, 179, 80, 33, 237, 231, 59, 210, 57, 114, 202, 194, 133, 254, 54, 69, 27, 57, 101, 225, 163, 162, 170, 45, 114, 10, 101, 33, 196, 41, 11, 21, 52, 174, 188, 133, 11, 153, 252, 45, 92, 232, 246, 22, 42, 72, 48, 113, 73, 98, 175, 0, 123, 11, 31, 254, 249, 142, 42, 192, 222, 194, 136, 10, 176, 183, 208, 81, 249, 133, 10, 190, 249, 133, 10, 46, 89, 5, 22, 250, 244, 77, 104, 244, 122, 33, 228, 245, 194, 198, 59, 205, 46, 10, 47, 100, 120, 38, 7, 8, 116, 44, 138, 194, 11, 23, 30, 47, 116, 64, 19, 159, 82, 27, 226, 188, 72, 247, 159, 23, 58, 92, 151, 59, 47, 108, 112, 188, 80, 129, 227, 28, 28, 226, 219, 178, 99, 109, 144, 186, 231, 243, 83, 173, 166, 121, 17, 244, 96, 81, 220, 52, 102, 11, 180, 196, 55, 59, 247, 116, 136, 129, 103, 94, 80, 131, 36, 229, 226, 152, 23, 50, 112, 129, 178, 92, 232, 104, 14, 71, 154, 198, 11, 25, 146, 119, 109, 26, 47, 116, 248, 199, 141, 23, 66, 154, 198, 11, 21, 42, 186, 120, 225, 130, 71, 86, 194, 11, 25, 86, 194, 11, 21, 24, 32, 165, 205, 139, 19, 114, 96, 233, 68, 87, 195, 11, 25, 79, 211, 240, 194, 133, 166, 225, 133, 15, 172, 153, 97, 76, 195, 171, 225, 133, 139, 231, 149, 13, 47, 92, 120, 36, 130, 134, 23, 50, 44, 104, 120, 73, 52, 188, 208, 209, 240, 66, 5, 206, 61, 231, 94, 189, 61, 231, 151, 50, 97, 219, 91, 125, 19, 182, 189, 9, 219, 94, 195, 132, 109, 207, 249, 165, 52, 222, 246, 32, 158, 165, 241, 182, 215, 120, 219, 123, 248, 206, 119, 182, 253, 202, 182, 223, 129, 109, 191, 115, 143, 219, 230, 114, 252, 20, 252, 14, 252, 252, 14, 174, 108, 127, 253, 115, 59, 191, 124, 179, 51, 118, 149, 100, 115, 173, 88, 127, 117, 245, 229, 88, 250, 122, 254, 174, 173, 78, 39, 204, 122, 211, 65, 190, 243, 93, 165, 107, 170, 210, 169, 116, 142, 103, 105, 85, 205, 169, 241, 179, 252, 50, 254, 101, 76, 225, 230, 112, 204, 77, 43, 150, 153, 50, 135, 103, 169, 36, 171, 36, 115, 184, 100, 16, 254, 168, 196, 37, 123, 239, 101, 90, 41, 188, 34, 212, 51, 181, 82, 120, 121, 174, 71, 37, 143, 103, 121, 84, 162, 158, 105, 201, 69, 37, 16, 237, 61, 172, 245, 218, 218, 6, 113, 210, 39, 107, 154, 46, 143, 208, 223, 182, 140, 47, 69, 98, 229, 155, 240, 188, 99, 234, 14, 250, 169, 220, 125, 93, 50, 149, 240, 164, 45, 196, 183, 78, 218, 58, 248, 171, 84, 231, 209, 214, 211, 241, 116, 28, 77, 255, 115, 49, 14, 239, 185, 84, 91, 70, 37, 170, 45, 227, 192, 60, 116, 162, 174, 162, 141, 118, 131, 243, 75, 113, 213, 212, 249, 165, 44, 169, 169, 247, 91, 84, 61, 60, 221, 47, 113, 122, 112, 245, 76, 75, 89, 38, 8, 16, 170, 237, 2, 225, 19, 130, 243, 75, 113, 126, 41, 109, 159, 78, 135, 131, 243, 233, 248, 95, 211, 174, 6, 127, 84, 194, 214, 113, 213, 118, 121, 117, 102, 213, 94, 3, 111, 85, 139, 29, 157, 236, 103, 211, 134, 120, 178, 59, 213, 83, 151, 182, 126, 46, 118, 173, 223, 86, 123, 193, 147, 221, 249, 218, 116, 58, 169, 211, 73, 139, 189, 243, 234, 173, 170, 61, 118, 140, 155, 129, 147, 50, 81, 72, 82, 46, 107, 101, 82, 109, 93, 223, 202, 137, 196, 132, 109, 207, 149, 194, 73, 159, 108, 229, 155, 160, 62, 241, 218, 52, 63, 168, 231, 82, 81, 213, 86, 181, 101, 212, 115, 129, 152, 112, 82, 234, 227, 56, 61, 217, 157, 21, 128, 16, 241, 80, 235, 138, 26, 142, 167, 226, 133, 12, 45, 73, 188, 36, 137, 23, 50, 36, 137, 23, 42, 252, 163, 105, 91, 177, 17, 218, 100, 51, 243, 216, 8, 51, 69, 186, 40, 5, 98, 185, 63, 52, 18, 135, 86, 38, 110, 247, 164, 134, 149, 137, 23, 66, 60, 194, 224, 158, 32, 120, 171, 71, 32, 52, 90, 91, 91, 123, 221, 224, 12, 106, 117, 60, 85, 242, 194, 133, 63, 232, 90, 135, 7, 196, 37, 158, 15, 209, 44, 19, 65, 209, 48, 9, 169, 228, 133, 140, 69, 177, 133, 14, 111, 218, 170, 182, 11, 98, 147, 181, 176, 65, 37, 47, 109, 157, 236, 66, 7, 197, 255, 46, 108, 104, 149, 164, 117, 250, 187, 208, 209, 250, 187, 240, 177, 11, 25, 11, 21, 232, 167, 114, 175, 181, 85, 53, 109, 244, 77, 215, 250, 130, 127, 174, 45, 122, 244, 194, 195, 108, 83, 39, 2, 225, 125, 23, 46, 220, 119, 33, 4, 211, 95, 244, 174, 246, 77, 216, 133, 15, 102, 218, 34, 214, 204, 124, 46, 135, 42, 175, 237, 194, 9, 165, 77, 190, 163, 111, 15, 179, 146, 182, 11, 29, 72, 210, 118, 97, 132, 191, 239, 107, 218, 46, 148, 168, 88, 144, 164, 246, 210, 252, 73, 39, 168, 83, 219, 46, 164, 208, 182, 109, 87, 99, 111, 113, 130, 208, 182, 11, 61, 11, 210, 182, 11, 33, 173, 139, 70, 73, 231, 143, 95, 244, 203, 118, 33, 99, 237, 194, 134, 218, 247, 208, 218, 133, 140, 125, 13, 90, 187, 112, 33, 225, 214, 241, 70, 107, 211, 240, 66, 234, 143, 29, 245, 199, 142, 227, 105, 93, 43, 27, 72, 107, 68, 132, 10, 47, 141, 135, 161, 119, 154, 93, 8, 225, 222, 51, 187, 144, 129, 97, 248, 153, 93, 184, 208, 93, 168, 128, 129, 122, 211, 180, 11, 31, 34, 52, 60, 178, 88, 101, 217, 133, 12, 151, 191, 236, 66, 6, 151, 96, 111, 21, 251, 178, 11, 27, 19, 220, 178, 171, 129, 71, 16, 70, 52, 48, 215, 150, 93, 8, 89, 118, 97, 67, 29, 39, 71, 43, 211, 86, 116, 97, 67, 235, 66, 71, 69, 23, 42, 104, 19, 93, 168, 128, 126, 149, 162, 7, 109, 245, 29, 111, 79, 103, 99, 52, 247, 22, 141, 194, 74, 194, 29, 222, 89, 162, 234, 104, 7, 151, 77, 65, 141, 247, 29, 71, 48, 101, 141, 202, 50, 15, 159, 169, 45, 72, 170, 56, 161, 199, 210, 137, 46, 92, 88, 192, 64, 130, 125, 77, 29, 67, 116, 225, 195, 93, 23, 42, 100, 107, 93, 184, 208, 94, 58, 73, 219, 233, 66, 135, 74, 135, 158, 209, 133, 12, 137, 234, 66, 133, 214, 247, 183, 82, 171, 164, 147, 45, 248, 150, 255, 24, 132, 214, 39, 151, 218, 110, 32, 60, 192, 218, 68, 80, 178, 21, 66, 136, 74, 93, 168, 224, 17, 151, 106, 33, 131, 75, 181, 210, 66, 135, 245, 92, 91, 98, 194, 105, 161, 67, 109, 90, 168, 224, 90, 177, 222, 112, 215, 230, 17, 8, 139, 149, 147, 73, 211, 103, 133, 22, 76, 80, 103, 84, 228, 66, 199, 83, 145, 11, 21, 26, 104, 204, 152, 68, 57, 138, 44, 240, 44, 73, 167, 66, 7, 90, 177, 109, 63, 23, 50, 90, 63, 23, 46, 180, 215, 12, 109, 187, 32, 214, 202, 132, 222, 115, 161, 3, 135, 38, 127, 121, 142, 208, 129, 55, 45, 23, 46, 56, 195, 104, 120, 161, 227, 145, 32, 228, 145, 96, 0, 54, 194, 140, 251, 73, 144, 209, 186, 158, 4, 23, 244, 73, 80, 129, 235, 107, 107, 93, 158, 4, 35, 42, 47, 193, 134, 218, 231, 18, 92, 112, 151, 160, 130, 182, 250, 238, 181, 4, 25, 57, 105, 44, 193, 133, 150, 141, 37, 184, 240, 190, 205, 139, 37, 200, 240, 92, 201, 18, 100, 248, 108, 7, 111, 78, 40, 66, 178, 4, 27, 15, 167, 232, 78, 156, 148, 9, 65, 60, 84, 83, 111, 135, 254, 227, 110, 104, 211, 178, 39, 48, 52, 207, 169, 218, 110, 157, 48, 74, 150, 32, 36, 147, 191, 6, 37, 178, 104, 236, 17, 143, 32, 223, 71, 155, 0, 4, 203, 180, 39, 134, 55, 167, 111, 157, 188, 54, 171, 218, 132, 58, 179, 4, 31, 143, 226, 71, 49, 99, 65, 178, 4, 29, 146, 37, 168, 192, 169, 46, 71, 44, 65, 134, 82, 165, 234, 72, 23, 195, 60, 199, 145, 243, 175, 73, 144, 162, 194, 77, 130, 10, 174, 219, 36, 72, 241, 143, 37, 137, 155, 4, 25, 217, 120, 73, 112, 161, 159, 46, 9, 46, 104, 91, 134, 73, 164, 150, 4, 29, 169, 61, 142, 40, 185, 36, 216, 96, 24, 169, 182, 18, 180, 214, 74, 176, 145, 140, 219, 145, 32, 3, 210, 38, 155, 223, 245, 49, 101, 104, 242, 168, 4, 27, 38, 143, 74, 80, 193, 123, 211, 61, 233, 22, 205, 221, 251, 168, 4, 27, 110, 187, 121, 84, 130, 11, 143, 32, 85, 156, 30, 149, 160, 67, 146, 188, 210, 163, 18, 132, 64, 140, 155, 81, 157, 188, 60, 42, 65, 5, 232, 164, 95, 82, 164, 158, 203, 163, 18, 116, 160, 168, 4, 21, 56, 183, 46, 173, 18, 100, 244, 50, 42, 113, 170, 18, 157, 236, 74, 228, 84, 37, 8, 129, 154, 170, 4, 31, 19, 72, 16, 161, 33, 201, 148, 84, 130, 12, 232, 240, 230, 36, 193, 5, 215, 184, 69, 130, 11, 21, 253, 148, 224, 130, 131, 243, 210, 58, 81, 164, 203, 155, 208, 217, 216, 185, 173, 55, 110, 251, 88, 144, 94, 58, 197, 118, 50, 233, 11, 220, 91, 139, 251, 183, 189, 9, 143, 166, 57, 144, 78, 98, 246, 104, 216, 8, 93, 203, 52, 240, 72, 132, 5, 38, 38, 77, 25, 248, 0, 30, 236, 106, 40, 227, 94, 176, 233, 36, 7, 3, 15, 179, 16, 205, 75, 151, 92, 80, 178, 78, 9, 58, 96, 170, 157, 18, 100, 208, 245, 220, 165, 4, 23, 173, 239, 171, 108, 45, 117, 41, 193, 6, 143, 164, 132, 73, 201, 91, 144, 4, 25, 149, 8, 50, 116, 57, 182, 174, 79, 137, 160, 131, 169, 67, 252, 72, 66, 137, 160, 227, 213, 95, 27, 164, 76, 122, 131, 122, 38, 180, 228, 162, 146, 6, 143, 103, 57, 151, 232, 129, 97, 182, 241, 11, 241, 139, 158, 238, 151, 208, 251, 139, 96, 67, 191, 8, 46, 60, 220, 86, 120, 4, 23, 154, 182, 142, 42, 30, 193, 134, 207, 137, 71, 112, 97, 226, 17, 84, 176, 253, 60, 130, 11, 21, 239, 17, 84, 112, 201, 26, 170, 253, 13, 30, 193, 199, 98, 21, 126, 143, 224, 194, 35, 8, 241, 249, 30, 193, 5, 247, 8, 66, 186, 89, 53, 157, 44, 48, 161, 107, 201, 1, 172, 215, 15, 124, 179, 35, 119, 220, 78, 233, 187, 182, 8, 9, 253, 136, 136, 6, 18, 11, 244, 115, 177, 175, 190, 123, 4, 29, 191, 237, 33, 247, 8, 66, 60, 148, 101, 66, 238, 17, 116, 112, 143, 160, 2, 165, 233, 41, 109, 20, 209, 154, 245, 244, 246, 8, 54, 26, 152, 107, 12, 230, 60, 130, 15, 70, 57, 143, 224, 130, 243, 233, 60, 178, 40, 229, 119, 161, 228, 122, 211, 105, 59, 30, 206, 171, 119, 58, 215, 216, 35, 184, 160, 152, 181, 93, 232, 219, 46, 135, 111, 187, 180, 109, 67, 173, 180, 141, 61, 130, 12, 14, 39, 125, 58, 134, 89, 5, 73, 139, 229, 211, 88, 204, 87, 37, 2, 227, 193, 57, 46, 194, 196, 83, 4, 198, 195, 236, 55, 59, 132, 197, 242, 65, 15, 147, 174, 105, 91, 218, 247, 85, 133, 26, 120, 120, 149, 36, 166, 120, 183, 157, 252, 249, 93, 157, 79, 48, 188, 86, 54, 88, 208, 42, 73, 134, 97, 150, 209, 86, 245, 252, 174, 93, 246, 31, 104, 167, 99, 156, 214, 139, 80, 155, 92, 55, 246, 182, 12, 241, 127, 93, 80, 211, 137, 58, 224, 164, 79, 7, 33, 241, 100, 30, 65, 105, 27, 110, 88, 168, 113, 69, 23, 83, 250, 208, 172, 18, 228, 158, 98, 160, 43, 61, 169, 242, 152, 42, 36, 209, 202, 48, 143, 189, 246, 232, 117, 137, 26, 123, 4, 39, 38, 158, 80, 4, 212, 216, 35, 168, 160, 140, 61, 130, 11, 17, 24, 218, 50, 143, 224, 194, 183, 93, 30, 65, 6, 73, 178, 212, 254, 200, 127, 117, 134, 72, 146, 165, 116, 104, 215, 35, 248, 216, 245, 8, 42, 124, 91, 199, 35, 200, 224, 234, 120, 58, 30, 65, 134, 218, 110, 60, 130, 12, 238, 25, 143, 224, 130, 166, 102, 198, 35, 184, 72, 174, 30, 193, 5, 167, 30, 65, 133, 166, 30, 65, 5, 8, 91, 208, 55, 249, 108, 135, 212, 61, 13, 248, 35, 42, 218, 104, 171, 119, 186, 165, 75, 46, 143, 117, 137, 26, 137, 149, 71, 112, 33, 63, 21, 106, 42, 161, 158, 236, 82, 229, 17, 140, 200, 85, 202, 86, 178, 20, 244, 234, 218, 110, 65, 98, 229, 17, 228, 201, 35, 232, 80, 46, 121, 4, 23, 158, 89, 199, 85, 113, 242, 8, 62, 94, 85, 167, 147, 60, 130, 141, 182, 120, 4, 21, 118, 241, 8, 42, 180, 244, 8, 42, 44, 86, 137, 224, 17, 132, 56, 44, 150, 15, 242, 8, 46, 30, 102, 33, 234, 50, 185, 66, 68, 128, 64, 2, 9, 19, 72, 16, 33, 29, 8, 210, 89, 124, 210, 229, 17, 108, 120, 4, 25, 238, 17, 132, 120, 4, 39, 60, 130, 14, 9, 20, 67, 30, 65, 6, 244, 116, 246, 178, 11, 121, 4, 39, 82, 113, 4, 121, 4, 23, 206, 156, 223, 230, 102, 37, 194, 137, 8, 66, 120, 218, 230, 207, 182, 11, 227, 132, 60, 130, 16, 17, 108, 128, 60, 130, 143, 8, 54, 86, 182, 101, 173, 207, 15, 225, 155, 157, 183, 236, 111, 208, 180, 245, 84, 93, 9, 115, 130, 208, 240, 218, 153, 32, 232, 100, 253, 245, 47, 220, 30, 114, 160, 241, 58, 169, 61, 183, 111, 129, 46, 213, 222, 130, 246, 237, 107, 172, 181, 204, 87, 244, 181, 237, 146, 116, 58, 8, 182, 203, 159, 214, 55, 129, 101, 167, 131, 44, 85, 135, 162, 254, 152, 69, 232, 103, 55, 203, 222, 105, 86, 29, 228, 164, 159, 88, 154, 46, 89, 3, 107, 102, 30, 44, 59, 157, 131, 210, 110, 101, 84, 61, 248, 146, 143, 154, 182, 107, 113, 39, 23, 0, 50, 176, 237, 71, 19, 34, 184, 104, 187, 160, 150, 253, 141, 186, 8, 66, 60, 130, 26, 117, 17, 92, 108, 62, 71, 112, 65, 157, 35, 168, 144, 205, 17, 84, 96, 199, 161, 229, 8, 66, 44, 71, 240, 177, 28, 65, 5, 191, 138, 35, 184, 64, 1, 8, 36, 144, 32, 130, 90, 197, 17, 118, 110, 73, 4, 31, 223, 94, 55, 232, 55, 130, 141, 198, 25, 250, 101, 233, 180, 93, 131, 102, 135, 236, 141, 224, 195, 177, 141, 160, 194, 98, 21, 109, 34, 200, 176, 42, 26, 65, 5, 181, 8, 29, 173, 146, 230, 135, 59, 233, 147, 210, 180, 201, 86, 127, 146, 196, 12, 241, 191, 68, 30, 177, 88, 62, 238, 9, 73, 252, 38, 150, 250, 205, 132, 194, 191, 105, 83, 186, 158, 215, 206, 119, 164, 101, 54, 169, 115, 6, 13, 174, 143, 40, 188, 26, 44, 246, 14, 106, 101, 251, 16, 119, 143, 187, 145, 104, 109, 237, 245, 3, 157, 44, 118, 109, 7, 205, 221, 234, 62, 165, 107, 184, 127, 7, 231, 173, 36, 146, 36, 102, 185, 74, 153, 147, 62, 89, 235, 119, 123, 145, 137, 223, 246, 34, 17, 212, 51, 161, 182, 222, 250, 205, 78, 223, 211, 105, 64, 146, 152, 233, 98, 71, 107, 147, 81, 154, 212, 85, 38, 22, 80, 197, 109, 65, 83, 253, 202, 186, 3, 77, 245, 251, 177, 0, 154, 234, 51, 203, 160, 7, 152, 178, 198, 189, 147, 198, 0, 194, 88, 77, 244, 65, 146, 152, 33, 253, 84, 14, 13, 174, 141, 202, 5, 105, 147, 173, 19, 138, 102, 153, 198, 143, 93, 201, 95, 234, 77, 109, 211, 73, 14, 173, 48, 180, 223, 90, 137, 222, 53, 130, 143, 119, 141, 160, 66, 227, 180, 223, 84, 69, 176, 193, 77, 34, 101, 251, 19, 20, 218, 214, 73, 201, 28, 52, 127, 38, 127, 204, 194, 11, 190, 217, 177, 193, 36, 35, 248, 136, 160, 40, 254, 142, 164, 206, 23, 168, 226, 230, 186, 150, 78, 246, 208, 74, 225, 110, 24, 124, 82, 87, 113, 96, 152, 85, 218, 156, 42, 25, 73, 4, 209, 182, 204, 51, 130, 11, 199, 9, 143, 160, 93, 153, 43, 35, 232, 80, 73, 70, 80, 97, 109, 70, 240, 209, 218, 104, 70, 176, 65, 146, 234, 92, 146, 50, 130, 141, 103, 39, 73, 25, 193, 197, 123, 242, 111, 197, 54, 56, 52, 35, 125, 136, 181, 22, 252, 191, 40, 241, 139, 14, 103, 250, 139, 11, 205, 160, 146, 124, 244, 139, 139, 86, 108, 232, 90, 82, 162, 234, 208, 163, 95, 100, 120, 207, 133, 126, 113, 177, 184, 120, 111, 198, 47, 54, 218, 102, 43, 244, 139, 140, 207, 197, 198, 47, 50, 214, 74, 244, 139, 12, 171, 95, 182, 93, 154, 191, 162, 239, 139, 14, 173, 106, 177, 227, 218, 206, 47, 224, 16, 218, 180, 50, 135, 9, 9, 179, 19, 177, 236, 90, 192, 94, 191, 183, 133, 60, 158, 251, 250, 34, 227, 31, 63, 185, 144, 58, 126, 246, 69, 7, 95, 108, 252, 54, 14, 20, 78, 122, 101, 32, 210, 58, 174, 153, 177, 47, 70, 64, 16, 129, 9, 38, 192, 190, 8, 225, 223, 146, 125, 177, 65, 66, 195, 169, 64, 16, 32, 10, 72, 152, 0, 177, 47, 66, 34, 32, 8, 208, 4, 19, 64, 32, 1, 177, 47, 74, 164, 109, 109, 248, 34, 195, 35, 186, 118, 97, 214, 173, 190, 184, 240, 197, 198, 243, 226, 139, 11, 186, 150, 241, 245, 197, 69, 4, 95, 84, 224, 182, 194, 25, 84, 51, 5, 249, 98, 68, 131, 79, 103, 241, 234, 46, 153, 36, 149, 130, 124, 157, 111, 204, 28, 52, 181, 124, 111, 17, 19, 11, 175, 166, 1, 45, 62, 44, 173, 238, 57, 90, 253, 26, 182, 159, 115, 15, 249, 98, 195, 34, 133, 243, 233, 80, 106, 175, 193, 129, 97, 228, 216, 175, 232, 231, 51, 44, 94, 216, 243, 233, 80, 51, 113, 228, 139, 143, 38, 23, 131, 156, 131, 94, 181, 60, 73, 203, 181, 60, 55, 164, 90, 162, 212, 254, 134, 227, 207, 208, 180, 117, 94, 9, 49, 235, 225, 181, 147, 122, 163, 105, 219, 218, 107, 10, 175, 149, 232, 233, 215, 94, 210, 215, 249, 116, 8, 34, 215, 123, 80, 218, 250, 190, 13, 174, 162, 77, 67, 27, 249, 58, 139, 144, 134, 231, 91, 221, 195, 23, 29, 186, 150, 116, 154, 29, 242, 182, 185, 32, 170, 214, 29, 20, 37, 161, 182, 200, 249, 116, 42, 178, 48, 242, 69, 6, 149, 236, 66, 139, 14, 204, 53, 228, 187, 220, 90, 129, 116, 178, 16, 159, 141, 54, 228, 139, 15, 43, 251, 69, 100, 67, 190, 200, 160, 118, 229, 228, 129, 208, 245, 148, 174, 93, 152, 33, 95, 108, 172, 37, 23, 39, 92, 50, 228, 139, 12, 20, 94, 138, 19, 242, 69, 136, 198, 139, 8, 242, 69, 71, 100, 225, 8, 242, 197, 134, 198, 69, 144, 47, 50, 56, 227, 22, 110, 145, 47, 46, 232, 100, 63, 101, 235, 59, 60, 107, 65, 131, 54, 201, 182, 121, 185, 138, 46, 242, 69, 200, 98, 239, 32, 95, 92, 60, 42, 121, 118, 144, 47, 54, 210, 65, 85, 212, 65, 190, 248, 176, 184, 88, 253, 28, 79, 243, 175, 179, 211, 142, 120, 190, 87, 253, 50, 219, 32, 95, 100, 80, 71, 255, 0, 105, 12, 106, 218, 240, 126, 106, 239, 241, 109, 217, 33, 85, 156, 144, 243, 106, 41, 107, 189, 198, 32, 95, 92, 120, 186, 241, 126, 86, 236, 202, 214, 128, 185, 122, 67, 211, 137, 34, 95, 92, 168, 102, 202, 163, 18, 52, 1, 4, 17, 136, 224, 17, 205, 221, 190, 8, 241, 188, 99, 202, 88, 155, 76, 37, 137, 21, 114, 72, 47, 131, 210, 182, 12, 242, 69, 71, 179, 66, 139, 18, 142, 223, 125, 177, 193, 61, 23, 163, 115, 189, 212, 219, 106, 19, 242, 197, 133, 174, 37, 215, 202, 132, 124, 241, 209, 246, 215, 190, 5, 249, 98, 132, 47, 82, 168, 222, 69, 223, 67, 210, 114, 45, 200, 23, 25, 157, 205, 225, 219, 54, 27, 193, 4, 234, 185, 32, 95, 108, 52, 6, 165, 246, 248, 195, 241, 125, 178, 123, 145, 209, 74, 241, 134, 210, 79, 182, 45, 145, 47, 62, 86, 70, 172, 76, 251, 186, 164, 227, 86, 34, 95, 124, 240, 197, 0, 184, 118, 47, 70, 44, 58, 26, 247, 162, 194, 4, 19, 183, 232, 64, 201, 102, 44, 238, 209, 188, 36, 212, 164, 106, 88, 110, 209, 225, 107, 255, 57, 190, 233, 46, 8, 95, 251, 143, 113, 139, 15, 173, 84, 78, 224, 22, 23, 19, 184, 69, 5, 237, 22, 27, 21, 109, 180, 145, 91, 100, 184, 69, 7, 183, 24, 0, 182, 142, 156, 23, 23, 105, 27, 47, 46, 180, 170, 93, 222, 120, 241, 161, 117, 45, 238, 8, 132, 86, 9, 247, 194, 139, 12, 188, 105, 251, 175, 14, 129, 189, 117, 46, 33, 240, 162, 132, 171, 123, 254, 225, 143, 120, 241, 161, 193, 195, 172, 183, 78, 114, 59, 39, 109, 177, 225, 252, 75, 70, 191, 239, 219, 34, 196, 35, 16, 184, 191, 45, 50, 88, 106, 91, 124, 252, 115, 109, 209, 210, 71, 235, 91, 175, 236, 183, 28, 196, 3, 9, 165, 190, 190, 45, 42, 232, 36, 149, 226, 96, 160, 213, 23, 188, 182, 115, 201, 26, 207, 203, 81, 195, 202, 198, 208, 148, 204, 195, 63, 86, 239, 232, 157, 38, 136, 125, 168, 245, 27, 218, 197, 96, 233, 183, 197, 133, 214, 70, 191, 45, 46, 36, 72, 240, 109, 113, 193, 61, 65, 248, 22, 129, 24, 55, 131, 62, 37, 179, 223, 137, 214, 106, 96, 93, 190, 183, 197, 5, 205, 15, 170, 173, 4, 35, 222, 105, 214, 219, 226, 194, 61, 161, 35, 66, 3, 61, 112, 62, 221, 196, 59, 166, 203, 49, 78, 252, 47, 81, 3, 173, 189, 111, 66, 91, 100, 104, 115, 66, 14, 18, 79, 214, 248, 124, 174, 45, 66, 22, 184, 59, 240, 225, 145, 180, 69, 5, 73, 91, 124, 184, 236, 247, 196, 10, 73, 218, 34, 164, 194, 11, 146, 180, 197, 133, 164, 53, 94, 200, 171, 58, 24, 129, 140, 109, 139, 10, 156, 241, 219, 234, 180, 197, 5, 51, 109, 241, 209, 120, 209, 193, 180, 197, 198, 55, 109, 18, 161, 131, 55, 185, 38, 19, 74, 59, 29, 255, 108, 245, 56, 15, 158, 253, 21, 101, 224, 158, 43, 81, 124, 58, 198, 14, 170, 184, 77, 208, 4, 183, 69, 107, 163, 48, 106, 101, 218, 226, 227, 91, 219, 226, 66, 69, 181, 69, 133, 149, 79, 237, 100, 85, 91, 116, 84, 28, 12, 35, 215, 10, 82, 90, 81, 213, 22, 29, 120, 177, 200, 240, 172, 73, 171, 47, 140, 22, 232, 239, 162, 99, 173, 231, 160, 138, 78, 26, 39, 132, 13, 90, 157, 79, 183, 160, 85, 45, 102, 218, 162, 3, 106, 139, 142, 228, 108, 81, 225, 87, 189, 212, 9, 183, 99, 139, 19, 238, 186, 158, 98, 135, 124, 101, 19, 21, 143, 56, 143, 218, 82, 52, 48, 126, 56, 174, 205, 64, 20, 37, 33, 7, 50, 232, 114, 239, 31, 124, 49, 255, 68, 21, 146, 208, 213, 120, 126, 215, 226, 132, 126, 174, 82, 198, 22, 27, 206, 22, 27, 173, 108, 209, 225, 17, 196, 48, 171, 80, 195, 22, 31, 186, 28, 91, 71, 46, 217, 226, 195, 37, 91, 84, 240, 72, 107, 202, 254, 6, 165, 42, 121, 121, 131, 101, 13, 220, 76, 28, 181, 101, 223, 242, 77, 104, 154, 139, 104, 154, 219, 119, 140, 218, 50, 136, 70, 93, 164, 130, 25, 106, 203, 118, 37, 4, 105, 203, 24, 20, 234, 158, 103, 235, 21, 235, 14, 253, 215, 149, 174, 98, 217, 182, 125, 32, 95, 153, 3, 66, 251, 189, 203, 132, 180, 73, 182, 216, 176, 52, 255, 90, 100, 112, 7, 103, 24, 13, 203, 116, 1, 244, 44, 40, 66, 155, 91, 179, 200, 64, 209, 90, 177, 222, 204, 162, 67, 183, 50, 139, 11, 147, 166, 136, 89, 100, 104, 234, 152, 155, 46, 50, 34, 144, 64, 2, 170, 186, 184, 168, 168, 69, 5, 174, 22, 21, 120, 4, 233, 82, 139, 139, 149, 147, 71, 37, 104, 81, 139, 142, 69, 45, 42, 240, 180, 232, 240, 180, 168, 64, 127, 23, 114, 76, 26, 167, 197, 5, 73, 90, 167, 105, 113, 1, 81, 154, 22, 29, 46, 19, 210, 180, 184, 240, 8, 132, 149, 105, 113, 209, 138, 86, 166, 197, 134, 102, 182, 44, 46, 80, 143, 87, 66, 108, 89, 148, 240, 197, 252, 45, 151, 197, 70, 203, 101, 81, 193, 65, 21, 183, 6, 21, 155, 120, 49, 104, 224, 165, 125, 184, 127, 71, 53, 149, 36, 10, 103, 36, 156, 212, 160, 185, 162, 109, 2, 16, 44, 14, 192, 49, 253, 134, 67, 34, 160, 54, 1, 8, 22, 25, 218, 4, 32, 88, 84, 80, 150, 13, 125, 82, 52, 117, 220, 227, 32, 195, 243, 173, 142, 0, 239, 250, 38, 56, 90, 37, 109, 215, 67, 237, 162, 213, 61, 14, 66, 154, 54, 143, 131, 11, 143, 196, 159, 131, 11, 173, 237, 57, 184, 96, 245, 131, 248, 91, 238, 193, 25, 210, 138, 213, 138, 245, 71, 20, 72, 43, 54, 66, 43, 86, 217, 190, 195, 87, 182, 102, 189, 97, 229, 164, 245, 155, 131, 90, 212, 146, 61, 7, 25, 109, 23, 196, 205, 115, 144, 241, 236, 124, 33, 73, 185, 252, 215, 173, 227, 144, 166, 234, 222, 224, 186, 94, 183, 205, 94, 148, 53, 207, 57, 244, 115, 121, 203, 126, 6, 62, 225, 40, 226, 121, 121, 14, 46, 124, 211, 38, 221, 33, 220, 253, 59, 184, 160, 27, 33, 130, 132, 42, 78, 232, 209, 40, 172, 254, 57, 206, 63, 241, 84, 184, 23, 188, 179, 243, 8, 114, 104, 218, 114, 243, 143, 37, 109, 23, 68, 211, 150, 113, 106, 11, 113, 247, 147, 213, 164, 170, 97, 173, 76, 158, 246, 91, 50, 117, 164, 78, 202, 68, 145, 214, 115, 113, 184, 34, 167, 68, 56, 255, 26, 223, 255, 14, 62, 220, 191, 131, 10, 143, 157, 95, 10, 138, 240, 112, 112, 203, 246, 109, 23, 67, 21, 167, 10, 64, 168, 69, 17, 68, 32, 48, 202, 69, 120, 120, 78, 90, 166, 8, 174, 44, 27, 106, 242, 145, 78, 246, 13, 224, 110, 37, 46, 128, 137, 126, 76, 0, 137, 175, 82, 157, 78, 3, 174, 150, 39, 205, 14, 218, 240, 21, 125, 196, 175, 146, 100, 140, 114, 136, 223, 27, 77, 62, 195, 117, 61, 255, 73, 151, 250, 131, 129, 136, 8, 15, 179, 20, 173, 203, 108, 91, 246, 174, 17, 212, 234, 50, 121, 67, 43, 195, 108, 243, 5, 46, 25, 98, 186, 20, 194, 88, 73, 184, 254, 91, 182, 255, 19, 45, 246, 14, 62, 44, 246, 14, 42, 76, 222, 114, 7, 23, 210, 29, 116, 44, 119, 176, 241, 141, 209, 118, 16, 50, 193, 57, 168, 192, 57, 7, 21, 56, 137, 147, 164, 116, 14, 50, 90, 23, 133, 29, 100, 240, 8, 242, 71, 37, 207, 14, 58, 252, 217, 113, 244, 236, 96, 35, 215, 99, 7, 37, 116, 237, 59, 59, 184, 120, 28, 179, 131, 11, 74, 43, 203, 160, 135, 47, 232, 90, 82, 189, 35, 9, 179, 131, 12, 110, 236, 160, 130, 71, 80, 107, 163, 114, 121, 180, 177, 131, 14, 16, 189, 74, 25, 59, 184, 168, 160, 125, 12, 180, 81, 219, 139, 50, 118, 208, 225, 124, 58, 164, 140, 29, 108, 56, 246, 168, 25, 41, 99, 71, 45, 118, 144, 225, 220, 208, 251, 178, 131, 13, 60, 2, 161, 101, 195, 14, 50, 36, 202, 14, 42, 64, 144, 142, 167, 100, 14, 50, 154, 197, 193, 134, 71, 32, 248, 114, 144, 161, 177, 71, 28, 92, 88, 10, 146, 192, 133, 175, 210, 94, 7, 23, 173, 155, 78, 114, 235, 32, 196, 243, 171, 118, 177, 35, 143, 68, 32, 48, 176, 38, 76, 104, 115, 66, 174, 154, 41, 20, 174, 232, 157, 102, 23, 68, 181, 92, 78, 179, 14, 50, 244, 77, 28, 28, 72, 248, 119, 58, 201, 105, 2, 234, 216, 224, 147, 46, 117, 100, 80, 109, 85, 75, 29, 25, 188, 8, 241, 235, 37, 211, 168, 35, 196, 63, 150, 168, 58, 46, 220, 86, 44, 72, 162, 234, 216, 80, 170, 142, 14, 165, 234, 248, 104, 240, 213, 232, 151, 212, 161, 217, 17, 2, 2, 201, 4, 18, 68, 112, 73, 29, 27, 206, 178, 211, 53, 248, 59, 205, 122, 91, 132, 15, 14, 220, 117, 177, 84, 71, 9, 167, 28, 21, 168, 231, 130, 36, 202, 145, 209, 90, 177, 238, 201, 209, 225, 113, 134, 71, 26, 238, 233, 228, 8, 129, 164, 109, 146, 61, 156, 87, 75, 65, 157, 75, 131, 82, 165, 218, 16, 179, 104, 1, 138, 238, 4, 241, 183, 117, 208, 188, 147, 116, 116, 65, 15, 77, 91, 100, 104, 168, 40, 194, 7, 220, 45, 28, 191, 196, 85, 161, 103, 199, 37, 214, 122, 12, 58, 28, 39, 71, 135, 235, 194, 117, 127, 211, 62, 133, 175, 253, 135, 144, 70, 70, 114, 124, 180, 126, 114, 132, 44, 109, 45, 157, 132, 146, 163, 227, 97, 214, 17, 178, 56, 6, 192, 155, 86, 210, 113, 161, 146, 142, 10, 30, 19, 85, 72, 39, 233, 200, 208, 73, 58, 42, 32, 77, 47, 29, 25, 124, 219, 213, 248, 228, 233, 8, 113, 79, 71, 133, 86, 231, 210, 145, 193, 73, 159, 238, 113, 79, 16, 32, 19, 139, 189, 211, 128, 17, 141, 61, 194, 142, 31, 105, 75, 199, 134, 86, 213, 210, 145, 193, 91, 151, 89, 247, 252, 2, 20, 118, 28, 61, 157, 239, 83, 75, 71, 7, 150, 206, 210, 145, 225, 97, 118, 177, 116, 92, 176, 116, 124, 188, 175, 66, 30, 129, 192, 11, 65, 215, 50, 16, 172, 25, 73, 152, 29, 228, 32, 241, 85, 200, 215, 166, 227, 194, 202, 137, 162, 118, 52, 196, 23, 232, 100, 177, 71, 168, 104, 163, 93, 209, 70, 123, 66, 189, 31, 218, 114, 228, 115, 49, 13, 136, 50, 233, 248, 104, 117, 82, 123, 185, 30, 42, 203, 160, 69, 45, 138, 0, 2, 180, 157, 76, 58, 70, 168, 74, 71, 5, 137, 114, 148, 46, 193, 145, 65, 105, 107, 214, 37, 56, 50, 90, 39, 45, 193, 145, 65, 130, 35, 196, 195, 203, 169, 66, 18, 28, 27, 17, 28, 31, 17, 223, 118, 249, 63, 156, 95, 10, 114, 201, 222, 95, 58, 21, 7, 210, 43, 242, 72, 165, 145, 225, 145, 74, 163, 130, 75, 232, 239, 66, 149, 198, 69, 165, 49, 0, 148, 198, 0, 184, 186, 231, 219, 107, 100, 180, 215, 216, 104, 218, 180, 215, 200, 224, 218, 94, 227, 66, 123, 237, 53, 62, 144, 64, 237, 53, 66, 94, 35, 163, 113, 66, 237, 53, 46, 82, 123, 60, 81, 123, 141, 13, 247, 180, 190, 145, 97, 125, 163, 195, 77, 188, 81, 65, 215, 146, 143, 32, 250, 251, 188, 145, 193, 189, 81, 129, 3, 87, 247, 124, 131, 174, 37, 41, 188, 152, 70, 200, 4, 230, 141, 143, 9, 204, 27, 21, 92, 69, 145, 98, 198, 212, 161, 244, 244, 70, 135, 174, 215, 141, 11, 158, 92, 163, 131, 71, 32, 44, 157, 112, 35, 195, 221, 162, 110, 134, 214, 138, 109, 13, 39, 109, 8, 136, 42, 110, 14, 253, 199, 141, 15, 126, 164, 218, 227, 70, 134, 58, 110, 108, 112, 62, 221, 51, 55, 50, 158, 185, 209, 225, 18, 230, 198, 5, 95, 251, 79, 66, 223, 228, 249, 78, 28, 60, 204, 174, 230, 69, 120, 117, 79, 157, 180, 250, 132, 123, 114, 85, 220, 144, 55, 224, 170, 184, 185, 42, 110, 141, 61, 34, 225, 124, 186, 5, 180, 98, 93, 215, 50, 106, 237, 91, 92, 253, 35, 40, 158, 213, 24, 185, 123, 196, 189, 150, 186, 210, 2, 173, 88, 71, 186, 84, 123, 15, 150, 46, 185, 76, 240, 63, 6, 90, 43, 158, 149, 45, 145, 193, 0, 58, 151, 181, 88, 23, 47, 44, 19, 55, 62, 124, 82, 119, 224, 250, 153, 86, 105, 187, 8, 157, 44, 246, 137, 71, 207, 223, 178, 45, 107, 125, 85, 18, 238, 218, 111, 225, 198, 7, 132, 13, 221, 201, 141, 11, 76, 181, 70, 133, 119, 118, 80, 107, 116, 88, 120, 45, 173, 177, 161, 25, 214, 168, 144, 88, 227, 131, 31, 173, 245, 28, 74, 172, 113, 2, 37, 214, 24, 145, 88, 35, 4, 107, 116, 36, 214, 8, 113, 171, 81, 65, 91, 134, 26, 34, 48, 1, 4, 138, 169, 219, 198, 134, 74, 71, 225, 214, 120, 167, 217, 198, 7, 99, 182, 83, 157, 70, 72, 170, 211, 168, 208, 188, 56, 45, 77, 35, 163, 162, 78, 132, 165, 105, 92, 84, 180, 209, 70, 75, 211, 216, 168, 168, 131, 150, 166, 113, 177, 52, 141, 10, 146, 98, 26, 21, 34, 68, 128, 2, 19, 36, 166, 113, 49, 129, 8, 38, 136, 32, 49, 141, 139, 95, 223, 9, 132, 129, 164, 153, 162, 141, 12, 146, 196, 204, 161, 189, 20, 109, 100, 104, 126, 104, 163, 137, 54, 50, 30, 102, 253, 105, 39, 122, 250, 181, 113, 65, 123, 159, 237, 107, 227, 130, 194, 237, 188, 54, 46, 22, 37, 105, 235, 188, 54, 54, 32, 252, 91, 186, 231, 59, 153, 75, 180, 253, 92, 16, 135, 175, 232, 55, 42, 104, 101, 47, 226, 205, 221, 234, 224, 15, 15, 179, 239, 218, 184, 80, 149, 41, 25, 244, 174, 141, 143, 119, 109, 84, 152, 108, 132, 74, 118, 65, 188, 177, 115, 109, 108, 240, 111, 118, 21, 133, 176, 250, 73, 172, 126, 174, 158, 187, 18, 249, 75, 48, 111, 225, 231, 118, 202, 178, 57, 15, 49, 89, 252, 192, 184, 93, 215, 50, 144, 94, 149, 154, 170, 166, 78, 85, 3, 69, 73, 143, 230, 86, 34, 132, 36, 108, 56, 40, 157, 244, 187, 82, 154, 65, 87, 69, 133, 86, 108, 67, 123, 23, 84, 84, 181, 109, 24, 43, 27, 239, 59, 174, 128, 147, 50, 181, 7, 161, 218, 175, 147, 197, 142, 180, 87, 233, 90, 167, 44, 27, 133, 178, 108, 201, 84, 178, 171, 25, 238, 85, 15, 238, 148, 12, 194, 130, 119, 120, 243, 187, 166, 150, 8, 35, 158, 126, 237, 124, 127, 120, 201, 13, 77, 190, 34, 200, 187, 62, 110, 134, 161, 40, 105, 173, 68, 19, 180, 113, 193, 124, 219, 229, 242, 205, 78, 27, 29, 13, 107, 165, 227, 1, 93, 203, 160, 182, 15, 72, 83, 46, 135, 30, 184, 104, 72, 117, 218, 232, 160, 86, 130, 13, 253, 109, 74, 235, 132, 31, 190, 86, 38, 196, 178, 105, 227, 2, 215, 148, 206, 115, 101, 167, 83, 71, 77, 219, 181, 217, 255, 224, 129, 241, 130, 116, 130, 12, 19, 85, 19, 171, 31, 106, 219, 108, 51, 210, 103, 246, 204, 180, 209, 161, 113, 218, 202, 50, 109, 108, 164, 82, 166, 141, 12, 149, 237, 79, 182, 164, 47, 72, 252, 250, 185, 28, 73, 58, 217, 227, 164, 182, 82, 165, 173, 106, 95, 227, 157, 46, 194, 249, 100, 143, 246, 88, 107, 118, 37, 82, 183, 174, 105, 171, 84, 58, 180, 150, 166, 7, 154, 198, 253, 254, 64, 215, 107, 6, 250, 86, 78, 124, 23, 2, 92, 169, 63, 2, 184, 106, 207, 0, 62, 161, 218, 34, 93, 75, 254, 0, 36, 109, 87, 2, 180, 73, 182, 232, 95, 250, 102, 5, 120, 231, 90, 172, 16, 55, 244, 109, 87, 3, 139, 189, 195, 152, 198, 33, 225, 250, 220, 158, 153, 129, 112, 73, 219, 181, 96, 35, 204, 20, 82, 145, 88, 61, 92, 146, 218, 75, 3, 58, 112, 201, 180, 209, 129, 155, 149, 21, 8, 29, 16, 143, 75, 152, 157, 199, 83, 128, 39, 151, 42, 173, 228, 210, 70, 136, 178, 77, 45, 219, 178, 183, 36, 244, 83, 97, 195, 202, 73, 235, 183, 213, 198, 5, 103, 160, 255, 150, 109, 110, 224, 65, 210, 201, 32, 148, 108, 71, 69, 98, 245, 240, 166, 173, 74, 117, 212, 61, 142, 54, 58, 96, 188, 156, 67, 69, 104, 253, 207, 228, 14, 42, 130, 182, 93, 15, 21, 161, 185, 91, 209, 106, 180, 17, 178, 26, 109, 84, 240, 72, 163, 141, 143, 166, 18, 254, 167, 39, 176, 129, 54, 39, 4, 121, 206, 85, 22, 44, 59, 93, 197, 155, 92, 12, 4, 8, 255, 84, 251, 145, 171, 60, 124, 253, 89, 217, 18, 189, 39, 114, 149, 166, 13, 163, 213, 59, 93, 69, 27, 109, 132, 44, 152, 104, 126, 184, 238, 183, 42, 78, 219, 30, 114, 64, 181, 209, 177, 246, 95, 195, 239, 115, 134, 4, 71, 142, 239, 90, 158, 91, 240, 52, 218, 232, 96, 27, 212, 180, 121, 84, 130, 26, 109, 92, 192, 23, 243, 51, 218, 200, 120, 84, 222, 98, 180, 145, 161, 194, 75, 165, 225, 143, 74, 26, 133, 31, 24, 126, 109, 32, 48, 72, 186, 24, 109, 132, 120, 210, 46, 118, 168, 241, 33, 25, 109, 84, 88, 133, 26, 24, 109, 116, 172, 203, 134, 24, 109, 100, 48, 218, 168, 64, 211, 75, 175, 60, 213, 94, 127, 83, 111, 185, 92, 54, 233, 174, 109, 155, 244, 108, 210, 29, 149, 167, 214, 99, 143, 202, 83, 206, 237, 98, 80, 197, 93, 153, 58, 191, 160, 225, 181, 128, 131, 230, 223, 198, 12, 73, 18, 43, 52, 81, 89, 204, 201, 209, 56, 165, 66, 116, 105, 160, 212, 73, 159, 203, 2, 231, 159, 196, 186, 68, 149, 79, 137, 26, 149, 167, 180, 113, 161, 217, 27, 162, 161, 178, 114, 211, 46, 199, 214, 31, 172, 149, 9, 81, 52, 253, 207, 197, 56, 164, 149, 9, 185, 39, 124, 232, 124, 87, 218, 184, 216, 149, 80, 35, 177, 210, 198, 5, 73, 226, 165, 180, 113, 33, 73, 204, 36, 137, 23, 51, 109, 29, 190, 14, 253, 254, 86, 66, 190, 171, 180, 113, 65, 233, 163, 74, 27, 23, 159, 82, 27, 85, 120, 81, 218, 8, 241, 215, 78, 234, 232, 83, 42, 109, 116, 160, 232, 78, 222, 119, 117, 35, 132, 147, 62, 41, 15, 169, 61, 142, 24, 32, 140, 72, 237, 113, 180, 40, 217, 73, 27, 33, 77, 211, 70, 6, 107, 57, 105, 35, 67, 47, 59, 73, 27, 23, 186, 82, 162, 67, 194, 4, 61, 94, 180, 113, 225, 158, 139, 54, 50, 180, 78, 82, 27, 25, 94, 213, 113, 196, 248, 159, 23, 132, 13, 156, 79, 183, 82, 27, 31, 216, 90, 104, 218, 182, 78, 10, 250, 149, 64, 126, 37, 251, 251, 144, 182, 93, 218, 118, 169, 182, 107, 33, 11, 175, 6, 245, 42, 149, 218, 8, 113, 217, 13, 252, 104, 81, 74, 106, 255, 3, 203, 199, 225, 209, 72, 220, 106, 172, 212, 210, 84, 209, 73, 83, 164, 82, 27, 66, 210, 158, 163, 78, 202, 228, 112, 15, 165, 94, 186, 228, 178, 86, 34, 165, 224, 178, 223, 43, 79, 77, 246, 179, 237, 106, 220, 207, 158, 150, 93, 18, 87, 213, 180, 162, 65, 151, 247, 143, 31, 231, 151, 226, 252, 82, 188, 169, 163, 9, 59, 191, 239, 157, 80, 116, 39, 251, 30, 163, 173, 159, 239, 234, 47, 98, 81, 202, 132, 191, 8, 245, 71, 161, 254, 246, 215, 123, 109, 212, 82, 208, 2, 7, 213, 169, 139, 106, 51, 7, 73, 184, 253, 197, 252, 139, 31, 15, 179, 239, 201, 255, 180, 253, 6, 108, 63, 130, 173, 50, 117, 38, 42, 250, 174, 63, 209, 216, 113, 186, 212, 155, 252, 135, 38, 127, 201, 255, 252, 246, 248, 218, 127, 218, 156, 16, 69, 119, 130, 214, 146, 234, 150, 226, 150, 178, 43, 161, 137, 55, 39, 212, 76, 188, 153, 120, 227, 125, 213, 190, 70, 215, 243, 174, 235, 121, 222, 31, 183, 237, 151, 48, 59, 72, 155, 108, 158, 80, 197, 109, 41, 47, 8, 226, 145, 164, 125, 175, 88, 10, 114, 250, 105, 63, 223, 59, 223, 219, 58, 215, 182, 75, 210, 233, 60, 162, 154, 66, 16, 72, 163, 176, 82, 181, 203, 153, 86, 64, 152, 46, 199, 84, 113, 202, 73, 203, 132, 180, 223, 103, 107, 214, 115, 81, 181, 222, 208, 204, 16, 133, 29, 167, 208, 78, 199, 25, 80, 88, 165, 195, 88, 161, 247, 93, 237, 241, 100, 224, 147, 46, 117, 71, 157, 75, 131, 191, 231, 66, 146, 182, 11, 57, 158, 14, 99, 245, 143, 187, 161, 222, 58, 161, 88, 169, 147, 125, 43, 21, 51, 6, 15, 204, 34, 165, 189, 111, 130, 54, 90, 139, 153, 53, 120, 114, 105, 51, 218, 217, 76, 69, 23, 163, 253, 158, 252, 18, 149, 167, 180, 215, 166, 198, 73, 91, 251, 179, 221, 227, 110, 40, 122, 130, 174, 166, 225, 71, 142, 91, 157, 29, 43, 191, 249, 193, 35, 16, 158, 245, 188, 28, 68, 210, 118, 33, 181, 185, 92, 196, 174, 213, 38, 157, 187, 111, 218, 182, 170, 102, 135, 166, 14, 5, 61, 171, 113, 235, 194, 222, 132, 42, 118, 71, 220, 124, 201, 111, 176, 40, 229, 217, 113, 68, 209, 157, 48, 96, 85, 59, 225, 79, 58, 121, 160, 246, 189, 198, 219, 180, 117, 207, 59, 240, 164, 166, 157, 174, 173, 36, 101, 127, 1, 26, 104, 117, 75, 113, 75, 105, 38, 238, 205, 196, 153, 151, 167, 249, 29, 232, 92, 84, 123, 44, 225, 178, 45, 208, 250, 159, 15, 180, 211, 241, 37, 31, 45, 254, 166, 172, 209, 2, 56, 69, 119, 146, 218, 137, 148, 73, 255, 206, 119, 10, 157, 236, 98, 239, 56, 112, 60, 149, 182, 210, 108, 253, 103, 105, 38, 168, 153, 193, 107, 202, 144, 123, 142, 25, 229, 92, 58, 109, 210, 241, 66, 77, 183, 185, 129, 98, 182, 82, 49, 147, 248, 138, 62, 210, 5, 11, 218, 166, 147, 30, 149, 80, 116, 39, 72, 59, 41, 137, 20, 160, 146, 164, 36, 114, 170, 146, 230, 207, 180, 170, 109, 107, 94, 180, 145, 115, 217, 22, 57, 151, 168, 237, 2, 140, 185, 130, 49, 87, 160, 150, 14, 105, 147, 140, 1, 199, 157, 92, 46, 69, 119, 178, 216, 59, 41, 23, 165, 202, 160, 180, 239, 210, 105, 224, 211, 73, 72, 233, 51, 219, 160, 215, 230, 1, 77, 59, 105, 117, 196, 139, 181, 113, 199, 115, 49, 219, 74, 209, 93, 151, 200, 73, 175, 204, 87, 180, 33, 229, 11, 35, 33, 105, 187, 208, 218, 100, 148, 236, 73, 211, 231, 9, 102, 218, 34, 77, 59, 81, 7, 159, 170, 129, 71, 16, 191, 123, 250, 83, 190, 42, 78, 214, 7, 104, 150, 105, 19, 105, 219, 99, 140, 19, 3, 138, 81, 75, 93, 105, 129, 95, 9, 250, 78, 39, 165, 150, 189, 76, 56, 158, 203, 249, 51, 47, 207, 98, 92, 57, 122, 120, 113, 254, 37, 114, 206, 95, 68, 169, 58, 14, 152, 253, 245, 34, 38, 60, 97, 86, 181, 147, 136, 149, 138, 217, 86, 150, 53, 101, 92, 209, 32, 87, 41, 235, 231, 169, 172, 65, 21, 27, 192, 62, 79, 74, 37, 158, 108, 53, 79, 46, 135, 116, 255, 121, 241, 126, 86, 236, 202, 196, 171, 241, 235, 82, 137, 51, 88, 154, 151, 35, 9, 38, 168, 177, 82, 137, 218, 29, 233, 90, 82, 37, 27, 64, 37, 59, 30, 102, 37, 109, 215, 186, 219, 181, 20, 185, 182, 93, 174, 43, 61, 73, 153, 93, 12, 188, 46, 38, 181, 113, 120, 42, 114, 65, 228, 164, 177, 196, 35, 238, 17, 214, 204, 52, 246, 8, 106, 236, 17, 110, 236, 17, 214, 145, 68, 205, 191, 18, 102, 7, 41, 253, 246, 152, 33, 223, 5, 74, 63, 147, 182, 83, 133, 124, 151, 177, 190, 173, 132, 217, 65, 12, 48, 78, 173, 223, 246, 185, 214, 76, 92, 194, 236, 160, 5, 154, 108, 133, 178, 229, 170, 246, 42, 219, 60, 36, 222, 180, 117, 6, 174, 77, 178, 10, 47, 239, 52, 187, 90, 215, 202, 166, 181, 73, 182, 142, 59, 33, 109, 146, 65, 104, 147, 12, 194, 108, 47, 181, 171, 158, 11, 106, 156, 246, 225, 43, 218, 38, 0, 193, 74, 152, 29, 212, 240, 158, 252, 232, 217, 89, 151, 232, 217, 145, 48, 59, 173, 174, 154, 41, 232, 193, 105, 214, 121, 101, 75, 29, 8, 75, 135, 189, 218, 110, 248, 201, 133, 212, 118, 35, 97, 130, 180, 25, 184, 54, 205, 115, 214, 6, 34, 130, 108, 178, 97, 60, 21, 21, 143, 105, 170, 157, 28, 173, 245, 34, 24, 43, 196, 184, 43, 84, 155, 129, 176, 108, 214, 204, 52, 70, 254, 18, 59, 72, 18, 47, 228, 47, 241, 226, 118, 73, 232, 132, 25, 114, 187, 212, 118, 131, 42, 188, 84, 116, 73, 252, 74, 80, 147, 235, 151, 105, 236, 83, 207, 69, 123, 25, 103, 167, 107, 25, 7, 93, 203, 56, 159, 202, 232, 155, 208, 201, 208, 123, 50, 18, 239, 18, 75, 43, 235, 154, 54, 157, 60, 185, 90, 39, 60, 241, 116, 170, 246, 120, 65, 205, 221, 218, 52, 143, 32, 126, 244, 120, 42, 132, 227, 78, 232, 241, 212, 6, 218, 184, 194, 113, 171, 181, 100, 211, 100, 187, 110, 243, 167, 100, 16, 99, 198, 76, 146, 88, 57, 30, 104, 224, 234, 158, 119, 220, 78, 1, 221, 58, 223, 167, 68, 77, 155, 196, 170, 105, 147, 24, 226, 164, 199, 13, 222, 245, 155, 98, 160, 141, 43, 40, 36, 88, 236, 29, 164, 154, 106, 160, 154, 114, 38, 17, 136, 0, 4, 104, 178, 15, 154, 114, 57, 95, 102, 39, 74, 241, 44, 80, 182, 175, 159, 74, 63, 213, 167, 202, 79, 181, 128, 218, 110, 80, 126, 170, 8, 168, 115, 105, 224, 171, 252, 53, 123, 191, 137, 39, 136, 137, 167, 6, 87, 157, 9, 253, 42, 109, 70, 27, 233, 167, 54, 132, 123, 223, 94, 115, 227, 109, 180, 29, 104, 114, 49, 232, 233, 111, 143, 41, 220, 208, 68, 163, 176, 250, 246, 156, 153, 79, 56, 51, 231, 71, 143, 227, 212, 64, 213, 250, 63, 150, 164, 93, 169, 49, 90, 204, 201, 191, 169, 55, 78, 104, 37, 12, 121, 77, 217, 87, 244, 91, 133, 151, 197, 252, 232, 27, 167, 135, 166, 223, 188, 241, 122, 83, 182, 10, 181, 182, 205, 111, 156, 22, 96, 189, 76, 155, 216, 127, 101, 218, 163, 104, 117, 118, 204, 27, 57, 88, 143, 105, 94, 220, 236, 46, 215, 138, 160, 138, 147, 242, 8, 132, 79, 202, 48, 138, 84, 173, 127, 211, 93, 13, 92, 219, 46, 228, 88, 174, 212, 185, 160, 166, 173, 214, 58, 136, 128, 60, 242, 157, 142, 219, 197, 32, 213, 15, 207, 210, 182, 75, 217, 62, 106, 224, 240, 154, 50, 212, 218, 244, 91, 154, 35, 12, 224, 43, 218, 144, 174, 37, 255, 91, 87, 190, 42, 197, 189, 113, 218, 166, 101, 235, 167, 106, 86, 37, 175, 246, 180, 153, 209, 69, 162, 105, 187, 158, 119, 52, 1, 4, 234, 185, 168, 226, 212, 185, 52, 104, 165, 85, 173, 125, 11, 3, 157, 159, 19, 72, 106, 231, 87, 244, 145, 86, 172, 55, 120, 144, 218, 227, 143, 239, 255, 183, 188, 166, 12, 229, 246, 130, 220, 86, 218, 75, 209, 142, 112, 78, 194, 27, 47, 132, 126, 178, 165, 112, 158, 153, 57, 146, 180, 93, 2, 248, 214, 245, 152, 104, 160, 109, 101, 25, 106, 85, 77, 145, 55, 86, 234, 1, 77, 105, 129, 7, 2, 8, 18, 29, 159, 82, 219, 73, 169, 141, 141, 8, 218, 168, 64, 215, 146, 218, 8, 105, 116, 120, 4, 49, 170, 145, 65, 43, 182, 113, 203, 132, 24, 213, 8, 105, 203, 164, 70, 198, 175, 210, 212, 200, 240, 190, 43, 53, 62, 164, 198, 134, 106, 171, 54, 82, 182, 143, 82, 163, 131, 47, 249, 40, 53, 46, 254, 177, 186, 165, 56, 74, 141, 15, 119, 250, 142, 82, 35, 35, 53, 54, 144, 86, 172, 107, 163, 212, 40, 209, 120, 81, 106, 108, 72, 141, 143, 212, 248, 240, 154, 50, 148, 26, 23, 218, 239, 93, 27, 148, 26, 29, 172, 153, 65, 169, 83, 83, 178, 21, 74, 141, 141, 102, 153, 6, 161, 238, 114, 45, 86, 149, 201, 59, 85, 211, 149, 9, 165, 198, 135, 126, 178, 109, 137, 82, 163, 35, 53, 6, 192, 241, 183, 52, 46, 80, 178, 209, 241, 40, 94, 16, 37, 27, 25, 30, 65, 77, 39, 217, 200, 104, 197, 135, 174, 101, 43, 186, 24, 212, 186, 64, 63, 27, 33, 146, 78, 208, 103, 227, 34, 29, 207, 198, 133, 165, 233, 184, 108, 92, 56, 233, 241, 59, 190, 217, 29, 127, 238, 161, 77, 43, 123, 150, 115, 217, 77, 203, 70, 8, 164, 162, 206, 90, 203, 48, 118, 164, 253, 100, 236, 95, 1, 125, 126, 19, 42, 240, 224, 170, 153, 2, 209, 224, 145, 6, 211, 223, 7, 132, 177, 106, 217, 200, 224, 42, 170, 90, 54, 46, 84, 203, 70, 71, 54, 62, 52, 189, 116, 199, 167, 246, 34, 42, 81, 67, 42, 150, 141, 11, 169, 22, 150, 141, 12, 30, 121, 141, 165, 27, 33, 92, 37, 247, 218, 108, 140, 168, 96, 178, 81, 97, 49, 217, 168, 160, 156, 228, 139, 217, 33, 38, 27, 25, 76, 54, 42, 224, 85, 217, 8, 97, 158, 20, 212, 118, 201, 70, 71, 132, 198, 0, 52, 246, 8, 106, 116, 64, 134, 124, 101, 170, 107, 73, 5, 161, 207, 111, 66, 123, 13, 252, 38, 32, 228, 77, 192, 134, 71, 22, 191, 237, 77, 192, 133, 252, 165, 106, 130, 215, 130, 40, 214, 218, 55, 1, 23, 30, 175, 23, 146, 164, 125, 19, 176, 33, 73, 251, 14, 137, 231, 115, 167, 101, 72, 223, 131, 54, 191, 171, 147, 210, 245, 77, 64, 135, 167, 245, 77, 128, 48, 86, 136, 194, 42, 29, 71, 173, 111, 2, 62, 232, 244, 124, 19, 144, 193, 125, 2, 42, 120, 152, 245, 9, 8, 209, 55, 129, 224, 120, 232, 9, 200, 224, 145, 9, 19, 80, 161, 117, 89, 120, 77, 192, 133, 47, 28, 153, 128, 11, 145, 9, 24, 0, 94, 52, 1, 21, 22, 77, 64, 5, 19, 16, 0, 159, 94, 127, 195, 90, 234, 56, 106, 236, 252, 227, 16, 226, 171, 226, 80, 193, 215, 254, 155, 184, 127, 14, 25, 30, 65, 173, 142, 63, 135, 141, 182, 156, 126, 23, 148, 159, 202, 241, 231, 16, 194, 35, 16, 28, 127, 14, 23, 254, 232, 97, 182, 159, 67, 71, 131, 197, 222, 65, 140, 155, 65, 18, 200, 120, 215, 126, 14, 25, 250, 53, 210, 126, 14, 27, 206, 175, 212, 119, 148, 253, 21, 125, 64, 155, 19, 114, 192, 70, 186, 231, 80, 65, 21, 167, 167, 61, 135, 12, 10, 171, 182, 148, 135, 174, 37, 29, 127, 14, 173, 245, 26, 75, 39, 186, 90, 25, 85, 142, 207, 132, 214, 122, 14, 25, 41, 121, 14, 21, 36, 43, 41, 110, 251, 29, 53, 207, 109, 46, 8, 135, 74, 126, 70, 171, 164, 237, 66, 205, 115, 232, 240, 71, 115, 183, 54, 109, 154, 231, 16, 226, 253, 159, 168, 121, 14, 27, 205, 115, 168, 192, 35, 8, 27, 203, 107, 203, 115, 8, 121, 215, 71, 74, 29, 39, 111, 175, 1, 183, 141, 180, 107, 121, 14, 29, 30, 166, 13, 65, 181, 223, 29, 62, 92, 178, 134, 174, 76, 188, 16, 162, 218, 143, 220, 29, 46, 222, 119, 33, 119, 184, 232, 118, 168, 64, 123, 223, 4, 71, 211, 22, 98, 210, 28, 26, 218, 166, 147, 30, 79, 191, 54, 4, 207, 142, 55, 213, 78, 174, 0, 20, 129, 0, 42, 201, 197, 64, 160, 3, 222, 104, 224, 190, 56, 45, 224, 17, 230, 45, 252, 252, 220, 14, 29, 20, 221, 9, 132, 239, 106, 224, 96, 169, 226, 8, 151, 236, 81, 201, 122, 253, 207, 181, 125, 154, 223, 215, 153, 200, 102, 65, 179, 247, 75, 142, 91, 49, 112, 213, 146, 49, 138, 37, 215, 226, 132, 154, 187, 151, 169, 75, 56, 110, 231, 156, 29, 183, 195, 69, 187, 138, 54, 120, 243, 35, 17, 129, 240, 1, 53, 109, 41, 244, 179, 73, 199, 237, 16, 4, 58, 84, 103, 5, 195, 223, 61, 203, 37, 122, 247, 142, 113, 59, 100, 120, 152, 93, 43, 19, 122, 152, 117, 120, 90, 162, 135, 89, 103, 193, 139, 84, 231, 162, 36, 41, 23, 8, 16, 30, 64, 112, 60, 29, 8, 234, 251, 180, 132, 160, 190, 136, 127, 226, 31, 43, 219, 95, 255, 234, 43, 247, 37, 158, 254, 167, 95, 123, 129, 175, 210, 126, 250, 38, 52, 232, 100, 189, 95, 210, 70, 238, 184, 93, 243, 191, 164, 21, 69, 139, 23, 60, 204, 170, 226, 38, 241, 78, 179, 139, 105, 235, 164, 84, 136, 66, 234, 203, 218, 166, 227, 224, 146, 148, 75, 196, 90, 153, 36, 90, 37, 169, 189, 60, 232, 231, 66, 107, 37, 106, 128, 11, 255, 124, 71, 169, 65, 254, 212, 121, 101, 220, 14, 39, 24, 183, 195, 71, 211, 8, 183, 67, 6, 101, 217, 208, 39, 141, 112, 187, 135, 206, 5, 49, 176, 32, 77, 79, 113, 59, 124, 112, 208, 24, 194, 155, 78, 36, 73, 251, 21, 109, 20, 254, 190, 21, 135, 9, 92, 209, 3, 23, 13, 47, 148, 184, 29, 50, 158, 23, 110, 135, 12, 171, 129, 160, 11, 183, 67, 134, 126, 78, 22, 30, 249, 148, 218, 57, 201, 8, 74, 251, 192, 88, 161, 180, 143, 100, 234, 36, 71, 18, 204, 183, 29, 66, 60, 162, 79, 223, 132, 231, 183, 121, 219, 225, 67, 132, 193, 41, 116, 45, 217, 240, 117, 30, 125, 219, 102, 124, 74, 237, 166, 45, 188, 113, 90, 71, 69, 23, 163, 108, 219, 97, 131, 59, 37, 131, 176, 114, 162, 21, 235, 142, 93, 233, 33, 73, 251, 38, 56, 67, 143, 178, 253, 118, 26, 154, 187, 53, 63, 213, 163, 194, 203, 243, 240, 64, 42, 13, 137, 8, 253, 165, 19, 103, 224, 21, 219, 178, 105, 30, 64, 78, 50, 210, 236, 136, 129, 138, 186, 164, 248, 182, 203, 245, 65, 117, 170, 150, 239, 168, 89, 166, 177, 3, 73, 82, 39, 185, 254, 179, 160, 214, 253, 215, 118, 232, 240, 77, 93, 219, 225, 66, 21, 55, 109, 135, 14, 72, 53, 117, 218, 14, 33, 42, 121, 105, 59, 100, 176, 232, 192, 28, 82, 218, 8, 209, 118, 237, 144, 225, 83, 219, 164, 237, 144, 225, 52, 105, 59, 116, 80, 8, 225, 30, 119, 131, 90, 246, 55, 248, 138, 126, 115, 104, 248, 148, 218, 14, 25, 28, 127, 14, 105, 59, 100, 120, 164, 105, 83, 121, 231, 176, 241, 116, 246, 178, 171, 223, 57, 164, 96, 184, 157, 195, 5, 95, 170, 152, 237, 226, 160, 107, 25, 150, 221, 228, 42, 7, 26, 251, 170, 231, 34, 0, 6, 43, 61, 81, 15, 224, 43, 15, 104, 115, 66, 15, 218, 180, 50, 9, 20, 123, 52, 104, 236, 17, 136, 106, 203, 56, 233, 149, 105, 112, 208, 134, 120, 227, 253, 164, 19, 250, 185, 22, 63, 248, 218, 127, 11, 214, 4, 95, 148, 130, 84, 113, 99, 128, 1, 106, 125, 151, 170, 1, 151, 108, 129, 69, 57, 233, 177, 195, 133, 166, 236, 103, 135, 11, 73, 74, 247, 236, 112, 161, 203, 118, 114, 73, 39, 123, 103, 205, 12, 111, 75, 166, 214, 190, 229, 157, 221, 98, 239, 44, 88, 236, 29, 212, 176, 227, 17, 212, 176, 227, 72, 253, 103, 209, 110, 180, 155, 119, 199, 101, 55, 144, 138, 170, 182, 21, 107, 45, 101, 162, 45, 155, 172, 156, 80, 172, 126, 149, 252, 246, 56, 112, 51, 105, 218, 126, 179, 63, 124, 39, 243, 206, 9, 210, 229, 216, 62, 123, 186, 50, 233, 19, 235, 219, 31, 164, 167, 180, 153, 54, 127, 197, 61, 72, 218, 46, 244, 180, 68, 238, 185, 18, 98, 245, 212, 221, 211, 96, 210, 20, 189, 186, 118, 101, 25, 109, 215, 64, 83, 46, 199, 64, 146, 218, 11, 210, 38, 157, 106, 233, 124, 179, 211, 58, 225, 5, 24, 60, 191, 41, 29, 55, 176, 250, 45, 80, 197, 105, 219, 243, 166, 45, 219, 47, 0, 3, 79, 46, 231, 171, 144, 86, 108, 123, 32, 213, 218, 79, 237, 113, 138, 149, 137, 215, 0, 92, 0, 44, 59, 221, 2, 7, 141, 25, 164, 235, 117, 58, 77, 227, 245, 77, 213, 58, 168, 228, 228, 53, 177, 228, 242, 136, 163, 153, 180, 237, 102, 183, 192, 171, 167, 85, 150, 205, 60, 42, 65, 238, 105, 25, 44, 246, 78, 46, 77, 87, 212, 121, 240, 86, 183, 212, 201, 134, 65, 51, 179, 15, 49, 125, 127, 28, 125, 115, 160, 173, 243, 75, 161, 208, 181, 172, 239, 4, 249, 75, 204, 84, 150, 65, 222, 188, 165, 162, 203, 25, 232, 122, 141, 84, 211, 175, 56, 76, 154, 62, 158, 58, 225, 8, 233, 90, 30, 19, 64, 169, 191, 246, 84, 61, 239, 152, 126, 166, 93, 238, 169, 5, 28, 168, 206, 228, 171, 246, 65, 174, 82, 134, 24, 191, 63, 10, 118, 79, 8, 242, 21, 109, 238, 9, 185, 167, 5, 173, 147, 198, 160, 45, 131, 88, 154, 214, 229, 250, 185, 76, 73, 23, 109, 6, 20, 179, 5, 22, 202, 242, 136, 116, 220, 74, 84, 81, 167, 193, 147, 221, 160, 230, 197, 105, 87, 122, 56, 96, 186, 72, 60, 115, 191, 191, 186, 59, 60, 203, 185, 134, 212, 114, 162, 18, 45, 224, 158, 222, 121, 229, 59, 59, 124, 104, 218, 54, 222, 95, 103, 167, 206, 14, 27, 206, 14, 21, 180, 182, 150, 233, 225, 223, 236, 112, 161, 85, 181, 101, 190, 217, 161, 67, 223, 4, 173, 252, 102, 101, 144, 67, 7, 165, 254, 208, 55, 59, 108, 180, 250, 155, 104, 167, 130, 24, 60, 60, 253, 218, 14, 20, 77, 91, 197, 15, 116, 165, 117, 199, 14, 25, 173, 203, 172, 98, 134, 180, 98, 29, 85, 146, 161, 86, 231, 216, 161, 3, 117, 118, 104, 159, 153, 99, 135, 13, 101, 167, 142, 255, 89, 236, 144, 1, 91, 199, 159, 197, 14, 25, 174, 109, 215, 47, 67, 56, 209, 180, 117, 110, 87, 66, 8, 161, 212, 241, 93, 236, 144, 161, 107, 25, 116, 180, 82, 116, 39, 136, 225, 198, 205, 66, 56, 124, 91, 118, 216, 160, 107, 25, 118, 200, 16, 137, 192, 206, 53, 135, 18, 109, 23, 132, 144, 101, 87, 5, 55, 200, 195, 35, 77, 115, 184, 208, 28, 6, 160, 194, 28, 42, 248, 109, 204, 252, 113, 20, 129, 41, 139, 192, 28, 58, 232, 231, 115, 55, 188, 80, 4, 230, 176, 33, 2, 115, 232, 104, 92, 73, 20, 129, 57, 100, 96, 163, 225, 229, 104, 238, 86, 132, 56, 94, 14, 21, 222, 119, 57, 92, 104, 173, 232, 114, 200, 80, 97, 70, 123, 25, 9, 109, 126, 96, 111, 25, 183, 147, 208, 4, 58, 24, 115, 63, 185, 28, 50, 154, 189, 111, 185, 28, 66, 104, 219, 245, 44, 118, 136, 31, 117, 182, 92, 14, 29, 168, 205, 229, 154, 114, 57, 108, 120, 100, 37, 14, 23, 152, 105, 219, 72, 28, 46, 220, 67, 141, 196, 33, 67, 35, 113, 216, 104, 214, 193, 52, 78, 168, 145, 56, 100, 72, 192, 147, 196, 225, 130, 71, 32, 128, 192, 147, 196, 33, 131, 105, 87, 214, 33, 131, 71, 32, 236, 194, 249, 101, 206, 48, 171, 208, 210, 202, 58, 116, 100, 219, 228, 235, 112, 225, 250, 217, 235, 112, 209, 79, 255, 213, 173, 195, 6, 47, 82, 183, 14, 23, 239, 109, 29, 46, 184, 122, 167, 216, 95, 143, 69, 184, 127, 167, 145, 42, 23, 167, 199, 55, 187, 79, 217, 239, 75, 34, 110, 235, 176, 1, 183, 117, 168, 224, 160, 43, 105, 235, 144, 33, 183, 173, 195, 133, 166, 173, 67, 5, 143, 48, 91, 209, 117, 200, 208, 38, 253, 169, 117, 200, 80, 237, 87, 235, 112, 177, 214, 50, 218, 239, 211, 58, 198, 105, 29, 54, 56, 173, 67, 199, 179, 32, 73, 90, 135, 13, 153, 214, 161, 130, 227, 208, 209, 250, 159, 10, 57, 199, 161, 68, 179, 227, 156, 29, 135, 14, 218, 216, 113, 184, 80, 217, 166, 236, 56, 92, 252, 218, 183, 104, 59, 36, 225, 17, 198, 223, 210, 113, 216, 112, 79, 215, 56, 100, 112, 141, 195, 70, 132, 53, 193, 81, 227, 112, 177, 56, 53, 14, 29, 168, 113, 8, 209, 56, 116, 160, 198, 97, 3, 53, 14, 27, 19, 248, 182, 168, 113, 184, 104, 28, 54, 28, 54, 220, 67, 227, 144, 162, 113, 24, 128, 10, 117, 168, 64, 210, 178, 33, 158, 223, 78, 247, 79, 63, 23, 163, 10, 73, 164, 117, 156, 124, 35, 16, 148, 61, 10, 55, 164, 169, 37, 107, 102, 90, 29, 62, 116, 46, 17, 170, 165, 163, 218, 12, 250, 164, 16, 46, 97, 118, 42, 224, 146, 78, 134, 152, 86, 135, 142, 39, 181, 58, 92, 240, 136, 83, 135, 11, 234, 143, 157, 111, 234, 176, 209, 218, 154, 58, 100, 80, 77, 29, 42, 48, 117, 168, 192, 35, 141, 58, 92, 80, 139, 90, 213, 225, 66, 213, 225, 131, 81, 14, 27, 239, 171, 144, 195, 35, 140, 114, 184, 240, 158, 140, 114, 200, 176, 236, 66, 140, 114, 184, 248, 228, 208, 193, 88, 161, 8, 183, 171, 44, 14, 31, 223, 16, 129, 81, 146, 197, 33, 131, 68, 57, 122, 215, 70, 43, 221, 147, 238, 73, 135, 11, 127, 233, 16, 178, 114, 226, 188, 51, 17, 156, 79, 135, 11, 30, 129, 176, 240, 106, 16, 63, 133, 166, 126, 236, 21, 110, 71, 101, 157, 27, 218, 121, 70, 246, 87, 84, 89, 182, 175, 40, 90, 160, 158, 169, 225, 124, 58, 116, 56, 159, 14, 21, 156, 244, 233, 176, 65, 53, 83, 30, 122, 156, 144, 123, 58, 156, 104, 253, 95, 202, 67, 52, 149, 240, 63, 141, 126, 246, 187, 0, 34, 172, 76, 188, 28, 156, 127, 233, 82, 173, 167, 68, 58, 117, 65, 238, 223, 161, 136, 64, 131, 8, 16, 48, 112, 254, 37, 47, 136, 0, 33, 97, 94, 52, 37, 19, 193, 248, 253, 37, 132, 15, 234, 153, 86, 38, 95, 153, 60, 29, 62, 60, 242, 232, 98, 108, 27, 107, 251, 49, 150, 93, 45, 89, 204, 143, 186, 245, 63, 25, 234, 9, 139, 71, 23, 163, 177, 71, 220, 249, 165, 32, 9, 210, 145, 4, 17, 170, 253, 40, 130, 0, 154, 182, 13, 72, 192, 208, 169, 207, 111, 123, 218, 205, 159, 246, 243, 41, 94, 61, 117, 235, 187, 84, 137, 156, 65, 13, 188, 105, 14, 69, 113, 79, 167, 44, 27, 106, 236, 17, 6, 202, 178, 161, 180, 173, 236, 53, 103, 140, 136, 182, 159, 235, 81, 73, 163, 177, 71, 190, 53, 32, 110, 169, 179, 240, 114, 172, 126, 104, 121, 206, 234, 135, 216, 105, 47, 80, 150, 13, 173, 245, 152, 7, 7, 199, 119, 53, 77, 29, 218, 38, 99, 197, 48, 235, 216, 126, 40, 63, 149, 67, 218, 197, 52, 110, 94, 143, 175, 168, 226, 180, 88, 5, 98, 226, 27, 51, 108, 145, 104, 118, 254, 65, 176, 193, 23, 190, 174, 206, 227, 155, 58, 252, 34, 151, 234, 153, 16, 243, 136, 3, 2, 37, 86, 65, 189, 211, 165, 75, 135, 141, 215, 180, 116, 184, 192, 146, 116, 168, 240, 63, 129, 33, 118, 26, 205, 159, 232, 160, 154, 182, 218, 164, 195, 6, 135, 142, 119, 154, 109, 164, 210, 97, 67, 165, 67, 5, 234, 17, 180, 250, 65, 120, 152, 109, 224, 124, 70, 56, 158, 14, 130, 224, 194, 35, 72, 83, 58, 92, 164, 116, 8, 73, 233, 240, 65, 43, 9, 49, 177, 9, 61, 16, 64, 144, 14, 25, 107, 37, 211, 250, 73, 65, 14, 31, 205, 12, 250, 77, 10, 114, 232, 120, 250, 145, 195, 5, 214, 204, 224, 163, 31, 200, 161, 67, 25, 251, 107, 35, 135, 11, 135, 11, 135, 11, 117, 235, 144, 67, 6, 151, 12, 57, 135, 11, 79, 69, 46, 228, 144, 225, 23, 57, 228, 16, 242, 172, 149, 109, 25, 228, 176, 193, 204, 50, 200, 33, 195, 211, 14, 23, 174, 219, 234, 200, 73, 169, 200, 97, 67, 43, 163, 10, 57, 92, 32, 183, 52, 181, 76, 200, 165, 246, 120, 34, 135, 13, 79, 75, 228, 112, 1, 33, 90, 39, 140, 10, 169, 61, 142, 158, 251, 199, 8, 209, 250, 228, 250, 199, 200, 248, 166, 234, 31, 227, 226, 253, 49, 42, 56, 233, 49, 42, 44, 187, 220, 51, 50, 84, 156, 241, 225, 124, 58, 103, 100, 112, 217, 156, 113, 129, 113, 161, 206, 216, 120, 214, 178, 100, 144, 51, 54, 156, 49, 0, 43, 219, 54, 219, 140, 140, 138, 54, 218, 168, 105, 198, 198, 202, 182, 170, 25, 23, 158, 218, 238, 184, 221, 2, 164, 180, 85, 53, 35, 69, 182, 178, 76, 232, 119, 105, 198, 6, 139, 210, 149, 178, 25, 25, 217, 140, 10, 252, 29, 163, 130, 71, 208, 74, 8, 50, 20, 128, 57, 50, 90, 223, 49, 46, 60, 238, 28, 227, 66, 235, 246, 107, 71, 172, 126, 30, 129, 160, 238, 249, 71, 211, 54, 101, 191, 132, 31, 33, 9, 255, 3, 9, 191, 187, 107, 92, 83, 199, 184, 80, 171, 182, 169, 99, 100, 208, 201, 54, 117, 140, 14, 254, 72, 194, 67, 59, 41, 205, 13, 52, 109, 84, 113, 66, 11, 184, 186, 231, 215, 4, 126, 180, 46, 251, 249, 237, 151, 212, 129, 39, 83, 39, 57, 104, 188, 203, 177, 244, 135, 5, 30, 180, 166, 86, 78, 168, 193, 174, 132, 180, 105, 101, 218, 180, 178, 134, 198, 30, 113, 64, 210, 76, 81, 150, 205, 68, 48, 204, 66, 90, 255, 213, 17, 3, 124, 104, 234, 24, 37, 154, 58, 70, 133, 149, 142, 17, 162, 218, 143, 118, 147, 39, 98, 198, 134, 125, 77, 189, 49, 46, 184, 49, 42, 248, 246, 152, 53, 198, 197, 106, 140, 142, 103, 53, 70, 5, 101, 251, 109, 151, 54, 198, 133, 178, 125, 164, 141, 145, 161, 141, 25, 29, 141, 145, 161, 169, 49, 42, 52, 125, 223, 133, 94, 27, 106, 140, 13, 141, 209, 161, 218, 12, 146, 164, 46, 244, 91, 81, 212, 24, 35, 60, 2, 225, 151, 49, 46, 158, 119, 76, 29, 142, 167, 226, 133, 32, 156, 170, 66, 191, 140, 177, 193, 108, 211, 48, 70, 6, 253, 215, 165, 140, 145, 81, 225, 197, 37, 67, 139, 241, 97, 49, 6, 32, 169, 101, 124, 56, 233, 149, 121, 152, 195, 216, 96, 160, 205, 9, 165, 237, 37, 25, 180, 111, 129, 82, 137, 52, 45, 195, 48, 66, 180, 190, 50, 86, 140, 140, 167, 245, 77, 120, 124, 42, 70, 136, 163, 198, 187, 192, 175, 132, 63, 49, 46, 86, 126, 98, 92, 96, 118, 37, 198, 133, 196, 232, 96, 222, 194, 168, 224, 141, 65, 232, 160, 188, 48, 42, 76, 60, 33, 126, 228, 14, 79, 118, 103, 51, 111, 163, 161, 81, 216, 211, 241, 102, 213, 40, 252, 218, 12, 128, 113, 51, 18, 13, 20, 2, 132, 95, 95, 136, 86, 168, 54, 211, 222, 195, 195, 172, 106, 191, 55, 157, 136, 159, 130, 97, 173, 88, 247, 71, 37, 14, 46, 25, 122, 126, 194, 241, 116, 34, 24, 52, 40, 125, 120, 220, 3, 33, 220, 113, 59, 20, 89, 24, 27, 234, 153, 80, 100, 97, 100, 64, 176, 48, 42, 208, 138, 109, 142, 240, 112, 254, 37, 227, 130, 100, 37, 5, 121, 50, 70, 180, 78, 60, 25, 33, 158, 140, 13, 158, 140, 142, 198, 43, 65, 158, 140, 14, 158, 140, 10, 38, 77, 39, 227, 66, 122, 26, 42, 168, 52, 12, 192, 186, 116, 74, 67, 134, 166, 104, 211, 175, 65, 67, 155, 0, 4, 139, 190, 242, 26, 54, 190, 242, 26, 42, 172, 108, 101, 175, 225, 130, 123, 97, 175, 33, 131, 82, 70, 91, 16, 127, 67, 136, 83, 184, 157, 127, 172, 245, 26, 58, 82, 242, 26, 54, 44, 175, 161, 130, 38, 41, 222, 112, 193, 27, 50, 156, 55, 84, 160, 157, 43, 169, 242, 134, 141, 158, 208, 80, 129, 187, 134, 141, 134, 13, 92, 56, 105, 29, 10, 98, 110, 173, 68, 237, 245, 163, 189, 118, 231, 211, 53, 156, 79, 247, 109, 145, 106, 63, 90, 201, 92, 67, 8, 230, 26, 62, 188, 85, 153, 107, 56, 225, 141, 247, 95, 106, 102, 16, 115, 13, 23, 48, 141, 25, 109, 27, 94, 104, 87, 131, 235, 167, 114, 15, 69, 48, 215, 176, 241, 171, 94, 34, 230, 152, 107, 184, 96, 174, 161, 2, 215, 48, 0, 173, 159, 11, 169, 150, 136, 194, 13, 27, 208, 241, 60, 55, 84, 112, 159, 239, 251, 220, 176, 193, 11, 65, 146, 210, 233, 115, 195, 7, 50, 60, 2, 193, 169, 46, 231, 134, 14, 95, 116, 195, 61, 65, 88, 170, 14, 165, 153, 36, 119, 120, 70, 23, 122, 104, 36, 14, 27, 30, 102, 223, 113, 195, 133, 54, 233, 15, 189, 227, 134, 142, 9, 34, 56, 230, 134, 11, 143, 198, 32, 167, 43, 97, 110, 184, 112, 198, 13, 21, 24, 55, 198, 13, 25, 184, 33, 227, 91, 123, 104, 204, 26, 133, 155, 100, 45, 165, 80, 44, 239, 31, 44, 102, 135, 220, 51, 165, 157, 142, 127, 179, 83, 119, 160, 182, 27, 213, 212, 29, 104, 224, 155, 29, 3, 173, 107, 147, 57, 41, 117, 151, 42, 110, 248, 96, 81, 10, 242, 8, 68, 46, 186, 145, 223, 102, 65, 225, 197, 64, 104, 250, 21, 133, 224, 84, 37, 204, 21, 110, 43, 24, 139, 229, 163, 191, 11, 45, 86, 105, 168, 248, 170, 44, 102, 135, 92, 165, 182, 243, 168, 85, 210, 236, 32, 130, 9, 42, 168, 45, 229, 181, 161, 180, 236, 101, 17, 197, 123, 17, 32, 157, 24, 125, 202, 86, 119, 253, 117, 137, 158, 23, 196, 178, 27, 93, 250, 11, 156, 244, 202, 180, 186, 231, 182, 2, 185, 42, 78, 40, 194, 159, 242, 207, 127, 56, 238, 146, 148, 203, 1, 65, 58, 173, 72, 213, 218, 119, 128, 220, 211, 221, 211, 27, 233, 17, 8, 127, 22, 212, 96, 130, 182, 63, 171, 58, 121, 113, 60, 149, 68, 91, 166, 18, 41, 109, 135, 148, 48, 41, 81, 253, 188, 99, 60, 175, 230, 89, 236, 26, 167, 138, 29, 8, 156, 127, 201, 77, 91, 255, 108, 19, 146, 196, 78, 250, 215, 200, 90, 136, 90, 164, 109, 157, 148, 236, 65, 178, 222, 130, 158, 213, 52, 188, 34, 152, 160, 130, 42, 175, 237, 114, 80, 231, 72, 114, 140, 8, 38, 248, 182, 202, 64, 211, 78, 84, 109, 4, 247, 239, 56, 212, 58, 110, 43, 26, 238, 105, 32, 76, 5, 227, 139, 167, 95, 59, 130, 227, 164, 87, 198, 241, 233, 42, 254, 176, 114, 162, 222, 228, 98, 24, 232, 90, 6, 77, 154, 62, 203, 105, 163, 181, 201, 20, 169, 226, 230, 52, 85, 148, 69, 40, 255, 124, 111, 216, 161, 55, 251, 93, 18, 89, 213, 48, 81, 213, 13, 197, 146, 67, 226, 1, 167, 13, 168, 228, 138, 136, 3, 132, 68, 242, 76, 162, 70, 73, 142, 41, 197, 148, 162, 162, 218, 0, 51, 18, 200, 97, 35, 113, 56, 26, 11, 3, 73, 22, 237, 1, 20, 128, 2, 11, 10, 197, 57, 237, 74, 18, 131, 36, 133, 138, 4, 4, 32, 3, 32, 1, 160, 0, 202, 5, 25, 88, 80, 108, 229, 116, 212, 199, 83, 154, 70, 218, 47, 23, 43, 66, 24, 212, 49, 246, 133, 246, 114, 219, 107, 207, 51, 13, 240, 61, 228, 153, 1, 201, 127, 238, 54, 60, 224, 38, 190, 105, 108, 181, 160, 198, 73, 159, 69, 4, 184, 13, 22, 57, 183, 4, 88, 110, 186, 46, 161, 202, 138, 254, 93, 79, 10, 7, 232, 252, 70, 80, 41, 74, 232, 241, 175, 54, 129, 81, 18, 103, 140, 64, 127, 208, 134, 126, 79, 65, 178, 6, 37, 173, 21, 60, 246, 46, 57, 234, 16, 109, 117, 139, 26, 251, 201, 9, 76, 180, 223, 14, 158, 143, 253, 103, 209, 7, 81, 21, 74, 161, 112, 245, 40, 202, 206, 142, 201, 43, 183, 186, 247, 75, 203, 227, 214, 192, 173, 26, 16, 118, 125, 130, 107, 130, 20, 210, 59, 137, 204, 5, 134, 71, 170, 34, 28, 77, 187, 65, 134, 153, 221, 102, 22, 137, 19, 146, 89, 121, 160, 123, 167, 193, 172, 104, 92, 112, 141, 195, 191, 248, 131, 125, 114, 117, 97, 15, 10, 79, 84, 50, 156, 242, 96, 129, 63, 17, 224, 192, 61, 90, 16, 74, 207, 236, 187, 120, 3, 89, 243, 53, 36, 135, 46, 160, 156, 126, 167, 238, 51, 156, 104, 60, 170, 181, 187, 24, 28, 99, 112, 9, 69, 163, 207, 157, 149, 60, 15, 177, 126, 109, 103, 59, 22, 163, 85, 122, 34, 169, 85, 146, 246, 67, 135, 73, 2, 13, 28, 166, 225, 80, 19, 172, 193, 210, 143, 66, 250, 129, 197, 103, 45, 249, 137, 180, 225, 3, 152, 208, 23, 7, 94, 198, 29, 226, 233, 10, 128, 67, 233, 213, 88, 106, 214, 76, 124, 235, 88, 80, 66, 124, 175, 72, 184, 233, 113, 232, 161, 22, 166, 134, 14, 92, 19, 152, 227, 22, 37, 49, 139, 110, 207, 254, 74, 86, 195, 129, 49, 58, 106, 71, 67, 137, 213, 67, 168, 111, 132, 253, 62, 134, 220, 185, 86, 83, 76, 215, 64, 164, 171, 42, 10, 217, 20, 211, 129, 219, 133, 126, 63, 37, 216, 182, 5, 184, 214, 178, 138, 69, 61, 180, 112, 181, 248, 172, 153, 181, 66, 159, 193, 83, 250, 231, 17, 80, 138, 142, 161, 163, 200, 220, 62, 178, 111, 182, 188, 43, 208, 174, 87, 60, 136, 95, 236, 46, 37, 2, 153, 30, 49, 107, 33, 69, 182, 88, 138, 67, 125, 179, 61, 23, 126, 27, 246, 111, 181, 94, 31, 241, 173, 1, 245, 32, 177, 247, 218, 85, 17, 6, 15, 158, 121, 150, 149, 55, 134, 141, 26, 93, 32, 101, 97, 62, 148, 237, 148, 191, 204, 8, 79, 6, 45, 246, 134, 59, 78, 188, 81, 109, 30, 102, 185, 92, 26, 31, 100, 85, 33, 89, 183, 64, 40, 72, 159, 102, 187, 225, 197, 209, 137, 183, 207, 71, 196, 252, 18, 8, 181, 171, 62, 2, 230, 27, 49, 241, 129, 160, 217, 204, 236, 134, 131, 184, 141, 132, 58, 34, 132, 5, 153, 234, 166, 4, 95, 196, 151, 115, 221, 72, 80, 4, 100, 212, 127, 158, 47, 26, 48, 129, 232, 9, 237, 71, 2, 139, 56, 0, 198, 96, 194, 110, 99, 56, 209, 203, 16, 178, 201, 192, 203, 206, 54, 199, 254, 135, 43, 83, 153, 187, 135, 218, 167, 74, 8, 214, 95, 44, 163, 211, 150, 81, 32, 238, 28, 240, 177, 82, 154, 0, 243, 129, 85, 224, 157, 187, 187, 216, 7, 197, 95, 21, 29, 92, 126, 75, 82, 65, 114, 98, 241, 2, 110, 25, 12, 137, 96, 156, 174, 102, 155, 41, 170, 190, 97, 59, 239, 0, 225, 22, 9, 32, 235, 26, 146, 190, 35, 45, 113, 0, 94, 132, 34, 170, 175, 22, 24, 136, 202, 193, 17, 93, 157, 170, 209, 233, 71, 153, 209, 45, 6, 217, 116, 35, 162, 52, 42, 232, 179, 232, 32, 47, 36, 227, 159, 99, 113, 95, 118, 159, 216, 203, 141, 136, 179, 248, 111, 187, 69, 198, 104, 127, 228, 217, 83, 14, 164, 121, 190, 182, 191, 114, 70, 71, 236, 180, 244, 240, 239, 87, 235, 243, 38, 163, 91, 216, 182, 157, 207, 79, 63, 27, 87, 133, 95, 64, 113, 150, 70, 195, 180, 117, 236, 242, 187, 74, 27, 236, 165, 241, 124, 175, 221, 214, 115, 133, 249, 148, 67, 4, 174, 218, 7, 207, 142, 13, 67, 43, 100, 48, 136, 206, 127, 23, 137, 1, 133, 165, 77, 75, 153, 102, 71, 127, 208, 78, 30, 248, 61, 23, 51, 235, 173, 25, 38, 129, 160, 178, 48, 249, 75, 175, 134, 45, 245, 200, 11, 218, 89, 243, 248, 86, 198, 99, 69, 122, 244, 41, 148, 71, 143, 210, 25, 68, 135, 149, 44, 48, 195, 90, 26, 65, 158, 226, 40, 56, 143, 59, 250, 64, 38, 79, 59, 93, 218, 84, 183, 57, 93, 243, 176, 187, 163, 8, 144, 147, 106, 112, 171, 37, 129, 151, 85, 49, 140, 95, 28, 185, 160, 118, 174, 241, 179, 238, 12, 84, 33, 135, 17, 187, 168, 197, 234, 35, 12, 133, 224, 157, 60, 237, 115, 84, 62, 162, 91, 157, 130, 71, 129, 122, 179, 72, 208, 176, 247, 77, 115, 169, 71, 37, 243, 26, 250, 178, 50, 106, 193, 219, 159, 80, 35, 88, 19, 137, 20, 18, 230, 78, 219, 10, 127, 197, 51, 127, 132, 30, 33, 13, 210, 194, 71, 231, 181, 118, 137, 136, 86, 252, 183, 57, 26, 108, 95, 140, 120, 1, 70, 232, 242, 26, 105, 70, 34, 65, 40, 210, 111, 74, 188, 210, 225, 81, 222, 64, 240, 126, 148, 147, 198, 11, 254, 49, 42, 14, 80, 226, 24, 33, 114, 33, 26, 130, 8, 29, 133, 98, 83, 183, 148, 90, 156, 121, 98, 182, 172, 147, 66, 126, 76, 56, 39, 181, 102, 227, 163, 225, 127, 164, 118, 233, 53, 202, 183, 252, 122, 77, 85, 179, 252, 24, 202, 28, 64, 64, 162, 244, 117, 202, 57, 181, 104, 17, 247, 167, 91, 240, 188, 26, 27, 109, 37, 113, 54, 205, 48, 83, 146, 89, 82, 244, 46, 244, 56, 133, 52, 246, 226, 28, 72, 57, 213, 180, 6, 232, 196, 27, 146, 252, 144, 215, 87, 149, 15, 31, 182, 155, 81, 96, 173, 162, 16, 207, 103, 152, 83, 8, 233, 188, 92, 117, 180, 129, 158, 136, 65, 111, 196, 11, 80, 8, 217, 142, 33, 244, 123, 234, 131, 226, 153, 34, 201, 99, 86, 101, 73, 219, 41, 171, 82, 110, 30, 24, 80, 218, 161, 57, 118, 132, 254, 161, 205, 70, 139, 114, 145, 181, 138, 36, 166, 229, 216, 124, 113, 67, 139, 139, 42, 210, 34, 28, 19, 83, 60, 115, 97, 48, 152, 99, 213, 85, 59, 66, 54, 146, 189, 194, 100, 65, 112, 186, 5, 45, 119, 128, 213, 130, 141, 187, 211, 80, 175, 146, 192, 168, 137, 11, 83, 90, 85, 97, 156, 129, 116, 247, 246, 62, 67, 246, 149, 75, 183, 134, 114, 209, 200, 156, 85, 27, 196, 163, 250, 151, 177, 75, 204, 11, 133, 187, 48, 183, 244, 239, 178, 85, 91, 207, 160, 35, 185, 112, 156, 174, 113, 139, 215, 50, 175, 84, 58, 145, 185, 31, 70, 1, 242, 22, 7, 232, 63, 31, 208, 117, 3, 231, 100, 131, 120, 64, 108, 184, 216, 120, 76, 153, 248, 0, 140, 4, 81, 23, 178, 109, 89, 188, 128, 104, 182, 190, 237, 240, 63, 102, 247, 62, 0, 77, 100, 61, 72, 130, 145, 111, 222, 236, 16, 105, 203, 133, 160, 255, 96, 45, 113, 170, 201, 43, 31, 229, 26, 148, 168, 201, 251, 176, 247, 164, 178, 181, 245, 152, 62, 37, 14, 156, 99, 234, 30, 136, 232, 249, 179, 51, 67, 140, 150, 134, 21, 156, 120, 201, 89, 141, 254, 62, 105, 243, 216, 231, 225, 190, 14, 40, 198, 229, 47, 100, 217, 228, 239, 142, 211, 234, 235, 199, 110, 76, 154, 105, 132, 76, 35, 180, 162, 147, 151, 203, 238, 50, 61, 97, 249, 205, 87, 217, 39, 42, 148, 88, 155, 6, 52, 248, 130, 238, 214, 57, 24, 127, 153, 16, 233, 94, 172, 42, 232, 209, 2, 172, 201, 181, 110, 11, 208, 108, 72, 150, 122, 13, 55, 95, 179, 245, 154, 250, 196, 59, 101, 67, 236, 179, 214, 62, 110, 80, 55, 7, 94, 8, 65, 200, 140, 180, 189, 17, 25, 80, 74, 177, 183, 142, 51, 171, 61, 236, 108, 124, 193, 137, 74, 41, 252, 255, 224, 0, 143, 238, 14, 143, 62, 124, 16, 185, 20, 22, 119, 13, 61, 4, 18, 245, 123, 141, 197, 35, 224, 233, 132, 38, 64, 50, 254, 201, 114, 99, 174, 35, 173, 227, 238, 158, 66, 161, 113, 222, 159, 0, 164, 69, 27, 136, 28, 142, 204, 215, 137, 32, 115, 54, 66, 41, 62, 108, 200, 15, 221, 73, 229, 119, 83, 27, 238, 110, 251, 107, 6, 112, 156, 22, 0, 164, 239, 236, 148, 88, 1, 125, 246, 48, 156, 103, 16, 97, 88, 221, 93, 133, 133, 204, 50, 191, 86, 234, 111, 172, 110, 55, 53, 56, 154, 29, 150, 175, 174, 200, 142, 104, 85, 246, 208, 238, 46, 210, 55, 118, 49, 188, 243, 131, 90, 252, 120, 156, 234, 136, 0, 49, 22, 193, 107, 106, 226, 169, 246, 33, 74, 182, 200, 25, 223, 69, 142, 221, 148, 177, 144, 17, 171, 49, 158, 220, 255, 66, 156, 252, 56, 41, 64, 40, 156, 75, 84, 67, 50, 226, 97, 246, 189, 4, 133, 173, 21, 26, 240, 155, 19, 48, 56, 93, 82, 133, 233, 49, 86, 82, 73, 3, 30, 108, 163, 177, 173, 195, 106, 124, 149, 249, 75, 107, 107, 144, 43, 91, 205, 78, 102, 156, 58, 167, 78, 246, 233, 68, 79, 152, 254, 129, 203, 232, 139, 227, 59, 84, 159, 110, 92, 245, 23, 87, 29, 201, 215, 233, 161, 84, 210, 16, 58, 35, 123, 166, 209, 32, 79, 3, 168, 243, 195, 112, 152, 178, 26, 118, 1, 115, 76, 222, 8, 225, 161, 178, 123, 249, 95, 104, 229, 115, 155, 52, 68, 234, 1, 229, 144, 201, 119, 179, 94, 18, 180, 151, 5, 80, 162, 22, 199, 5, 96, 30, 197, 247, 27, 238, 59, 171, 145, 11, 240, 6, 248, 254, 150, 236, 8, 223, 178, 159, 1, 164, 233, 240, 118, 55, 35, 88, 89, 114, 124, 112, 245, 38, 155, 74, 57, 132, 201, 69, 227, 170, 233, 28, 232, 227, 19, 231, 217, 252, 205, 5, 85, 206, 18, 188, 175, 57, 85, 81, 224, 186, 112, 146, 16, 48, 72, 197, 245, 124, 9, 131, 197, 240, 75, 227, 235, 242, 225, 184, 10, 151, 128, 124, 182, 65, 96, 101, 109, 102, 103, 47, 79, 46, 130, 203, 190, 205, 114, 228, 131, 170, 182, 175, 178, 196, 195, 199, 188, 195, 151, 130, 106, 98, 14, 165, 6, 82, 116, 164, 152, 156, 24, 3, 49, 85, 136, 12, 68, 95, 35, 212, 168, 35, 52, 71, 19, 91, 142, 184, 95, 195, 252, 224, 182, 173, 198, 204, 137, 13, 254, 34, 70, 140, 14, 16, 48, 160, 251, 148, 53, 73, 13, 152, 82, 226, 194, 44, 137, 60, 15, 71, 208, 199, 67, 75, 55, 58, 55, 9, 247, 179, 48, 56, 42, 209, 127, 6, 61, 192, 59, 8, 170, 64, 219, 250, 7, 173, 219, 68, 161, 113, 244, 101, 80, 39, 170, 175, 58, 175, 86, 129, 145, 40, 164, 234, 20, 66, 39, 102, 111, 16, 123, 10, 192, 27, 28, 80, 26, 87, 184, 186, 202, 126, 124, 141, 7, 35, 21, 235, 3, 81, 129, 79, 146, 19, 154, 190, 2, 175, 177, 0, 231, 28, 151, 73, 147, 239, 144, 128, 220, 180, 167, 167, 82, 221, 99, 57, 168, 246, 251, 35, 203, 180, 84, 102, 68, 249, 138, 37, 17, 229, 65, 217, 99, 21, 82, 37, 161, 253, 12, 34, 106, 17, 229, 1, 213, 70, 84, 105, 154, 252, 102, 128, 24, 19, 132, 116, 214, 240, 6, 110, 7, 59, 51, 83, 32, 133, 222, 175, 69, 134, 191, 64, 62, 176, 195, 3, 64, 113, 58, 188, 63, 68, 60, 35, 189, 198, 58, 75, 114, 132, 252, 179, 192, 181, 128, 93, 189, 255, 233, 78, 219, 176, 108, 60, 143, 48, 53, 63, 213, 167, 98, 75, 141, 73, 189, 59, 190, 147, 106, 69, 125, 206, 230, 251, 49, 147, 171, 252, 26, 47, 159, 230, 72, 26, 26, 145, 40, 64, 33, 172, 124, 166, 119, 90, 122, 137, 104, 254, 60, 25, 69, 224, 149, 111, 138, 191, 244, 81, 108, 205, 168, 48, 97, 15, 4, 98, 39, 156, 188, 162, 45, 29, 176, 254, 62, 121, 81, 106, 76, 238, 248, 113, 3, 13, 152, 253, 160, 145, 156, 86, 173, 8, 197, 252, 140, 86, 45, 39, 67, 54, 97, 56, 191, 161, 220, 69, 216, 215, 84, 171, 128, 2, 95, 181, 207, 238, 45, 221, 53, 147, 208, 68, 110, 18, 58, 255, 57, 143, 78, 52, 207, 148, 174, 10, 18, 196, 40, 213, 253, 101, 4, 7, 3, 223, 92, 125, 36, 183, 229, 71, 248, 120, 154, 33, 58, 211, 231, 17, 232, 151, 216, 255, 74, 201, 61, 253, 156, 209, 255, 167, 172, 202, 161, 56, 77, 180, 117, 5, 180, 52, 24, 8, 33, 72, 74, 30, 119, 13, 179, 187, 181, 115, 68, 197, 239, 10, 69, 79, 81, 200, 145, 209, 198, 237, 12, 152, 124, 200, 203, 170, 99, 151, 22, 62, 89, 198, 68, 116, 237, 139, 217, 107, 209, 109, 9, 96, 35, 250, 54, 149, 111, 53, 192, 225, 79, 26, 97, 60, 243, 162, 104, 147, 24, 175, 84, 2, 49, 174, 202, 38, 53, 34, 160, 82, 158, 101, 180, 144, 18, 238, 65, 63, 165, 108, 15, 108, 140, 170, 32, 122, 73, 76, 64, 188, 103, 225, 239, 100, 240, 12, 25, 39, 9, 187, 228, 112, 162, 100, 185, 27, 72, 122, 218, 28, 2, 20, 247, 7, 190, 131, 66, 116, 242, 180, 95, 189, 79, 158, 86, 246, 22, 14, 0, 104, 154, 105, 100, 39, 227, 139, 56, 221, 153, 88, 164, 163, 19, 248, 164, 72, 149, 49, 161, 247, 6, 100, 233, 26, 245, 44, 43, 115, 214, 91, 164, 205, 224, 59, 5, 48, 170, 187, 210, 184, 4, 83, 123, 170, 24, 194, 169, 181, 127, 47, 225, 198, 59, 145, 144, 8, 106, 166, 8, 121, 198, 120, 198, 155, 26, 143, 137, 243, 213, 27, 235, 203, 195, 28, 143, 144, 33, 123, 252, 32, 18, 248, 224, 59, 193, 210, 78, 21, 149, 16, 232, 130, 47, 93, 161, 37, 98, 80, 219, 199, 46, 45, 177, 231, 28, 127, 238, 28, 144, 0, 39, 54, 5, 215, 8, 70, 41, 196, 118, 117, 233, 11, 252, 41, 217, 123, 250, 53, 74, 20, 228, 84, 231, 254, 19, 211, 177, 231, 41, 16, 38, 47, 21, 158, 64, 255, 107, 29, 83, 142, 37, 37, 153, 116, 81, 210, 58, 227, 49, 184, 188, 219, 170, 168, 29, 19, 228, 8, 78, 45, 162, 75, 40, 157, 32, 224, 130, 72, 105, 24, 87, 20, 250, 9, 123, 187, 110, 77, 232, 243, 110, 45, 175, 67, 117, 168, 169, 57, 142, 12, 225, 19, 132, 2, 113, 42, 233, 47, 132, 241, 11, 189, 145, 11, 227, 175, 254, 14, 168, 95, 4, 241, 224, 97, 0, 196, 105, 146, 205, 254, 212, 1, 252, 81, 109, 177, 226, 171, 172, 44, 153, 216, 153, 245, 78, 167, 185, 63, 105, 184, 114, 92, 13, 107, 5, 21, 150, 22, 208, 65, 169, 159, 237, 9, 48, 206, 61, 24, 121, 172, 137, 75, 105, 105, 85, 149, 162, 190, 212, 129, 15, 74, 239, 185, 44, 162, 12, 192, 218, 84, 23, 132, 130, 120, 242, 243, 202, 192, 150, 177, 158, 242, 191, 184, 97, 16, 204, 35, 173, 159, 99, 33, 109, 204, 111, 3, 249, 253, 75, 113, 207, 98, 66, 218, 7, 81, 164, 106, 108, 77, 225, 64, 109, 33, 143, 88, 87, 76, 52, 48, 200, 172, 169, 190, 246, 172, 170, 230, 2, 43, 138, 226, 155, 225, 150, 250, 19, 234, 86, 75, 20, 18, 62, 163, 10, 172, 69, 38, 122, 35, 48, 48, 234, 21, 189, 158, 78, 153, 72, 62, 77, 157, 102, 248, 38, 151, 164, 15, 230, 232, 230, 230, 146, 195, 221, 244, 233, 250, 93, 118, 64, 249, 223, 158, 216, 33, 138, 44, 50, 225, 112, 56, 94, 44, 98, 154, 44, 31, 190, 150, 194, 223, 110, 165, 225, 157, 146, 115, 174, 157, 44, 76, 168, 155, 77, 222, 205, 138, 49, 160, 195, 193, 154, 228, 1, 60, 37, 239, 9, 18, 10, 238, 72, 220, 33, 88, 93, 40, 58, 88, 251, 117, 183, 246, 20, 109, 188, 79, 127, 123, 207, 90, 125, 178, 113, 34, 218, 135, 250, 57, 242, 163, 23, 203, 191, 231, 174, 34, 16, 210, 238, 64, 175, 248, 180, 16, 182, 177, 98, 231, 121, 51, 52, 88, 91, 236, 10, 11, 179, 145, 3, 66, 177, 33, 92, 244, 102, 231, 182, 106, 10, 237, 184, 148, 178, 39, 56, 14, 45, 223, 14, 14, 204, 22, 49, 75, 1, 241, 117, 246, 7, 29, 24, 122, 120, 132, 15, 171, 69, 223, 192, 162, 79, 44, 136, 41, 174, 170, 129, 118, 1, 74, 30, 218, 247, 39, 55, 99, 150, 72, 199, 214, 184, 4, 129, 72, 67, 121, 183, 235, 143, 183, 228, 130, 92, 160, 3, 194, 145, 242, 95, 85, 45, 170, 174, 157, 173, 73, 121, 213, 168, 95, 101, 58, 207, 57, 237, 51, 156, 67, 35, 207, 85, 161, 33, 129, 138, 8, 241, 58, 58, 218, 43, 97, 220, 177, 200, 65, 164, 152, 238, 19, 59, 174, 149, 178, 12, 116, 134, 0, 72, 43, 107, 23, 254, 57, 7, 86, 85, 22, 185, 194, 226, 25, 46, 23, 81, 132, 78, 65, 99, 41, 37, 91, 202, 168, 4, 103, 176, 70, 247, 112, 34, 178, 26, 38, 234, 249, 169, 232, 245, 141, 182, 155, 255, 2, 79, 139, 67, 182, 27, 8, 131, 32, 114, 21, 192, 243, 151, 58, 13, 202, 255, 52, 6, 209, 44, 79, 60, 83, 180, 39, 94, 235, 226, 156, 32, 152, 44, 75, 50, 22, 249, 148, 230, 69, 98, 136, 120, 252, 39, 11, 85, 109, 117, 181, 106, 249, 82, 163, 207, 240, 192, 56, 34, 98, 6, 11, 36, 89, 64, 181, 52, 148, 28, 174, 129, 74, 125, 2, 118, 246, 6, 140, 76, 196, 122, 215, 85, 51, 192, 137, 93, 192, 37, 30, 68, 155, 100, 224, 59, 192, 218, 1, 33, 57, 247, 155, 123, 126, 79, 101, 74, 8, 19, 169, 9, 41, 232, 229, 24, 102, 75, 78, 210, 239, 226, 219, 215, 170, 229, 116, 116, 190, 121, 212, 59, 20, 55, 80, 94, 246, 251, 114, 1, 252, 136, 224, 51, 243, 18, 200, 101, 13, 102, 133, 25, 157, 53, 245, 48, 241, 153, 68, 160, 148, 126, 93, 251, 113, 245, 174, 211, 43, 242, 95, 62, 43, 198, 25, 136, 140, 219, 98, 19, 42, 63, 93, 130, 63, 120, 203, 45, 113, 5, 110, 148, 163, 223, 73, 8, 202, 136, 41, 122, 54, 247, 148, 76, 211, 44, 33, 86, 36, 182, 163, 204, 160, 22, 126, 202, 172, 52, 174, 18, 132, 159, 92, 76, 90, 114, 170, 105, 4, 154, 131, 248, 128, 228, 101, 160, 212, 203, 39, 171, 149, 239, 57, 123, 168, 81, 5, 74, 147, 83, 42, 173, 196, 87, 198, 143, 248, 5, 165, 138, 198, 34, 196, 25, 1, 203, 100, 203, 238, 217, 141, 27, 158, 38, 149, 145, 45, 104, 34, 27, 237, 64, 74, 35, 68, 226, 142, 114, 174, 122, 142, 239, 104, 153, 247, 155, 19, 0, 113, 104, 228, 155, 119, 147, 216, 215, 90, 53, 47, 92, 112, 75, 201, 85, 95, 45, 29, 232, 100, 73, 61, 145, 220, 235, 94, 68, 16, 170, 210, 162, 205, 5, 118, 225, 147, 229, 142, 31, 91, 98, 235, 125, 214, 111, 222, 45, 79, 180, 40, 29, 126, 112, 149, 52, 52, 158, 53, 59, 209, 240, 231, 220, 239, 9, 17, 78, 58, 3, 81, 167, 87, 133, 110, 67, 101, 39, 147, 188, 60, 15, 243, 6, 162, 34, 162, 125, 184, 237, 10, 57, 81, 154, 213, 251, 47, 54, 245, 10, 115, 127, 166, 254, 237, 197, 167, 157, 118, 105, 92, 96, 254, 188, 140, 228, 183, 106, 153, 82, 122, 162, 242, 31, 233, 215, 186, 110, 200, 169, 178, 107, 83, 113, 130, 168, 158, 111, 20, 150, 140, 162, 125, 53, 200, 205, 128, 219, 38, 242, 196, 139, 150, 239, 78, 224, 157, 25, 104, 63, 159, 50, 48, 186, 33, 219, 82, 157, 194, 209, 13, 65, 120, 100, 254, 44, 9, 120, 31, 103, 89, 94, 79, 150, 142, 167, 115, 117, 146, 214, 96, 152, 213, 142, 228, 72, 127, 85, 102, 237, 129, 12, 220, 220, 105, 45, 43, 38, 6, 128, 133, 87, 48, 105, 136, 177, 240, 42, 185, 72, 0, 107, 230, 26, 172, 122, 251, 110, 2, 32, 170, 103, 101, 69, 49, 107, 46, 36, 226, 208, 68, 31, 186, 81, 21, 31, 30, 236, 191, 244, 50, 30, 54, 143, 67, 207, 180, 19, 116, 96, 16, 123, 210, 82, 168, 221, 199, 147, 189, 133, 188, 91, 41, 205, 62, 61, 134, 36, 46, 18, 78, 133, 139, 190, 114, 11, 16, 28, 71, 53, 175, 35, 164, 173, 144, 111, 33, 184, 196, 125, 36, 101, 243, 29, 80, 169, 81, 186, 41, 196, 124, 120, 63, 118, 15, 61, 0, 60, 177, 247, 142, 158, 220, 202, 24, 204, 68, 10, 180, 34, 54, 16, 114, 151, 107, 6, 32, 220, 210, 191, 129, 80, 190, 124, 140, 214, 61, 1, 34, 193, 136, 141, 251, 157, 193, 46, 232, 84, 160, 249, 138, 207, 67, 2, 2, 7, 8, 244, 179, 136, 166, 131, 1, 145, 14, 5, 47, 81, 190, 198, 188, 245, 5, 50, 60, 55, 70, 217, 89, 28, 3, 41, 47, 251, 77, 248, 33, 68, 6, 116, 121, 191, 24, 67, 197, 16, 215, 111, 229, 132, 37, 212, 180, 190, 21, 69, 211, 154, 146, 141, 69, 69, 16, 0, 60, 110, 57, 13, 184, 190, 241, 198, 7, 83, 89, 150, 66, 157, 141, 175, 0, 136, 156, 163, 218, 215, 127, 82, 255, 152, 215, 37, 251, 186, 223, 111, 242, 253, 233, 175, 46, 179, 1, 247, 225, 30, 19, 192, 85, 130, 137, 155, 219, 41, 33, 185, 33, 126, 131, 237, 0, 45, 246, 54, 86, 176, 133, 211, 6, 141, 230, 90, 73, 65, 75, 120, 47, 179, 96, 28, 193, 30, 17, 22, 43, 98, 93, 196, 105, 88, 201, 40, 82, 5, 186, 29, 165, 158, 119, 102, 58, 14, 85, 89, 47, 85, 29, 140, 17, 27, 113, 21, 217, 143, 195, 91, 38, 192, 181, 229, 0, 150, 248, 97, 36, 158, 62, 103, 179, 116, 191, 114, 121, 95, 124, 249, 112, 228, 21, 127, 248, 123, 5, 192, 167, 229, 174, 2, 242, 151, 132, 55, 183, 139, 51, 103, 138, 69, 210, 136, 33, 104, 169, 119, 127, 45, 152, 138, 226, 157, 201, 29, 80, 106, 224, 12, 30, 1, 132, 36, 248, 62, 0, 147, 132, 226, 104, 67, 211, 87, 38, 35, 99, 160, 131, 195, 32, 144, 10, 32, 252, 197, 133, 128, 180, 123, 104, 143, 82, 64, 74, 70, 188, 208, 2, 59, 77, 212, 55, 110, 161, 52, 248, 78, 230, 221, 102, 142, 40, 136, 142, 172, 69, 135, 25, 92, 126, 241, 174, 200, 85, 205, 44, 175, 144, 83, 54, 250, 11, 206, 204, 162, 120, 232, 215, 8, 198, 110, 71, 48, 136, 146, 12, 184, 0, 18, 30, 55, 48, 216, 77, 109, 17, 9, 249, 51, 71, 255, 170, 218, 62, 243, 195, 71, 45, 149, 217, 142, 83, 181, 38, 44, 9, 9, 66, 57, 175, 69, 15, 60, 170, 97, 112, 61, 249, 182, 34, 100, 11, 216, 137, 101, 195, 80, 14, 35, 111, 223, 11, 61, 106, 208, 91, 81, 142, 145, 96, 145, 226, 159, 88, 22, 18, 211, 192, 154, 185, 67, 93, 73, 144, 206, 221, 201, 179, 138, 223, 88, 151, 122, 128, 150, 6, 102, 9, 91, 68, 130, 217, 147, 125, 1, 225, 102, 245, 212, 7, 178, 203, 91, 139, 175, 43, 102, 221, 172, 214, 192, 107, 116, 54, 78, 92, 225, 4, 6, 241, 194, 148, 237, 44, 171, 149, 17, 180, 104, 33, 144, 86, 133, 205, 70, 236, 87, 40, 195, 147, 67, 8, 34, 112, 64, 22, 111, 196, 96, 246, 129, 131, 226, 36, 181, 250, 68, 98, 86, 159, 77, 5, 182, 147, 224, 21, 65, 18, 180, 36, 85, 224, 100, 229, 166, 85, 59, 255, 113, 41, 130, 120, 232, 2, 113, 114, 211, 53, 200, 45, 183, 238, 240, 174, 1, 68, 82, 167, 6, 198, 172, 55, 103, 200, 2, 8, 30, 53, 196, 99, 40, 138, 239, 185, 86, 191, 230, 174, 97, 61, 7, 120, 85, 142, 6, 202, 107, 114, 20, 202, 13, 209, 82, 46, 122, 14, 21, 27, 44, 152, 132, 217, 40, 254, 113, 170, 186, 229, 228, 81, 15, 148, 77, 26, 43, 113, 17, 100, 156, 33, 90, 38, 88, 129, 171, 199, 148, 30, 16, 94, 95, 182, 24, 159, 4, 96, 106, 98, 219, 36, 73, 218, 79, 152, 152, 176, 159, 34, 13, 80, 54, 176, 157, 191, 128, 46, 230, 117, 199, 127, 8, 36, 208, 7, 237, 41, 241, 160, 116, 172, 181, 90, 94, 233, 130, 233, 225, 35, 53, 155, 106, 115, 118, 192, 220, 118, 190, 248, 170, 110, 113, 23, 171, 120, 176, 247, 181, 130, 172, 197, 44, 111, 239, 3, 89, 217, 108, 182, 120, 190, 62, 138, 226, 232, 31, 233, 3, 77, 114, 53, 228, 157, 129, 209, 233, 26, 245, 254, 235, 164, 195, 194, 50, 73, 225, 14, 225, 251, 100, 59, 93, 167, 134, 171, 186, 46, 101, 169, 205, 33, 87, 23, 97, 138, 116, 226, 51, 2, 229, 221, 188, 16, 219, 175, 168, 202, 198, 113, 51, 183, 116, 137, 139, 224, 233, 20, 110, 121, 47, 206, 155, 201, 166, 114, 226, 30, 186, 157, 124, 241, 5, 119, 99, 101, 106, 151, 49, 60, 206, 210, 16, 66, 2, 247, 168, 159, 166, 192, 198, 55, 217, 22, 126, 235, 14, 203, 81, 72, 142, 194, 187, 42, 118, 189, 167, 4, 199, 59, 110, 8, 88, 121, 247, 138, 57, 180, 45, 96, 77, 227, 228, 29, 187, 65, 173, 142, 96, 100, 26, 22, 160, 88, 108, 210, 83, 138, 196, 35, 9, 58, 176, 71, 59, 21, 128, 59, 166, 47, 114, 158, 226, 145, 144, 199, 35, 25, 219, 22, 38, 104, 119, 65, 4, 222, 170, 224, 89, 206, 26, 96, 33, 60, 62, 37, 201, 27, 92, 91, 201, 64, 220, 109, 103, 222, 7, 100, 225, 114, 221, 19, 47, 192, 117, 243, 236, 23, 100, 113, 251, 111, 69, 196, 144, 237, 22, 0, 243, 251, 138, 240, 123, 95, 168, 224, 167, 223, 133, 197, 143, 144, 126, 100, 139, 36, 120, 185, 19, 175, 240, 251, 66, 46, 56, 197, 169, 168, 17, 168, 218, 183, 9, 186, 123, 140, 168, 226, 74, 117, 140, 191, 210, 161, 96, 53, 229, 192, 250, 224, 73, 189, 235, 153, 225, 28, 2, 12, 95, 25, 130, 167, 139, 189, 24, 71, 2, 102, 46, 149, 137, 237, 194, 61, 67, 138, 20, 249, 40, 35, 24, 176, 188, 60, 122, 73, 231, 156, 204, 253, 245, 41, 229, 144, 192, 152, 102, 71, 6, 241, 0, 37, 176, 223, 91, 213, 236, 216, 245, 235, 127, 83, 130, 229, 102, 244, 219, 40, 236, 135, 5, 153, 88, 186, 213, 62, 120, 187, 115, 9, 181, 44, 8, 212, 111, 78, 255, 237, 244, 101, 133, 113, 169, 31, 28, 202, 147, 120, 190, 147, 133, 123, 14, 223, 120, 41, 71, 114, 51, 165, 6, 90, 90, 113, 207, 246, 150, 40, 143, 124, 73, 170, 193, 232, 107, 43, 98, 59, 25, 123, 59, 250, 108, 7, 21, 105, 79, 72, 113, 27, 1, 88, 37, 20, 218, 254, 183, 233, 14, 124, 16, 59, 17, 164, 162, 242, 247, 9, 80, 7, 183, 151, 68, 41, 52, 22, 53, 134, 88, 223, 113, 154, 95, 205, 178, 170, 125, 216, 45, 152, 141, 76, 33, 184, 43, 186, 41, 151, 115, 223, 224, 97, 100, 154, 30, 74, 20, 148, 113, 180, 100, 226, 221, 19, 143, 119, 182, 45, 90, 99, 157, 90, 57, 80, 58, 227, 107, 36, 177, 138, 144, 245, 78, 4, 218, 205, 154, 147, 59, 62, 163, 67, 7, 174, 32, 91, 254, 145, 126, 187, 221, 208, 92, 111, 73, 170, 173, 107, 59, 69, 78, 7, 171, 135, 241, 148, 138, 50, 40, 228, 138, 10, 229, 228, 145, 95, 223, 13, 161, 183, 245, 41, 150, 149, 199, 7, 255, 138, 221, 142, 172, 65, 53, 31, 230, 47, 229, 126, 42, 131, 66, 18, 77, 203, 6, 222, 228, 215, 192, 209, 175, 98, 184, 159, 241, 106, 95, 255, 111, 55, 45, 234, 212, 4, 32, 208, 111, 37, 212, 53, 129, 70, 168, 156, 151, 188, 2, 121, 154, 140, 84, 155, 164, 51, 114, 142, 45, 24, 51, 99, 137, 224, 147, 212, 26, 220, 163, 19, 39, 180, 215, 53, 165, 162, 182, 233, 59, 221, 11, 90, 237, 112, 78, 36, 117, 233, 23, 229, 192, 94, 99, 96, 118, 171, 57, 42, 16, 98, 175, 43, 171, 196, 248, 18, 57, 19, 98, 181, 237, 235, 184, 177, 155, 6, 83, 179, 70, 162, 221, 121, 216, 116, 116, 200, 193, 164, 252, 59, 216, 48, 104, 112, 42, 207, 152, 246, 91, 109, 141, 68, 104, 49, 225, 210, 8, 79, 179, 62, 10, 31, 156, 189, 216, 179, 81, 102, 220, 79, 187, 167, 207, 11, 119, 83, 130, 24, 100, 215, 115, 143, 96, 213, 132, 109, 77, 35, 168, 40, 247, 133, 60, 55, 179, 26, 159, 70, 149, 59, 249, 130, 175, 113, 97, 166, 123, 156, 54, 129, 126, 197, 171, 18, 105, 91, 254, 211, 78, 233, 206, 145, 166, 101, 97, 32, 157, 236, 137, 252, 183, 59, 234, 219, 181, 236, 190, 76, 56, 145, 170, 245, 59, 208, 29, 16, 116, 45, 138, 135, 248, 118, 228, 3, 251, 244, 177, 85, 107, 13, 57, 60, 35, 237, 73, 5, 58, 172, 120, 165, 47, 223, 127, 98, 136, 84, 16, 18, 225, 126, 38, 100, 120, 35, 194, 204, 170, 144, 253, 217, 18, 86, 133, 225, 191, 220, 178, 177, 11, 51, 146, 205, 132, 128, 33, 90, 195, 234, 116, 68, 20, 73, 194, 135, 137, 0, 16, 169, 243, 123, 5, 130, 172, 162, 48, 240, 232, 208, 158, 32, 49, 140, 245, 51, 37, 131, 92, 67, 126, 44, 13, 31, 62, 240, 80, 131, 136, 187, 222, 199, 19, 28, 229, 240, 122, 208, 244, 180, 58, 232, 46, 1, 83, 171, 236, 220, 69, 6, 43, 152, 203, 3, 16, 246, 17, 69, 116, 54, 64, 9, 240, 109, 189, 32, 237, 189, 153, 148, 107, 2, 7, 224, 144, 242, 114, 76, 46, 66, 91, 31, 228, 112, 115, 124, 108, 39, 108, 229, 232, 245, 175, 122, 57, 47, 175, 12, 179, 39, 27, 172, 167, 249, 76, 135, 106, 133, 82, 162, 27, 220, 11, 94, 144, 228, 95, 114, 158, 217, 58, 24, 211, 24, 42, 118, 88, 178, 81, 163, 27, 41, 116, 193, 231, 88, 164, 166, 21, 95, 207, 245, 47, 245, 173, 56, 11, 144, 87, 124, 231, 79, 214, 60, 160, 185, 39, 102, 146, 204, 70, 202, 222, 203, 101, 183, 165, 180, 33, 216, 127, 96, 249, 7, 143, 237, 96, 186, 72, 40, 64, 213, 23, 251, 103, 123, 251, 135, 182, 237, 169, 43, 46, 30, 140, 133, 53, 127, 17, 18, 37, 31, 123, 86, 187, 5, 75, 64, 27, 13, 175, 180, 152, 249, 135, 82, 16, 139, 136, 204, 175, 27, 135, 255, 204, 39, 223, 160, 78, 6, 151, 95, 65, 13, 41, 64, 93, 64, 1, 218, 99, 109, 134, 201, 25, 62, 0, 191, 212, 140, 170, 8, 19, 28, 119, 45, 2, 53, 228, 169, 150, 252, 218, 233, 121, 176, 198, 208, 137, 58, 62, 37, 8, 150, 83, 247, 152, 133, 121, 85, 85, 2, 54, 179, 179, 105, 251, 99, 239, 223, 90, 42, 76, 49, 187, 250, 187, 197, 150, 141, 139, 36, 178, 143, 241, 206, 44, 80, 255, 14, 198, 156, 112, 154, 232, 11, 75, 53, 213, 83, 123, 94, 141, 155, 201, 113, 241, 56, 70, 252, 64, 158, 166, 165, 96, 152, 186, 2, 92, 3, 114, 52, 156, 134, 7, 222, 31, 90, 137, 52, 48, 12, 201, 84, 147, 254, 138, 19, 184, 114, 245, 138, 7, 90, 49, 167, 145, 107, 182, 83, 253, 40, 52, 160, 187, 243, 67, 151, 82, 3, 218, 68, 56, 202, 178, 144, 175, 238, 77, 145, 191, 171, 245, 128, 4, 208, 195, 102, 119, 57, 240, 6, 66, 254, 211, 45, 130, 58, 225, 51, 99, 73, 13, 56, 58, 28, 35, 110, 33, 180, 51, 26, 140, 70, 26, 229, 180, 229, 176, 138, 226, 9, 134, 129, 185, 187, 239, 223, 2, 229, 233, 150, 121, 138, 51, 41, 143, 68, 57, 118, 56, 31, 87, 195, 1, 75, 87, 156, 253, 225, 48, 243, 60, 94, 212, 205, 205, 151, 180, 100, 135, 245, 23, 108, 18, 5, 132, 244, 135, 177, 10, 37, 12, 28, 10, 127, 93, 103, 207, 148, 27, 227, 93, 148, 246, 204, 17, 88, 121, 29, 100, 198, 40, 185, 62, 104, 157, 5, 56, 71, 213, 100, 127, 249, 128, 244, 137, 235, 154, 144, 197, 8, 208, 124, 114, 242, 13, 251, 50, 254, 34, 91, 56, 10, 193, 195, 147, 85, 84, 21, 114, 112, 185, 50, 108, 118, 235, 123, 103, 247, 179, 202, 50, 17, 200, 66, 193, 58, 63, 43, 104, 163, 165, 140, 252, 54, 59, 102, 13, 117, 138, 175, 183, 48, 220, 215, 173, 86, 24, 135, 190, 226, 209, 212, 8, 111, 15, 152, 3, 126, 226, 149, 168, 204, 178, 165, 4, 230, 32, 34, 8, 79, 242, 94, 100, 141, 5, 125, 159, 109, 205, 161, 61, 95, 14, 59, 3, 132, 196, 133, 176, 198, 172, 25, 243, 70, 148, 96, 196, 241, 24, 65, 116, 30, 177, 162, 251, 228, 156, 147, 77, 244, 65, 138, 223, 212, 22, 40, 122, 1, 202, 219, 51, 101, 78, 118, 96, 101, 146, 112, 10, 180, 36, 211, 254, 136, 208, 48, 88, 82, 217, 33, 32, 148, 185, 234, 217, 100, 29, 141, 88, 247, 168, 34, 215, 165, 136, 149, 42, 203, 97, 227, 69, 216, 67, 65, 14, 27, 19, 84, 33, 141, 58, 75, 72, 178, 44, 16, 160, 251, 174, 94, 248, 52, 184, 125, 190, 77, 251, 88, 72, 11, 153, 160, 127, 77, 22, 127, 219, 245, 89, 76, 136, 192, 202, 239, 219, 248, 248, 171, 164, 198, 78, 148, 85, 159, 72, 218, 223, 99, 53, 38, 201, 186, 121, 68, 137, 194, 174, 136, 239, 224, 160, 67, 111, 220, 229, 93, 245, 31, 250, 193, 91, 110, 252, 12, 7, 131, 47, 62, 73, 10, 100, 129, 88, 40, 230, 53, 209, 146, 14, 132, 120, 204, 222, 135, 68, 47, 222, 19, 60, 161, 7, 67, 64, 68, 70, 29, 152, 64, 7, 183, 251, 225, 148, 61, 155, 127, 233, 89, 112, 169, 73, 157, 76, 150, 85, 219, 41, 71, 220, 234, 15, 173, 98, 124, 209, 206, 71, 56, 201, 187, 64, 16, 103, 159, 78, 9, 84, 251, 250, 154, 196, 49, 125, 168, 154, 127, 40, 15, 139, 198, 155, 71, 7, 80, 98, 219, 105, 202, 183, 96, 32, 115, 28, 168, 81, 69, 23, 103, 33, 219, 47, 154, 131, 125, 7, 229, 140, 163, 248, 62, 156, 231, 8, 141, 34, 232, 193, 150, 171, 224, 190, 62, 76, 79, 203, 161, 1, 186, 3, 67, 55, 0, 117, 153, 152, 165, 90, 146, 124, 169, 150, 90, 241, 163, 67, 146, 64, 13, 165, 218, 131, 135, 166, 193, 186, 200, 149, 8, 55, 9, 227, 66, 157, 212, 226, 97, 91, 172, 199, 196, 59, 3, 76, 170, 88, 8, 242, 30, 148, 211, 214, 208, 102, 225, 102, 165, 119, 155, 69, 208, 18, 168, 81, 84, 153, 79, 240, 92, 216, 36, 99, 75, 125, 249, 93, 182, 54, 232, 169, 235, 184, 210, 169, 104, 11, 163, 110, 116, 174, 218, 205, 75, 188, 68, 8, 194, 219, 137, 103, 93, 23, 10, 64, 49, 217, 198, 215, 166, 151, 189, 209, 148, 92, 61, 14, 11, 101, 129, 79, 230, 112, 234, 42, 125, 185, 107, 178, 135, 186, 78, 220, 33, 145, 91, 144, 176, 224, 134, 93, 16, 202, 31, 211, 10, 221, 21, 202, 245, 141, 245, 51, 147, 27, 192, 146, 205, 175, 255, 21, 186, 205, 62, 177, 127, 20, 231, 2, 81, 3, 161, 67, 225, 24, 66, 9, 102, 150, 218, 178, 3, 255, 65, 4, 141, 81, 0, 197, 198, 168, 72, 163, 246, 235, 224, 14, 62, 70, 205, 42, 161, 183, 151, 76, 86, 78, 101, 168, 253, 154, 46, 206, 132, 135, 104, 60, 217, 8, 128, 64, 60, 88, 6, 152, 85, 189, 49, 186, 230, 62, 156, 64, 47, 172, 148, 77, 114, 199, 27, 222, 122, 225, 213, 230, 57, 233, 175, 32, 113, 1, 36, 30, 146, 82, 127, 199, 75, 195, 196, 117, 250, 190, 80, 4, 229, 168, 125, 109, 55, 135, 0, 189, 75, 14, 58, 177, 239, 93, 131, 234, 227, 168, 209, 224, 140, 99, 240, 36, 225, 141, 184, 71, 253, 235, 142, 103, 83, 120, 97, 74, 94, 20, 13, 176, 36, 55, 204, 132, 64, 162, 157, 251, 233, 127, 119, 51, 143, 194, 94, 249, 60, 10, 141, 252, 138, 129, 160, 193, 213, 122, 197, 216, 74, 4, 20, 59, 47, 197, 124, 199, 186, 87, 30, 88, 120, 70, 15, 171, 134, 218, 144, 167, 229, 168, 35, 179, 203, 208, 151, 121, 47, 192, 83, 179, 102, 112, 147, 20, 118, 169, 148, 69, 103, 200, 134, 204, 254, 162, 24, 3, 120, 7, 226, 166, 163, 175, 153, 35, 252, 209, 15, 165, 29, 133, 23, 74, 179, 174, 196, 118, 97, 220, 139, 245, 22, 58, 125, 146, 250, 198, 163, 228, 225, 101, 103, 214, 180, 18, 111, 105, 127, 33, 249, 2, 217, 144, 86, 167, 107, 236, 76, 40, 72, 64, 24, 94, 2, 238, 174, 42, 26, 117, 41, 124, 44, 108, 0, 7, 49, 228, 158, 225, 78, 88, 247, 141, 142, 242, 207, 128, 58, 142, 40, 141, 36, 93, 17, 54, 9, 210, 175, 248, 170, 142, 121, 4, 221, 108, 1, 184, 162, 113, 221, 64, 181, 30, 9, 32, 13, 69, 14, 154, 11, 237, 136, 237, 188, 146, 233, 171, 57, 159, 80, 235, 12, 80, 151, 11, 42, 157, 137, 44, 104, 53, 241, 188, 62, 99, 253, 118, 220, 242, 169, 182, 146, 31, 113, 19, 16, 61, 6, 75, 128, 18, 5, 52, 168, 187, 7, 139, 94, 14, 12, 107, 223, 20, 134, 162, 13, 12, 142, 51, 39, 158, 99, 191, 124, 233, 4, 96, 172, 172, 84, 138, 84, 49, 91, 8, 133, 190, 160, 59, 122, 114, 72, 82, 57, 6, 93, 108, 9, 88, 252, 240, 247, 185, 170, 28, 163, 243, 228, 81, 212, 118, 86, 5, 30, 20, 80, 46, 173, 177, 119, 216, 111, 84, 139, 132, 97, 122, 67, 108, 176, 171, 31, 192, 71, 108, 22, 65, 42, 83, 221, 166, 15, 32, 207, 141, 92, 177, 170, 65, 169, 83, 65, 54, 118, 184, 156, 7, 197, 130, 29, 9, 157, 87, 71, 235, 66, 54, 225, 220, 48, 160, 193, 88, 185, 231, 251, 229, 157, 118, 66, 206, 143, 242, 42, 72, 52, 178, 243, 198, 193, 43, 12, 81, 121, 178, 65, 82, 39, 113, 135, 191, 197, 25, 142, 148, 52, 46, 123, 192, 188, 246, 95, 87, 173, 225, 162, 39, 182, 51, 169, 185, 228, 25, 115, 30, 210, 225, 47, 168, 93, 139, 76, 121, 224, 61, 30, 24, 45, 34, 37, 181, 180, 128, 145, 155, 43, 70, 224, 60, 218, 30, 252, 249, 131, 154, 168, 9, 191, 85, 234, 233, 1, 44, 212, 224, 137, 138, 217, 13, 22, 242, 242, 53, 56, 105, 189, 221, 117, 62, 23, 174, 5, 224, 90, 248, 165, 13, 60, 67, 82, 189, 152, 105, 3, 139, 183, 12, 172, 166, 171, 255, 217, 124, 209, 99, 54, 24, 198, 163, 255, 2, 240, 164, 227, 85, 33, 161, 145, 116, 165, 236, 167, 159, 144, 242, 3, 146, 19, 50, 41, 147, 107, 91, 175, 196, 255, 199, 237, 77, 251, 219, 134, 189, 244, 68, 30, 7, 75, 127, 198, 102, 251, 159, 11, 184, 93, 83, 138, 212, 140, 140, 6, 36, 173, 187, 180, 108, 151, 197, 118, 66, 79, 12, 118, 208, 46, 125, 226, 42, 57, 213, 210, 197, 108, 152, 71, 173, 149, 135, 237, 62, 232, 173, 29, 172, 126, 113, 71, 106, 218, 86, 188, 1, 33, 158, 245, 155, 87, 41, 192, 89, 211, 249, 179, 104, 18, 33, 85, 24, 147, 141, 184, 80, 179, 223, 73, 21, 49, 7, 51, 100, 176, 0, 147, 244, 197, 172, 193, 132, 53, 85, 13, 245, 234, 12, 200, 81, 229, 103, 54, 92, 103, 85, 26, 128, 20, 35, 187, 4, 27, 213, 225, 155, 33, 131, 173, 198, 30, 7, 9, 53, 196, 10, 94, 237, 163, 5, 172, 28, 113, 80, 194, 43, 145, 4, 236, 3, 72, 133, 153, 203, 227, 3, 246, 104, 97, 142, 157, 88, 45, 227, 179, 186, 37, 91, 33, 179, 62, 102, 144, 76, 199, 215, 113, 163, 177, 129, 129, 96, 215, 157, 4, 245, 192, 127, 80, 107, 219, 227, 216, 148, 203, 227, 212, 164, 165, 165, 83, 55, 18, 157, 178, 38, 72, 132, 180, 238, 70, 3, 12, 5, 97, 58, 155, 168, 184, 115, 175, 123, 17, 168, 187, 243, 74, 109, 199, 96, 126, 228, 98, 132, 15, 144, 164, 246, 57, 19, 83, 230, 184, 222, 50, 245, 22, 162, 245, 162, 146, 89, 186, 89, 5, 177, 128, 97, 29, 86, 147, 172, 67, 139, 57, 166, 137, 110, 149, 113, 229, 162, 164, 59, 218, 41, 17, 124, 43, 130, 13, 113, 199, 215, 165, 33, 146, 8, 220, 14, 151, 124, 1, 70, 231, 102, 246, 217, 176, 97, 79, 191, 243, 204, 172, 78, 71, 4, 239, 151, 227, 221, 255, 133, 178, 140, 248, 91, 235, 79, 111, 48, 181, 151, 236, 142, 165, 198, 189, 28, 53, 136, 250, 153, 75, 195, 82, 131, 204, 217, 175, 219, 137, 72, 87, 207, 28, 73, 112, 14, 44, 55, 68, 97, 88, 27, 154, 179, 9, 200, 145, 146, 232, 191, 23, 150, 223, 15, 205, 21, 161, 118, 30, 188, 186, 171, 208, 8, 63, 88, 180, 56, 192, 72, 228, 135, 104, 243, 190, 238, 39, 179, 179, 122, 84, 54, 120, 48, 154, 174, 253, 192, 59, 249, 111, 119, 73, 17, 139, 121, 27, 98, 57, 161, 222, 147, 146, 37, 54, 159, 66, 191, 158, 153, 60, 147, 6, 126, 84, 165, 19, 22, 147, 43, 148, 87, 63, 174, 214, 178, 22, 233, 112, 25, 157, 123, 118, 219, 179, 249, 182, 114, 217, 218, 80, 33, 248, 103, 89, 0, 87, 200, 154, 249, 23, 157, 67, 106, 97, 249, 183, 20, 67, 56, 75, 84, 176, 40, 0, 50, 144, 58, 38, 89, 93, 107, 197, 123, 90, 164, 99, 48, 17, 13, 212, 121, 152, 96, 84, 166, 118, 106, 128, 230, 107, 95, 26, 107, 4, 161, 48, 191, 181, 197, 150, 66, 18, 252, 11, 235, 79, 238, 66, 233, 26, 137, 89, 16, 5, 249, 174, 96, 250, 242, 12, 16, 241, 94, 73, 232, 36, 244, 54, 140, 38, 43, 213, 89, 53, 115, 212, 223, 21, 84, 167, 119, 246, 0, 5, 218, 87, 141, 124, 140, 206, 146, 171, 26, 171, 128, 9, 221, 33, 116, 110, 98, 87, 46, 15, 34, 41, 60, 123, 115, 8, 168, 183, 63, 117, 171, 129, 157, 216, 92, 75, 128, 46, 59, 169, 53, 33, 115, 65, 162, 155, 178, 128, 25, 109, 237, 41, 89, 107, 48, 23, 79, 191, 16, 205, 172, 148, 171, 201, 246, 104, 166, 6, 134, 23, 233, 136, 106, 157, 246, 136, 102, 57, 76, 34, 221, 231, 144, 129, 9, 26, 234, 97, 208, 97, 94, 134, 86, 25, 206, 224, 129, 138, 240, 108, 64, 17, 97, 248, 188, 16, 16, 184, 9, 123, 43, 18, 135, 33, 252, 11, 100, 46, 42, 20, 209, 144, 173, 136, 115, 65, 129, 236, 137, 53, 9, 5, 109, 211, 100, 75, 199, 57, 141, 40, 42, 32, 10, 66, 177, 93, 91, 215, 170, 24, 79, 41, 9, 230, 65, 104, 193, 139, 75, 233, 180, 90, 204, 152, 170, 244, 35, 149, 77, 41, 120, 50, 106, 72, 8, 103, 152, 32, 198, 161, 133, 129, 252, 38, 148, 229, 225, 133, 5, 81, 134, 16, 45, 17, 145, 114, 193, 12, 41, 18, 161, 219, 118, 197, 208, 151, 77, 227, 115, 137, 121, 225, 156, 42, 251, 13, 233, 206, 235, 129, 94, 197, 158, 104, 19, 26, 117, 164, 6, 236, 54, 97, 246, 84, 239, 138, 233, 18, 151, 202, 152, 137, 218, 168, 105, 128, 167, 7, 162, 193, 86, 129, 128, 95, 5, 237, 98, 57, 8, 155, 11, 199, 247, 109, 71, 90, 58, 206, 232, 88, 164, 210, 115, 126, 230, 26, 251, 216, 109, 3, 37, 203, 62, 194, 123, 27, 87, 107, 146, 154, 64, 194, 130, 148, 138, 89, 40, 242, 253, 235, 64, 128, 99, 74, 225, 162, 211, 246, 170, 219, 168, 158, 47, 173, 210, 184, 231, 53, 225, 124, 18, 57, 137, 223, 144, 48, 164, 114, 106, 209, 216, 70, 29, 69, 114, 131, 174, 112, 40, 234, 73, 138, 176, 194, 110, 119, 204, 79, 241, 81, 1, 18, 72, 164, 80, 97, 203, 114, 152, 4, 27, 118, 67, 177, 81, 53, 58, 15, 106, 163, 227, 43, 142, 91, 251, 72, 129, 99, 15, 173, 239, 36, 41, 54, 107, 131, 4, 66, 9, 42, 152, 125, 34, 68, 170, 80, 188, 250, 63, 62, 198, 231, 62, 246, 254, 127, 11, 248, 242, 76, 15, 173, 32, 230, 106, 145, 228, 85, 175, 156, 71, 40, 30, 78, 202, 15, 233, 254, 63, 68, 191, 238, 126, 87, 79, 31, 78, 135, 113, 199, 114, 193, 181, 215, 192, 108, 128, 120, 62, 34, 247, 87, 5, 111, 105, 244, 85, 56, 77, 112, 206, 109, 50, 74, 1, 163, 18, 158, 27, 21, 65, 122, 11, 232, 11, 85, 145, 177, 4, 246, 1, 133, 84, 70, 68, 61, 155, 51, 232, 150, 77, 34, 2, 64, 205, 110, 1, 179, 229, 251, 168, 238, 45, 9, 246, 52, 91, 13, 93, 109, 252, 70, 184, 105, 79, 40, 199, 91, 65, 31, 2, 163, 248, 150, 245, 2, 208, 223, 162, 18, 170, 125, 201, 16, 195, 242, 148, 17, 197, 153, 149, 234, 129, 134, 71, 30, 146, 2, 227, 248, 213, 121, 212, 153, 29, 101, 7, 246, 119, 92, 30, 63, 55, 73, 129, 27, 128, 162, 96, 10, 248, 250, 55, 99, 115, 129, 101, 230, 163, 14, 8, 158, 92, 159, 97, 2, 192, 149, 22, 3, 196, 9, 176, 114, 137, 2, 104, 182, 5, 134, 58, 60, 97, 146, 148, 6, 54, 33, 203, 162, 53, 23, 50, 45, 30, 228, 13, 233, 55, 200, 65, 150, 39, 104, 168, 200, 140, 65, 178, 143, 114, 40, 64, 225, 60, 43, 248, 40, 191, 0, 138, 172, 254, 185, 91, 2, 67, 184, 237, 169, 95, 69, 57, 162, 110, 78, 143, 92, 24, 7, 4, 63, 151, 107, 144, 82, 60, 19, 170, 227, 90, 163, 221, 81, 180, 224, 102, 136, 144, 152, 237, 77, 247, 168, 212, 87, 160, 135, 76, 58, 139, 227, 103, 212, 184, 10, 77, 150, 189, 39, 90, 149, 197, 204, 125, 100, 171, 79, 66, 202, 131, 89, 1, 15, 18, 85, 202, 30, 107, 110, 156, 181, 213, 87, 68, 44, 0, 13, 19, 69, 235, 242, 150, 69, 138, 65, 200, 55, 48, 178, 71, 211, 139, 121, 53, 182, 165, 252, 203, 117, 40, 100, 248, 16, 110, 70, 94, 39, 211, 236, 178, 194, 163, 191, 249, 233, 188, 244, 124, 122, 192, 107, 230, 78, 27, 175, 65, 222, 1, 217, 198, 37, 181, 19, 162, 241, 159, 133, 55, 110, 82, 134, 43, 192, 149, 126, 201, 214, 254, 223, 73, 62, 227, 220, 138, 83, 117, 190, 169, 25, 161, 135, 38, 83, 133, 204, 56, 212, 115, 38, 88, 46, 237, 27, 228, 40, 68, 24, 233, 116, 28, 119, 95, 36, 205, 134, 129, 220, 194, 44, 198, 222, 121, 227, 126, 192, 26, 175, 204, 149, 162, 71, 159, 158, 238, 116, 123, 249, 201, 74, 206, 30, 11, 40, 16, 72, 170, 42, 127, 197, 252, 159, 6, 9, 3, 110, 70, 213, 133, 181, 153, 92, 140, 105, 86, 185, 71, 115, 231, 85, 241, 220, 137, 34, 32, 52, 195, 234, 49, 220, 123, 165, 126, 247, 177, 10, 69, 93, 145, 71, 89, 211, 222, 234, 148, 198, 199, 206, 211, 35, 19, 96, 130, 231, 137, 108, 217, 123, 17, 167, 78, 141, 242, 196, 17, 129, 9, 159, 237, 183, 133, 1, 95, 26, 231, 8, 204, 152, 184, 96, 56, 144, 136, 128, 42, 236, 247, 18, 217, 172, 141, 57, 187, 21, 23, 198, 26, 109, 218, 180, 199, 199, 52, 118, 164, 120, 51, 3, 19, 152, 144, 249, 152, 74, 129, 82, 55, 204, 102, 74, 211, 97, 180, 104, 113, 209, 27, 229, 238, 60, 123, 251, 114, 201, 0, 8, 11, 126, 113, 102, 100, 1, 233, 218, 52, 166, 231, 69, 75, 10, 166, 179, 78, 191, 117, 254, 97, 201, 153, 1, 179, 188, 140, 137, 132, 34, 108, 132, 26, 216, 175, 234, 36, 196, 161, 45, 149, 180, 217, 174, 75, 129, 85, 205, 21, 110, 248, 108, 53, 154, 47, 4, 152, 72, 146, 46, 208, 106, 168, 37, 201, 232, 44, 211, 129, 57, 134, 251, 150, 29, 46, 60, 104, 20, 67, 56, 116, 61, 181, 52, 191, 143, 192, 5, 214, 81, 68, 73, 182, 179, 32, 23, 84, 124, 205, 49, 41, 137, 195, 167, 189, 38, 89, 22, 182, 242, 76, 52, 158, 92, 160, 224, 36, 154, 168, 212, 60, 182, 143, 12, 51, 123, 142, 80, 60, 112, 0, 213, 34, 3, 27, 161, 9, 108, 141, 28, 97, 102, 130, 29, 95, 191, 220, 148, 138, 190, 64, 49, 170, 159, 245, 227, 255, 3, 116, 128, 174, 124, 214, 165, 98, 78, 9, 216, 65, 206, 0, 240, 109, 119, 67, 165, 0, 22, 168, 170, 130, 2, 94, 14, 206, 158, 181, 157, 26, 44, 241, 21, 176, 84, 200, 91, 59, 16, 3, 138, 69, 84, 146, 150, 138, 226, 172, 18, 96, 49, 156, 163, 18, 212, 26, 169, 99, 98, 8, 205, 231, 18, 191, 36, 118, 189, 185, 60, 128, 83, 107, 88, 253, 58, 205, 163, 48, 163, 18, 221, 148, 128, 219, 103, 135, 40, 168, 232, 116, 68, 122, 38, 10, 62, 71, 41, 169, 34, 131, 174, 122, 58, 59, 82, 24, 59, 79, 184, 118, 242, 27, 214, 199, 140, 39, 105, 142, 148, 153, 43, 176, 126, 83, 217, 240, 118, 100, 76, 234, 70, 92, 22, 48, 46, 216, 75, 133, 119, 92, 108, 32, 99, 211, 25, 142, 175, 226, 156, 53, 178, 36, 117, 218, 218, 130, 5, 49, 215, 164, 191, 34, 234, 90, 1, 60, 151, 105, 226, 255, 94, 126, 182, 52, 164, 105, 139, 126, 178, 244, 160, 252, 170, 140, 160, 99, 186, 139, 43, 143, 92, 145, 250, 33, 139, 91, 252, 207, 17, 154, 169, 53, 140, 170, 64, 216, 181, 181, 69, 231, 198, 224, 170, 71, 21, 82, 187, 224, 216, 164, 51, 161, 2, 68, 131, 137, 107, 206, 196, 203, 20, 77, 51, 160, 234, 153, 61, 217, 109, 184, 164, 61, 249, 210, 156, 67, 254, 94, 254, 35, 139, 189, 123, 49, 111, 194, 101, 82, 135, 234, 205, 215, 109, 63, 84, 79, 221, 20, 132, 133, 79, 208, 84, 170, 123, 187, 24, 159, 243, 26, 124, 217, 103, 225, 238, 200, 80, 47, 245, 48, 17, 219, 60, 162, 146, 241, 182, 133, 72, 132, 4, 206, 197, 20, 181, 1, 135, 121, 121, 102, 202, 98, 211, 29, 88, 61, 100, 149, 6, 24, 103, 138, 194, 101, 107, 177, 206, 250, 179, 154, 47, 29, 144, 246, 120, 115, 27, 188, 252, 18, 150, 214, 198, 144, 182, 149, 178, 71, 12, 252, 147, 243, 126, 143, 187, 181, 21, 250, 253, 120, 103, 240, 28, 73, 36, 139, 61, 124, 6, 180, 161, 218, 142, 82, 245, 168, 60, 7, 197, 252, 83, 83, 68, 102, 64, 138, 25, 132, 194, 88, 240, 135, 232, 53, 70, 19, 212, 62, 102, 170, 32, 22, 5, 208, 231, 207, 89, 208, 157, 87, 96, 148, 67, 164, 172, 97, 249, 238, 116, 233, 217, 10, 225, 246, 202, 56, 222, 205, 23, 245, 76, 19, 201, 146, 68, 28, 166, 127, 67, 168, 145, 135, 194, 8, 129, 29, 180, 70, 38, 80, 142, 94, 9, 254, 58, 249, 113, 90, 121, 11, 27, 55, 110, 80, 43, 62, 116, 209, 48, 7, 133, 100, 72, 227, 79, 69, 25, 253, 109, 6, 127, 214, 182, 234, 26, 231, 79, 201, 180, 42, 209, 200, 185, 110, 118, 71, 103, 233, 178, 98, 56, 70, 193, 27, 32, 133, 115, 89, 37, 192, 103, 138, 49, 222, 9, 166, 94, 84, 214, 119, 147, 161, 190, 93, 253, 110, 110, 208, 89, 174, 143, 83, 164, 147, 39, 228, 244, 128, 66, 8, 46, 42, 225, 45, 150, 234, 138, 17, 139, 48, 33, 36, 88, 43, 219, 159, 3, 28, 230, 122, 23, 4, 116, 204, 220, 129, 173, 42, 0, 176, 17, 23, 221, 184, 218, 68, 210, 178, 163, 102, 122, 148, 105, 208, 188, 158, 52, 134, 84, 62, 90, 242, 66, 174, 54, 14, 51, 96, 205, 239, 250, 121, 155, 33, 163, 224, 42, 57, 199, 183, 224, 242, 114, 96, 160, 253, 199, 53, 253, 61, 158, 9, 32, 103, 93, 232, 0, 125, 247, 146, 32, 217, 137, 214, 186, 110, 15, 91, 127, 246, 127, 33, 135, 7, 44, 2, 162, 224, 205, 152, 69, 128, 162, 87, 10, 160, 38, 36, 59, 72, 118, 204, 166, 236, 102, 149, 44, 13, 60, 187, 63, 83, 19, 49, 253, 110, 147, 55, 20, 172, 83, 120, 0, 177, 96, 25, 49, 154, 37, 135, 8, 145, 124, 182, 7, 13, 47, 170, 118, 175, 60, 131, 98, 0, 128, 43, 58, 251, 84, 47, 10, 77, 140, 175, 223, 52, 132, 221, 193, 62, 191, 80, 150, 188, 62, 194, 149, 9, 145, 250, 79, 199, 24, 233, 21, 13, 55, 35, 212, 59, 6, 124, 64, 93, 67, 61, 98, 219, 129, 3, 163, 178, 107, 8, 173, 253, 110, 79, 175, 255, 253, 215, 170, 129, 49, 148, 31, 58, 203, 79, 101, 113, 18, 123, 212, 29, 2, 174, 8, 1, 14, 232, 64, 95, 205, 2, 18, 64, 181, 240, 112, 39, 155, 254, 68, 182, 53, 203, 108, 109, 215, 168, 12, 186, 184, 4, 45, 21, 222, 54, 155, 212, 64, 96, 186, 246, 162, 161, 32, 68, 205, 3, 240, 2, 207, 218, 168, 147, 50, 219, 208, 252, 74, 112, 131, 200, 28, 86, 42, 228, 62, 6, 128, 202, 234, 205, 32, 102, 143, 154, 128, 165, 77, 208, 44, 20, 134, 200, 75, 221, 112, 218, 178, 194, 170, 245, 151, 185, 16, 201, 98, 209, 37, 129, 168, 175, 23, 99, 72, 251, 40, 217, 139, 209, 131, 185, 222, 232, 197, 152, 198, 147, 33, 226, 225, 66, 211, 51, 150, 105, 103, 241, 27, 44, 236, 24, 170, 51, 142, 222, 8, 157, 106, 232, 145, 236, 170, 1, 17, 89, 91, 216, 40, 238, 187, 81, 30, 53, 51, 146, 206, 232, 142, 62, 189, 71, 145, 64, 40, 244, 96, 92, 51, 186, 135, 165, 172, 17, 180, 165, 204, 104, 232, 84, 147, 125, 49, 217, 183, 133, 14, 208, 208, 207, 195, 139, 234, 193, 139, 16, 25, 22, 131, 233, 222, 232, 97, 177, 245, 73, 225, 134, 164, 24, 121, 190, 150, 229, 85, 177, 235, 82, 164, 96, 175, 62, 105, 247, 93, 3, 84, 254, 101, 226, 65, 71, 70, 161, 190, 127, 111, 31, 239, 186, 185, 119, 191, 66, 238, 32, 58, 187, 136, 8, 3, 210, 127, 197, 17, 70, 225, 84, 248, 206, 18, 94, 163, 26, 93, 105, 96, 217, 210, 142, 12, 14, 91, 182, 61, 62, 208, 0, 91, 118, 195, 221, 38, 127, 81, 166, 106, 206, 141, 43, 191, 27, 205, 130, 156, 33, 135, 135, 38, 245, 222, 64, 39, 162, 70, 239, 152, 249, 105, 249, 4, 200, 130, 77, 65, 132, 230, 174, 163, 227, 57, 235, 106, 198, 186, 163, 244, 173, 248, 45, 238, 86, 108, 215, 100, 243, 114, 57, 125, 203, 135, 227, 122, 201, 247, 100, 19, 206, 13, 5, 29, 116, 117, 80, 19, 19, 112, 63, 63, 235, 42, 57, 7, 19, 253, 206, 106, 4, 143, 78, 61, 244, 217, 71, 252, 226, 229, 130, 205, 45, 254, 194, 233, 40, 250, 208, 32, 163, 106, 241, 161, 218, 23, 238, 94, 126, 208, 142, 223, 231, 43, 103, 178, 149, 172, 62, 33, 0, 198, 45, 197, 208, 157, 106, 21, 40, 88, 9, 211, 112, 8, 130, 246, 234, 102, 193, 185, 158, 176, 61, 40, 85, 16, 39, 238, 25, 205, 29, 100, 166, 5, 109, 34, 165, 187, 210, 36, 190, 170, 57, 243, 144, 157, 243, 24, 251, 95, 239, 23, 46, 149, 164, 179, 147, 231, 141, 111, 223, 3, 48, 175, 187, 172, 182, 225, 98, 187, 98, 180, 154, 99, 207, 38, 79, 233, 142, 163, 171, 59, 63, 151, 235, 70, 63, 32, 110, 112, 210, 11, 31, 221, 250, 245, 142, 90, 123, 8, 207, 96, 97, 29, 1, 178, 16, 151, 21, 132, 34, 19, 170, 74, 136, 70, 75, 164, 117, 97, 7, 209, 49, 64, 39, 67, 211, 233, 201, 255, 147, 85, 141, 238, 60, 253, 3, 26, 62, 66, 50, 69, 64, 4, 218, 89, 154, 254, 54, 24, 27, 136, 127, 254, 10, 77, 5, 60, 74, 116, 36, 4, 98, 129, 167, 228, 134, 187, 106, 250, 136, 174, 45, 180, 102, 38, 209, 246, 192, 231, 164, 95, 56, 74, 228, 22, 67, 141, 36, 124, 53, 192, 99, 254, 21, 110, 116, 72, 112, 231, 100, 195, 39, 222, 90, 212, 189, 174, 78, 220, 228, 36, 54, 54, 138, 230, 117, 22, 228, 24, 146, 90, 182, 180, 37, 142, 173, 194, 115, 146, 236, 192, 82, 132, 141, 5, 126, 82, 203, 70, 33, 147, 197, 234, 90, 205, 200, 180, 161, 34, 90, 156, 99, 108, 181, 185, 244, 105, 182, 12, 152, 53, 171, 149, 41, 243, 158, 153, 243, 14, 38, 161, 177, 181, 33, 27, 15, 194, 135, 20, 31, 156, 61, 53, 84, 209, 146, 179, 83, 178, 160, 170, 46, 15, 101, 178, 94, 60, 43, 22, 149, 141, 49, 199, 172, 178, 186, 23, 138, 173, 41, 244, 95, 129, 232, 165, 232, 32, 172, 45, 78, 227, 148, 56, 20, 163, 106, 35, 236, 99, 73, 132, 19, 138, 182, 171, 73, 185, 246, 99, 11, 62, 190, 255, 149, 83, 20, 37, 93, 203, 233, 83, 224, 94, 153, 149, 224, 4, 209, 138, 204, 161, 38, 50, 79, 187, 219, 29, 201, 189, 191, 107, 171, 0, 6, 23, 119, 144, 217, 146, 27, 249, 243, 234, 22, 146, 198, 248, 99, 200, 164, 120, 12, 147, 174, 101, 88, 248, 180, 111, 219, 38, 236, 203, 74, 76, 14, 73, 204, 131, 220, 92, 255, 176, 63, 133, 157, 99, 165, 237, 108, 195, 247, 104, 180, 228, 0, 128, 47, 135, 74, 184, 226, 134, 106, 118, 36, 34, 95, 80, 243, 17, 191, 4, 68, 48, 19, 28, 227, 232, 85, 147, 24, 173, 54, 20, 138, 240, 105, 203, 133, 145, 20, 134, 169, 85, 21, 168, 214, 136, 206, 46, 18, 85, 191, 167, 15, 255, 182, 60, 63, 93, 42, 61, 47, 22, 18, 82, 120, 223, 24, 50, 136, 141, 218, 227, 228, 120, 171, 49, 221, 134, 68, 222, 222, 123, 72, 17, 112, 23, 183, 227, 200, 170, 121, 13, 251, 113, 0, 184, 12, 128, 123, 75, 103, 100, 200, 161, 51, 255, 63, 83, 237, 198, 191, 117, 144, 109, 212, 34, 220, 180, 68, 69, 137, 55, 96, 216, 89, 42, 186, 104, 144, 227, 5, 102, 170, 118, 161, 133, 41, 227, 25, 244, 127, 249, 252, 132, 81, 115, 107, 59, 151, 158, 71, 69, 36, 52, 236, 254, 120, 107, 3, 100, 8, 25, 64, 174, 6, 71, 203, 11, 43, 43, 79, 75, 55, 50, 190, 208, 109, 48, 185, 253, 105, 126, 25, 1, 9, 136, 131, 150, 92, 200, 64, 154, 187, 74, 55, 167, 21, 65, 218, 202, 181, 65, 28, 213, 40, 105, 129, 212, 54, 141, 205, 106, 110, 71, 68, 109, 21, 73, 201, 173, 56, 193, 154, 144, 174, 152, 3, 81, 195, 27, 100, 231, 16, 28, 217, 11, 186, 123, 79, 149, 180, 167, 126, 93, 206, 180, 33, 45, 178, 250, 52, 96, 242, 26, 96, 128, 119, 128, 5, 24, 142, 156, 173, 159, 47, 97, 153, 16, 102, 86, 217, 161, 236, 39, 99, 33, 255, 206, 150, 165, 247, 136, 45, 175, 175, 211, 130, 174, 3, 21, 95, 41, 216, 230, 109, 168, 48, 10, 48, 97, 87, 201, 3, 221, 206, 15, 59, 6, 33, 88, 107, 115, 33, 0, 90, 170, 162, 68, 98, 150, 102, 85, 114, 79, 125, 72, 153, 218, 188, 221, 145, 206, 165, 157, 136, 96, 46, 175, 41, 99, 190, 46, 249, 224, 131, 82, 125, 229, 129, 156, 152, 248, 100, 215, 64, 40, 64, 98, 75, 249, 120, 171, 74, 65, 160, 210, 0, 215, 248, 207, 129, 148, 171, 192, 96, 79, 35, 196, 165, 232, 4, 48, 107, 145, 31, 1, 64, 145, 143, 235, 75, 43, 122, 197, 193, 97, 73, 13, 142, 36, 62, 34, 109, 47, 161, 122, 207, 184, 192, 76, 110, 210, 142, 195, 205, 178, 136, 233, 41, 184, 135, 53, 251, 69, 167, 206, 247, 16, 95, 116, 70, 225, 177, 113, 197, 94, 21, 252, 105, 245, 235, 93, 100, 226, 11, 254, 224, 214, 107, 187, 133, 152, 220, 200, 234, 237, 64, 252, 25, 76, 96, 58, 80, 201, 68, 154, 131, 141, 202, 221, 199, 26, 186, 87, 110, 199, 201, 251, 60, 170, 68, 240, 6, 15, 122, 149, 213, 110, 94, 246, 11, 50, 31, 170, 9, 3, 4, 148, 132, 9, 73, 147, 39, 120, 106, 52, 35, 73, 2, 226, 214, 68, 214, 228, 91, 4, 31, 196, 39, 129, 78, 61, 170, 247, 220, 136, 233, 67, 80, 154, 115, 140, 149, 159, 250, 208, 22, 26, 152, 199, 195, 240, 163, 80, 78, 92, 97, 238, 106, 145, 105, 18, 191, 108, 86, 197, 194, 227, 157, 51, 127, 25, 178, 11, 56, 114, 15, 102, 78, 165, 59, 53, 200, 28, 206, 141, 235, 10, 61, 154, 192, 58, 228, 132, 135, 241, 19, 116, 114, 185, 103, 210, 146, 117, 162, 19, 163, 244, 251, 123, 194, 164, 19, 209, 218, 105, 158, 87, 242, 132, 219, 4, 188, 104, 0, 219, 95, 47, 151, 15, 115, 87, 217, 218, 124, 220, 237, 40, 45, 188, 241, 81, 110, 249, 17, 69, 70, 13, 230, 76, 68, 26, 118, 147, 250, 254, 76, 195, 46, 65, 79, 181, 24, 145, 125, 55, 49, 109, 57, 171, 53, 45, 93, 198, 139, 254, 229, 160, 116, 221, 4, 20, 22, 202, 4, 87, 64, 235, 68, 180, 214, 192, 169, 224, 96, 104, 250, 56, 49, 87, 70, 38, 239, 58, 124, 27, 69, 83, 232, 127, 154, 42, 186, 53, 91, 76, 129, 202, 72, 209, 197, 182, 57, 64, 2, 34, 82, 214, 42, 126, 198, 202, 222, 241, 87, 230, 6, 162, 158, 199, 39, 215, 119, 83, 72, 172, 176, 208, 204, 67, 174, 212, 153, 70, 2, 150, 162, 175, 242, 13, 170, 143, 4, 45, 96, 44, 190, 62, 148, 184, 239, 234, 134, 116, 239, 63, 195, 15, 136, 12, 238, 69, 18, 46, 22, 59, 104, 212, 202, 66, 185, 44, 68, 55, 85, 29, 82, 181, 184, 183, 61, 200, 152, 103, 13, 82, 236, 12, 213, 158, 205, 33, 177, 139, 117, 206, 105, 78, 80, 153, 27, 222, 169, 37, 112, 79, 99, 182, 217, 35, 9, 210, 28, 241, 196, 236, 51, 104, 208, 247, 74, 118, 216, 247, 107, 182, 56, 105, 185, 131, 225, 2, 58, 80, 59, 75, 218, 52, 166, 17, 52, 0, 149, 191, 153, 67, 56, 164, 10, 169, 247, 143, 175, 203, 160, 41, 77, 251, 166, 119, 153, 146, 101, 149, 130, 22, 23, 89, 95, 128, 254, 130, 30, 100, 28, 164, 202, 224, 231, 167, 170, 9, 101, 210, 211, 144, 16, 83, 146, 204, 101, 168, 56, 133, 169, 168, 7, 65, 46, 224, 177, 28, 233, 43, 7, 27, 93, 58, 239, 75, 237, 14, 197, 213, 232, 57, 30, 39, 211, 248, 243, 192, 246, 85, 190, 64, 231, 7, 136, 60, 10, 67, 168, 185, 128, 60, 77, 210, 235, 211, 123, 24, 55, 66, 163, 201, 141, 30, 212, 130, 125, 171, 104, 57, 254, 60, 106, 25, 41, 109, 172, 195, 46, 50, 183, 222, 15, 55, 171, 47, 79, 1, 40, 32, 241, 140, 103, 13, 70, 187, 151, 50, 192, 125, 54, 108, 98, 39, 134, 10, 211, 94, 62, 198, 206, 100, 58, 220, 107, 30, 237, 113, 236, 157, 202, 244, 132, 239, 246, 147, 248, 166, 249, 79, 251, 123, 198, 203, 207, 46, 147, 37, 200, 158, 18, 237, 175, 91, 12, 225, 179, 140, 145, 84, 137, 5, 34, 56, 36, 102, 199, 89, 101, 225, 185, 38, 200, 1, 251, 73, 98, 211, 137, 135, 22, 32, 241, 144, 245, 142, 106, 22, 158, 105, 45, 192, 109, 25, 249, 251, 42, 206, 58, 20, 71, 169, 175, 96, 37, 147, 146, 34, 56, 220, 19, 137, 142, 151, 49, 174, 177, 103, 143, 251, 245, 165, 93, 105, 122, 52, 78, 57, 65, 25, 21, 241, 1, 29, 31, 228, 250, 89, 49, 51, 171, 21, 155, 92, 201, 1, 143, 132, 91, 124, 192, 40, 59, 79, 10, 185, 189, 76, 188, 123, 120, 181, 78, 208, 139, 217, 222, 121, 208, 224, 212, 175, 25, 202, 29, 122, 175, 168, 211, 52, 146, 3, 4, 50, 37, 161, 159, 183, 223, 7, 181, 180, 190, 147, 118, 119, 120, 81, 27, 132, 2, 111, 182, 81, 192, 95, 145, 229, 95, 61, 242, 51, 208, 5, 152, 207, 221, 165, 180, 219, 71, 50, 248, 72, 250, 38, 118, 202, 190, 235, 60, 250, 243, 163, 217, 101, 132, 31, 163, 89, 1, 1, 8, 14, 148, 100, 176, 29, 187, 10, 154, 87, 253, 143, 209, 162, 216, 130, 91, 237, 29, 187, 250, 150, 193, 67, 80, 165, 163, 148, 91, 54, 17, 187, 179, 154, 233, 234, 41, 185, 102, 176, 132, 48, 233, 133, 97, 229, 68, 142, 131, 90, 239, 63, 224, 150, 164, 91, 24, 251, 33, 18, 135, 117, 188, 154, 104, 59, 129, 88, 186, 141, 130, 165, 198, 149, 66, 110, 201, 20, 104, 195, 30, 7, 22, 66, 9, 32, 73, 120, 168, 127, 28, 58, 171, 103, 164, 57, 173, 10, 182, 125, 27, 169, 15, 97, 200, 167, 41, 187, 184, 13, 181, 176, 77, 43, 242, 232, 131, 252, 98, 84, 67, 254, 210, 240, 183, 232, 132, 16, 253, 129, 155, 236, 170, 13, 42, 244, 88, 86, 150, 60, 103, 59, 214, 240, 75, 20, 46, 9, 212, 71, 63, 66, 64, 135, 240, 67, 72, 253, 112, 73, 152, 250, 231, 142, 192, 149, 23, 137, 14, 115, 60, 135, 29, 134, 12, 4, 154, 86, 47, 7, 122, 51, 134, 249, 28, 222, 227, 191, 224, 107, 151, 157, 4, 200, 161, 131, 50, 248, 55, 222, 99, 97, 171, 84, 209, 146, 75, 78, 33, 37, 129, 172, 194, 235, 181, 248, 146, 127, 66, 72, 189, 59, 77, 211, 157, 5, 241, 113, 111, 47, 185, 24, 142, 240, 212, 125, 96, 166, 132, 16, 57, 30, 83, 164, 63, 243, 225, 56, 62, 87, 111, 75, 134, 154, 175, 213, 41, 186, 116, 42, 51, 144, 94, 22, 179, 252, 103, 231, 125, 45, 235, 218, 57, 232, 207, 132, 2, 221, 118, 176, 232, 181, 222, 247, 46, 2, 49, 120, 174, 47, 206, 38, 148, 117, 106, 135, 201, 193, 118, 63, 253, 24, 133, 69, 133, 95, 1, 152, 35, 6, 109, 234, 25, 183, 59, 113, 192, 238, 0, 112, 154, 30, 61, 167, 240, 75, 65, 75, 158, 162, 45, 38, 104, 227, 120, 194, 159, 141, 220, 187, 60, 121, 227, 233, 192, 197, 207, 249, 183, 20, 57, 3, 235, 71, 88, 146, 178, 101, 78, 32, 20, 255, 17, 95, 139, 112, 195, 73, 69, 86, 224, 21, 157, 86, 30, 42, 152, 188, 77, 191, 35, 212, 42, 88, 107, 162, 186, 102, 98, 48, 110, 179, 174, 198, 123, 69, 177, 169, 179, 107, 182, 249, 232, 28, 37, 193, 162, 99, 36, 171, 32, 27, 152, 97, 167, 55, 141, 248, 67, 133, 152, 125, 113, 68, 183, 139, 232, 96, 196, 91, 47, 104, 109, 249, 128, 171, 19, 153, 23, 113, 142, 191, 90, 146, 188, 161, 112, 31, 110, 31, 50, 65, 137, 55, 10, 44, 234, 57, 112, 194, 39, 71, 112, 115, 56, 177, 158, 35, 190, 153, 119, 97, 128, 72, 38, 252, 67, 27, 130, 18, 68, 149, 0, 246, 236, 9, 194, 140, 219, 18, 131, 227, 224, 116, 68, 154, 140, 79, 135, 223, 154, 73, 141, 84, 179, 6, 149, 233, 48, 234, 166, 74, 8, 9, 229, 241, 33, 84, 205, 226, 241, 43, 63, 9, 70, 163, 184, 58, 204, 53, 160, 46, 248, 38, 67, 155, 157, 207, 182, 112, 171, 65, 140, 50, 174, 80, 17, 226, 178, 243, 169, 80, 130, 101, 242, 89, 137, 5, 158, 52, 16, 139, 119, 175, 210, 112, 63, 50, 53, 173, 35, 64, 13, 40, 133, 102, 197, 250, 170, 152, 13, 102, 105, 138, 61, 100, 1, 109, 248, 107, 190, 169, 15, 45, 182, 36, 236, 34, 188, 125, 44, 119, 140, 63, 87, 74, 197, 201, 85, 193, 36, 71, 152, 130, 186, 122, 10, 176, 99, 73, 241, 208, 131, 134, 210, 136, 211, 25, 77, 202, 242, 167, 189, 163, 112, 162, 132, 55, 64, 94, 113, 111, 60, 51, 100, 136, 83, 238, 135, 190, 14, 147, 201, 36, 240, 173, 37, 45, 25, 153, 71, 15, 36, 200, 0, 241, 149, 194, 180, 141, 54, 37, 17, 72, 88, 157, 107, 137, 145, 203, 178, 208, 5, 190, 112, 19, 200, 90, 152, 8, 122, 212, 172, 130, 0, 156, 83, 106, 199, 126, 53, 126, 118, 78, 142, 164, 110, 2, 51, 206, 229, 115, 164, 191, 188, 96, 242, 143, 76, 210, 19, 63, 160, 210, 53, 167, 191, 74, 137, 36, 107, 94, 236, 129, 24, 128, 42, 156, 72, 104, 220, 101, 196, 198, 173, 191, 235, 202, 210, 187, 143, 3, 222, 146, 109, 142, 94, 19, 176, 150, 161, 146, 14, 191, 77, 100, 101, 96, 10, 249, 193, 34, 40, 141, 99, 39, 170, 25, 64, 196, 228, 160, 7, 219, 209, 252, 9, 114, 137, 126, 157, 36, 124, 50, 106, 130, 138, 182, 166, 54, 251, 227, 157, 200, 78, 225, 82, 14, 233, 140, 69, 26, 10, 67, 15, 41, 109, 11, 178, 125, 76, 165, 155, 68, 205, 194, 3, 146, 142, 85, 112, 3, 191, 97, 46, 210, 36, 135, 216, 160, 164, 87, 223, 136, 242, 110, 0, 138, 113, 115, 3, 255, 95, 124, 195, 237, 171, 192, 244, 168, 74, 174, 184, 181, 149, 17, 63, 111, 106, 173, 221, 66, 203, 120, 137, 222, 69, 236, 124, 226, 216, 137, 75, 217, 128, 79, 121, 189, 237, 116, 142, 247, 17, 9, 193, 66, 160, 232, 27, 85, 174, 153, 198, 4, 238, 28, 199, 138, 28, 204, 64, 178, 151, 43, 24, 208, 179, 88, 149, 94, 59, 255, 108, 237, 122, 86, 199, 172, 246, 24, 3, 13, 144, 84, 140, 207, 186, 6, 112, 201, 69, 44, 94, 160, 76, 155, 125, 146, 24, 254, 41, 12, 126, 175, 32, 241, 112, 251, 221, 52, 2, 96, 153, 128, 81, 191, 167, 233, 101, 20, 22, 49, 15, 235, 228, 193, 200, 48, 165, 179, 192, 154, 192, 52, 56, 235, 8, 216, 21, 72, 50, 4, 173, 34, 50, 135, 19, 114, 142, 54, 97, 247, 23, 218, 64, 223, 120, 196, 97, 37, 123, 214, 227, 245, 42, 110, 7, 225, 122, 146, 39, 159, 151, 108, 229, 130, 237, 169, 6, 61, 178, 237, 105, 121, 90, 22, 228, 249, 12, 29, 143, 207, 179, 52, 17, 163, 169, 120, 149, 242, 51, 36, 236, 95, 194, 26, 35, 226, 224, 47, 203, 138, 159, 183, 208, 41, 20, 130, 86, 9, 99, 131, 192, 175, 123, 54, 43, 120, 190, 0, 203, 178, 80, 119, 181, 39, 159, 210, 140, 147, 69, 24, 220, 168, 50, 255, 51, 34, 123, 141, 167, 160, 138, 67, 189, 206, 207, 230, 193, 95, 190, 161, 33, 231, 80, 77, 15, 134, 216, 33, 208, 235, 88, 131, 41, 146, 214, 30, 229, 220, 248, 114, 132, 10, 175, 38, 124, 55, 160, 172, 152, 37, 64, 124, 29, 233, 63, 1, 36, 239, 231, 54, 4, 79, 48, 109, 203, 128, 130, 25, 64, 83, 151, 227, 15, 226, 78, 8, 14, 117, 100, 58, 192, 243, 65, 6, 69, 88, 196, 180, 11, 140, 127, 182, 74, 187, 24, 156, 129, 20, 88, 212, 145, 235, 158, 107, 37, 39, 141, 1, 10, 112, 244, 25, 209, 37, 187, 30, 130, 177, 141, 161, 170, 129, 255, 139, 111, 40, 20, 61, 23, 60, 17, 104, 35, 134, 120, 241, 132, 25, 171, 119, 184, 22, 56, 66, 79, 153, 9, 78, 173, 9, 108, 93, 75, 177, 0, 250, 15, 254, 84, 67, 40, 99, 19, 171, 110, 3, 229, 22, 164, 144, 0, 220, 23, 98, 161, 224, 118, 52, 129, 201, 15, 164, 180, 156, 217, 139, 213, 108, 43, 61, 36, 218, 200, 85, 54, 157, 11, 47, 121, 6, 249, 158, 231, 22, 143, 28, 5, 82, 88, 188, 160, 250, 244, 237, 15, 63, 139, 235, 244, 224, 12, 62, 238, 177, 75, 197, 192, 225, 203, 38, 43, 197, 17, 178, 92, 224, 234, 102, 204, 83, 28, 209, 46, 156, 213, 31, 48, 32, 94, 118, 227, 27, 36, 212, 223, 0, 153, 208, 193, 156, 145, 100, 148, 119, 213, 20, 106, 96, 6, 105, 230, 182, 199, 33, 153, 118, 212, 36, 54, 80, 199, 254, 116, 202, 39, 201, 245, 163, 177, 236, 75, 159, 233, 37, 27, 37, 31, 25, 237, 65, 19, 190, 222, 251, 179, 199, 245, 147, 197, 238, 205, 48, 169, 250, 233, 174, 212, 235, 9, 115, 105, 161, 145, 199, 19, 202, 208, 98, 213, 47, 27, 53, 57, 124, 248, 12, 245, 2, 234, 80, 107, 213, 182, 5, 243, 29, 238, 192, 110, 132, 174, 114, 243, 123, 102, 119, 241, 100, 86, 27, 13, 210, 46, 7, 204, 144, 180, 223, 55, 47, 37, 126, 104, 16, 62, 109, 75, 245, 4, 128, 241, 149, 0, 125, 154, 82, 0, 146, 255, 99, 121, 57, 247, 120, 185, 201, 183, 102, 10, 66, 221, 252, 235, 33, 64, 60, 69, 250, 119, 211, 223, 118, 189, 253, 229, 194, 13, 230, 100, 111, 209, 71, 90, 217, 141, 40, 196, 171, 168, 118, 252, 16, 192, 124, 148, 41, 109, 126, 234, 85, 219, 95, 130, 167, 217, 196, 199, 231, 219, 77, 100, 190, 106, 253, 225, 180, 190, 193, 0, 76, 181, 254, 210, 241, 196, 76, 50, 158, 234, 120, 116, 136, 75, 52, 192, 192, 6, 16, 9, 0, 137, 110, 144, 246, 55, 14, 204, 135, 172, 93, 226, 121, 120, 0, 112, 2, 165, 151, 57, 160, 215, 201, 178, 237, 229, 194, 76, 145, 83, 103, 17, 121, 130, 192, 21, 116, 6, 252, 97, 219, 72, 173, 174, 227, 26, 128, 206, 197, 51, 31, 122, 29, 187, 60, 132, 168, 148, 90, 39, 219, 87, 117, 178, 210, 99, 121, 43, 116, 82, 21, 17, 135, 11, 3, 24, 117, 15, 222, 207, 206, 41, 242, 2, 150, 44, 174, 28, 218, 187, 181, 71, 196, 137, 193, 135, 105, 16, 172, 54, 143, 115, 79, 192, 207, 130, 21, 195, 213, 37, 244, 50, 82, 36, 62, 236, 31, 79, 193, 244, 166, 96, 239, 250, 238, 181, 65, 254, 193, 246, 143, 204, 94, 71, 6, 198, 168, 141, 48, 0, 228, 153, 70, 86, 4, 28, 87, 208, 182, 82, 12, 93, 32, 134, 176, 196, 176, 106, 36, 30, 166, 151, 128, 33, 89, 28, 171, 26, 120, 184, 227, 229, 5, 106, 165, 100, 57, 82, 248, 165, 3, 172, 98, 114, 235, 68, 178, 80, 228, 66, 139, 50, 107, 235, 68, 148, 115, 127, 111, 199, 8, 95, 64, 190, 243, 90, 232, 64, 0, 6, 234, 225, 143, 45, 171, 9, 242, 88, 109, 135, 246, 54, 31, 158, 46, 196, 2, 189, 147, 152, 70, 147, 170, 150, 134, 77, 87, 165, 64, 134, 254, 202, 193, 190, 200, 89, 21, 217, 241, 229, 110, 154, 16, 15, 20, 111, 112, 183, 208, 75, 146, 111, 201, 84, 41, 9, 133, 8, 7, 224, 162, 168, 20, 118, 191, 48, 134, 215, 129, 72, 223, 44, 193, 132, 2, 94, 177, 33, 166, 248, 249, 108, 16, 36, 231, 134, 245, 48, 213, 23, 155, 110, 206, 95, 77, 211, 49, 193, 95, 6, 63, 113, 52, 75, 163, 225, 78, 242, 245, 34, 153, 240, 53, 187, 224, 205, 223, 173, 78, 196, 129, 100, 150, 139, 157, 111, 145, 145, 176, 203, 100, 190, 115, 50, 94, 51, 137, 96, 175, 169, 91, 204, 155, 101, 35, 185, 68, 254, 116, 65, 85, 63, 75, 187, 28, 104, 224, 7, 117, 149, 129, 209, 50, 89, 60, 199, 215, 117, 147, 205, 225, 36, 39, 103, 69, 5, 91, 43, 115, 26, 131, 98, 217, 144, 123, 149, 82, 120, 45, 177, 229, 37, 3, 134, 3, 25, 25, 184, 6, 41, 142, 180, 82, 218, 18, 152, 89, 155, 83, 237, 55, 171, 31, 193, 37, 232, 246, 138, 105, 215, 81, 37, 35, 15, 82, 198, 146, 21, 41, 18, 128, 242, 250, 32, 56, 47, 150, 116, 193, 46, 178, 84, 7, 39, 124, 147, 132, 29, 94, 255, 48, 164, 66, 255, 9, 228, 33, 195, 122, 6, 125, 65, 113, 90, 186, 179, 51, 52, 90, 224, 112, 204, 14, 92, 37, 179, 184, 62, 169, 189, 97, 143, 199, 179, 212, 55, 196, 106, 26, 201, 36, 192, 253, 157, 170, 209, 155, 154, 2, 232, 152, 154, 107, 233, 138, 245, 110, 208, 41, 38, 7, 216, 79, 185, 21, 17, 47, 80, 0, 116, 242, 11, 247, 93, 85, 116, 81, 108, 129, 246, 103, 41, 56, 161, 39, 109, 143, 107, 157, 165, 115, 215, 33, 66, 113, 122, 49, 89, 38, 225, 162, 94, 221, 169, 44, 145, 225, 195, 233, 30, 65, 188, 17, 86, 245, 52, 185, 69, 66, 179, 210, 185, 45, 211, 134, 178, 166, 115, 53, 239, 161, 187, 176, 206, 216, 31, 191, 63, 65, 193, 192, 150, 237, 9, 132, 13, 147, 243, 87, 148, 116, 213, 205, 43, 243, 242, 188, 108, 28, 49, 65, 23, 25, 242, 67, 227, 120, 46, 124, 153, 165, 127, 29, 91, 250, 140, 65, 79, 67, 59, 49, 37, 124, 125, 245, 226, 224, 150, 193, 165, 6, 92, 189, 189, 114, 199, 239, 13, 11, 78, 42, 4, 195, 24, 115, 23, 231, 32, 232, 201, 24, 166, 12, 115, 53, 46, 6, 126, 74, 245, 144, 37, 22, 63, 36, 29, 149, 11, 229, 83, 109, 7, 78, 199, 24, 129, 204, 162, 118, 44, 133, 11, 234, 253, 12, 41, 110, 150, 188, 80, 66, 126, 144, 121, 32, 36, 237, 19, 235, 218, 50, 94, 253, 46, 25, 54, 124, 191, 67, 128, 143, 42, 200, 117, 108, 218, 112, 116, 123, 163, 187, 1, 209, 137, 24, 107, 156, 168, 193, 71, 247, 36, 117, 246, 4, 6, 51, 32, 147, 42, 170, 142, 101, 142, 216, 148, 9, 170, 154, 108, 165, 208, 106, 179, 236, 100, 17, 214, 232, 222, 145, 58, 210, 148, 100, 81, 255, 69, 8, 173, 194, 200, 56, 80, 66, 244, 90, 42, 7, 244, 123, 171, 22, 102, 1, 134, 9, 165, 208, 173, 136, 221, 156, 4, 57, 185, 34, 149, 106, 204, 21, 227, 60, 35, 1, 107, 176, 74, 109, 81, 66, 147, 172, 91, 32, 251, 21, 168, 167, 188, 93, 142, 159, 188, 16, 134, 67, 51, 137, 234, 158, 123, 112, 31, 186, 156, 160, 137, 8, 7, 202, 94, 190, 250, 24, 169, 230, 130, 232, 112, 166, 226, 153, 46, 29, 148, 108, 113, 112, 97, 103, 125, 36, 21, 119, 25, 185, 241, 35, 116, 211, 138, 35, 11, 140, 1, 50, 178, 91, 134, 31, 89, 69, 22, 53, 119, 150, 81, 48, 39, 29, 224, 77, 102, 117, 139, 139, 40, 32, 17, 153, 24, 17, 228, 35, 142, 9, 43, 147, 22, 88, 113, 121, 213, 11, 252, 157, 187, 190, 53, 201, 195, 239, 146, 244, 163, 122, 203, 41, 99, 32, 211, 30, 29, 32, 147, 13, 142, 239, 67, 44, 69, 185, 0, 18, 242, 222, 11, 86, 211, 59, 104, 196, 181, 152, 143, 248, 64, 42, 193, 1, 88, 157, 77, 37, 227, 81, 165, 213, 176, 198, 124, 178, 15, 200, 176, 131, 190, 21, 172, 146, 219, 164, 0, 168, 147, 110, 132, 1, 72, 131, 229, 128, 52, 183, 124, 198, 223, 172, 123, 135, 244, 217, 13, 246, 241, 207, 39, 149, 50, 52, 22, 206, 254, 34, 64, 200, 235, 210, 217, 43, 28, 171, 8, 111, 66, 96, 123, 29, 178, 7, 31, 150, 156, 42, 26, 16, 42, 117, 8, 157, 189, 104, 175, 27, 159, 238, 255, 232, 62, 221, 210, 8, 138, 159, 14, 199, 115, 146, 86, 143, 242, 80, 233, 9, 182, 197, 191, 70, 246, 98, 66, 216, 11, 123, 31, 236, 123, 39, 144, 67, 118, 202, 86, 217, 24, 86, 20, 21, 245, 34, 247, 186, 201, 134, 65, 169, 196, 231, 87, 152, 62, 97, 122, 38, 69, 180, 26, 81, 100, 88, 175, 203, 26, 107, 33, 209, 180, 202, 141, 4, 254, 108, 129, 190, 124, 23, 214, 130, 213, 6, 154, 17, 9, 204, 177, 47, 142, 113, 161, 125, 89, 56, 230, 112, 129, 212, 189, 164, 89, 149, 95, 107, 253, 37, 251, 80, 178, 134, 57, 230, 71, 96, 213, 74, 226, 199, 103, 45, 17, 49, 20, 141, 205, 246, 136, 236, 194, 62, 102, 23, 155, 67, 50, 74, 18, 164, 52, 20, 149, 193, 121, 75, 253, 217, 224, 74, 221, 179, 202, 11, 73, 63, 224, 175, 9, 228, 182, 51, 193, 218, 108, 140, 225, 141, 107, 243, 41, 170, 215, 184, 109, 9, 250, 187, 123, 28, 254, 94, 4, 116, 24, 65, 29, 106, 54, 71, 147, 229, 246, 248, 241, 143, 163, 219, 146, 137, 76, 6, 240, 226, 7, 207, 24, 242, 243, 108, 0, 120, 104, 189, 104, 203, 153, 201, 109, 142, 89, 214, 93, 59, 244, 210, 187, 228, 135, 156, 122, 42, 206, 6, 108, 97, 197, 137, 145, 78, 24, 76, 169, 7, 224, 221, 209, 48, 254, 29, 67, 34, 1, 144, 220, 15, 44, 109, 52, 56, 200, 150, 169, 17, 236, 11, 252, 209, 36, 155, 147, 36, 4, 48, 13, 172, 29, 178, 65, 206, 117, 58, 7, 228, 239, 210, 196, 79, 68, 219, 165, 174, 169, 132, 212, 11, 236, 243, 130, 195, 118, 57, 109, 137, 186, 208, 62, 202, 14, 138, 60, 6, 86, 116, 129, 172, 242, 27, 156, 14, 184, 68, 81, 3, 60, 124, 98, 214, 22, 50, 47, 218, 125, 181, 77, 125, 0, 170, 53, 202, 202, 10, 227, 211, 167, 32, 230, 102, 65, 188, 80, 246, 42, 143, 48, 167, 17, 129, 248, 5, 195, 134, 79, 251, 148, 55, 84, 215, 101, 73, 52, 134, 60, 65, 211, 14, 226, 131, 243, 136, 83, 3, 246, 249, 130, 137, 71, 141, 252, 152, 45, 20, 92, 102, 248, 223, 50, 149, 86, 214, 191, 107, 178, 14, 96, 1, 120, 84, 109, 65, 165, 46, 172, 166, 91, 6, 51, 72, 123, 128, 169, 104, 194, 53, 154, 63, 122, 16, 111, 220, 253, 113, 207, 131, 236, 170, 248, 16, 176, 189, 9, 234, 126, 78, 210, 169, 162, 105, 229, 138, 179, 56, 233, 48, 51, 170, 188, 215, 233, 186, 17, 19, 54, 209, 203, 75, 93, 158, 198, 58, 10, 120, 51, 52, 244, 55, 117, 188, 177, 145, 41, 173, 98, 110, 28, 82, 244, 141, 60, 198, 80, 174, 246, 95, 120, 176, 247, 149, 91, 22, 218, 94, 113, 108, 250, 0, 200, 17, 127, 144, 206, 107, 9, 139, 229, 206, 233, 44, 253, 100, 155, 142, 72, 20, 150, 157, 254, 144, 236, 79, 219, 34, 174, 104, 14, 217, 193, 249, 59, 28, 238, 207, 106, 39, 25, 6, 75, 32, 88, 124, 158, 34, 98, 60, 34, 172, 35, 163, 216, 134, 111, 198, 166, 120, 55, 109, 118, 250, 86, 31, 6, 27, 5, 81, 182, 187, 226, 162, 43, 80, 61, 35, 235, 128, 28, 113, 172, 157, 225, 69, 2, 9, 94, 11, 117, 103, 40, 189, 236, 131, 75, 136, 12, 60, 112, 66, 159, 208, 178, 200, 175, 37, 221, 225, 97, 130, 113, 237, 120, 69, 149, 8, 155, 10, 107, 183, 247, 75, 108, 165, 119, 121, 133, 46, 35, 11, 18, 187, 5, 5, 39, 102, 199, 163, 159, 112, 58, 19, 229, 72, 185, 188, 120, 198, 252, 213, 139, 39, 68, 33, 139, 255, 218, 14, 229, 156, 23, 2, 129, 169, 220, 13, 222, 23, 70, 251, 1, 107, 81, 145, 11, 38, 185, 108, 225, 133, 15, 27, 180, 3, 187, 138, 129, 132, 234, 199, 28, 42, 194, 246, 31, 201, 124, 189, 160, 217, 209, 19, 53, 204, 200, 181, 194, 21, 167, 142, 223, 241, 81, 154, 28, 68, 151, 41, 188, 90, 32, 208, 162, 247, 39, 43, 139, 64, 145, 170, 245, 56, 218, 102, 166, 86, 207, 54, 225, 132, 151, 208, 125, 147, 204, 124, 175, 67, 44, 11, 6, 181, 230, 51, 96, 122, 30, 212, 136, 225, 105, 213, 108, 166, 37, 42, 88, 184, 90, 67, 184, 20, 126, 83, 127, 162, 165, 72, 147, 219, 30, 23, 12, 215, 100, 101, 172, 87, 108, 46, 154, 157, 227, 2, 164, 46, 254, 50, 176, 155, 39, 230, 243, 36, 169, 17, 141, 100, 223, 68, 212, 200, 144, 43, 37, 154, 252, 70, 211, 122, 69, 94, 74, 12, 36, 224, 193, 39, 66, 245, 15, 17, 157, 254, 38, 162, 51, 11, 213, 115, 116, 216, 206, 23, 14, 4, 204, 128, 247, 192, 199, 20, 33, 169, 194, 117, 231, 31, 18, 195, 225, 185, 58, 38, 196, 57, 23, 197, 112, 17, 115, 45, 120, 250, 109, 147, 116, 133, 129, 68, 170, 73, 60, 59, 74, 182, 18, 194, 225, 75, 250, 59, 172, 155, 228, 238, 214, 181, 73, 27, 154, 238, 125, 224, 1, 9, 211, 145, 28, 144, 69, 8, 102, 12, 121, 73, 180, 146, 61, 226, 64, 85, 22, 154, 109, 141, 56, 68, 61, 65, 61, 26, 41, 33, 18, 19, 12, 237, 175, 159, 130, 7, 80, 17, 176, 104, 146, 7, 178, 13, 131, 14, 17, 142, 41, 100, 171, 214, 92, 131, 187, 184, 77, 39, 17, 46, 24, 143, 4, 142, 146, 225, 225, 143, 131, 95, 65, 127, 64, 58, 87, 205, 141, 120, 246, 189, 17, 0, 252, 254, 231, 37, 76, 71, 7, 171, 92, 227, 247, 196, 133, 212, 211, 20, 103, 109, 4, 77, 56, 62, 60, 99, 230, 55, 65, 145, 126, 163, 198, 85, 187, 241, 95, 118, 132, 34, 20, 234, 153, 211, 108, 192, 144, 104, 112, 18, 131, 232, 80, 180, 202, 178, 238, 64, 228, 35, 250, 236, 188, 178, 67, 140, 158, 187, 164, 18, 188, 27, 249, 67, 94, 155, 71, 3, 196, 103, 222, 127, 153, 23, 112, 252, 55, 113, 197, 22, 31, 84, 186, 253, 218, 242, 39, 232, 116, 246, 142, 219, 140, 107, 85, 10, 226, 137, 151, 115, 242, 6, 166, 179, 68, 47, 80, 100, 148, 160, 101, 219, 89, 28, 125, 180, 28, 232, 26, 227, 234, 141, 225, 82, 223, 106, 109, 0, 7, 225, 135, 41, 193, 96, 43, 242, 206, 192, 50, 110, 39, 187, 177, 241, 184, 80, 41, 163, 147, 130, 55, 99, 218, 9, 192, 169, 157, 127, 22, 129, 220, 254, 30, 118, 32, 49, 76, 232, 255, 194, 113, 153, 79, 137, 156, 100, 13, 162, 96, 155, 105, 176, 159, 113, 21, 120, 210, 200, 53, 145, 169, 55, 212, 244, 24, 26, 113, 70, 57, 17, 203, 202, 143, 148, 190, 118, 22, 76, 226, 58, 92, 23, 33, 110, 6, 2, 96, 3, 103, 223, 131, 219, 102, 135, 43, 20, 124, 179, 65, 100, 236, 109, 117, 39, 199, 101, 238, 202, 5, 103, 167, 137, 30, 164, 154, 214, 200, 89, 146, 147, 158, 76, 170, 105, 183, 73, 208, 65, 188, 51, 85, 213, 232, 30, 207, 144, 53, 18, 106, 3, 54, 209, 3, 209, 104, 173, 123, 183, 62, 46, 245, 90, 172, 157, 181, 117, 252, 125, 72, 11, 42, 234, 98, 214, 80, 46, 143, 44, 122, 31, 193, 78, 109, 225, 129, 148, 217, 190, 20, 206, 141, 129, 149, 225, 204, 69, 43, 34, 195, 123, 252, 54, 114, 155, 71, 159, 44, 209, 10, 220, 246, 70, 192, 122, 105, 15, 113, 214, 224, 80, 144, 33, 215, 60, 214, 119, 84, 6, 168, 152, 201, 202, 51, 52, 8, 199, 131, 153, 253, 213, 152, 218, 167, 206, 92, 32, 169, 53, 219, 212, 166, 121, 198, 131, 95, 146, 229, 11, 146, 43, 112, 224, 134, 189, 110, 216, 90, 32, 228, 85, 83, 91, 184, 229, 244, 177, 178, 247, 168, 28, 196, 178, 243, 100, 34, 128, 106, 232, 218, 219, 215, 216, 87, 186, 192, 46, 111, 102, 111, 27, 70, 229, 233, 246, 144, 64, 119, 189, 95, 211, 215, 109, 202, 86, 223, 37, 160, 104, 17, 224, 223, 126, 96, 8, 213, 44, 186, 217, 236, 116, 93, 104, 192, 212, 210, 56, 32, 101, 206, 28, 11, 6, 95, 251, 209, 232, 12, 107, 182, 231, 64, 129, 68, 65, 110, 67, 137, 133, 100, 167, 145, 36, 133, 187, 35, 43, 77, 150, 129, 198, 84, 234, 220, 170, 168, 205, 15, 132, 186, 88, 5, 78, 80, 20, 48, 103, 202, 194, 36, 21, 218, 148, 212, 103, 64, 118, 46, 214, 32, 18, 36, 93, 129, 50, 177, 201, 176, 0, 137, 192, 55, 156, 172, 226, 87, 45, 63, 240, 88, 65, 12, 121, 22, 124, 22, 8, 87, 182, 161, 180, 87, 215, 226, 144, 190, 229, 12, 123, 62, 249, 14, 177, 133, 196, 193, 37, 50, 161, 83, 156, 233, 128, 162, 167, 26, 114, 112, 95, 252, 115, 64, 243, 140, 176, 41, 220, 155, 105, 105, 47, 7, 118, 96, 244, 98, 67, 34, 145, 166, 175, 166, 231, 195, 3, 194, 35, 243, 59, 68, 24, 245, 166, 161, 234, 14, 121, 172, 1, 142, 157, 105, 246, 173, 212, 14, 11, 184, 212, 187, 133, 142, 122, 190, 165, 233, 148, 156, 126, 191, 58, 64, 91, 71, 124, 199, 40, 132, 191, 166, 93, 53, 135, 147, 224, 134, 4, 20, 135, 64, 17, 247, 11, 19, 251, 206, 75, 177, 68, 106, 131, 38, 176, 194, 169, 197, 84, 103, 75, 112, 0, 51, 34, 166, 130, 115, 183, 220, 190, 6, 169, 201, 164, 56, 14, 122, 13, 142, 166, 131, 99, 94, 57, 217, 200, 251, 86, 46, 76, 93, 20, 168, 73, 52, 72, 50, 245, 4, 60, 193, 6, 25, 120, 74, 75, 17, 229, 222, 218, 25, 28, 20, 137, 21, 127, 76, 244, 98, 205, 135, 86, 127, 151, 248, 147, 16, 168, 178, 135, 3, 192, 138, 57, 139, 1, 249, 9, 63, 12, 119, 83, 83, 3, 230, 194, 141, 249, 235, 246, 35, 92, 165, 94, 55, 251, 52, 177, 251, 236, 227, 34, 124, 60, 222, 117, 76, 167, 190, 192, 56, 200, 62, 51, 136, 114, 206, 70, 16, 187, 107, 140, 105, 142, 9, 251, 53, 236, 30, 143, 236, 169, 96, 196, 90, 0, 228, 52, 33, 88, 67, 112, 54, 27, 42, 212, 164, 241, 163, 186, 217, 107, 197, 47, 78, 21, 49, 98, 176, 227, 144, 237, 110, 43, 57, 243, 112, 97, 59, 58, 48, 174, 84, 193, 103, 140, 45, 254, 226, 179, 79, 90, 27, 16, 208, 62, 222, 107, 22, 56, 4, 219, 67, 42, 194, 142, 113, 162, 162, 224, 178, 115, 245, 128, 221, 194, 5, 13, 52, 108, 95, 54, 12, 227, 37, 130, 184, 38, 14, 136, 34, 28, 43, 132, 25, 126, 69, 79, 113, 70, 14, 153, 45, 3, 82, 233, 253, 19, 198, 26, 233, 213, 133, 180, 152, 217, 146, 2, 147, 15, 102, 45, 80, 119, 254, 163, 196, 113, 161, 125, 79, 207, 185, 88, 144, 72, 233, 21, 6, 125, 231, 23, 8, 151, 51, 152, 154, 119, 37, 130, 196, 194, 200, 151, 24, 223, 184, 25, 215, 215, 225, 224, 8, 73, 73, 244, 233, 117, 209, 217, 212, 21, 239, 114, 161, 138, 250, 248, 240, 190, 225, 219, 52, 191, 58, 232, 218, 126, 243, 50, 29, 232, 161, 156, 192, 60, 97, 177, 23, 4, 77, 58, 148, 232, 42, 140, 80, 224, 105, 9, 182, 101, 20, 14, 148, 138, 81, 64, 129, 70, 78, 236, 132, 67, 48, 227, 194, 13, 247, 154, 169, 100, 127, 12, 231, 143, 88, 23, 192, 63, 251, 4, 111, 236, 137, 71, 122, 240, 209, 166, 184, 132, 186, 10, 138, 42, 194, 197, 48, 243, 206, 219, 207, 53, 145, 24, 100, 247, 116, 128, 99, 12, 17, 173, 79, 74, 230, 170, 65, 229, 22, 108, 137, 218, 250, 133, 160, 193, 190, 195, 202, 160, 182, 236, 119, 222, 197, 25, 89, 59, 7, 59, 224, 228, 72, 91, 187, 76, 38, 156, 224, 171, 39, 35, 234, 206, 56, 34, 148, 9, 25, 224, 28, 15, 27, 35, 122, 206, 90, 66, 46, 184, 212, 69, 176, 93, 153, 12, 68, 44, 132, 116, 115, 132, 127, 77, 128, 248, 94, 123, 214, 86, 25, 86, 47, 40, 31, 180, 110, 35, 71, 78, 85, 178, 19, 28, 237, 133, 16, 183, 58, 220, 96, 117, 171, 40, 50, 59, 229, 39, 28, 162, 217, 224, 32, 50, 42, 9, 70, 69, 201, 114, 164, 18, 80, 139, 255, 12, 245, 214, 198, 186, 114, 109, 51, 40, 154, 173, 3, 56, 42, 252, 194, 21, 152, 99, 162, 139, 72, 74, 98, 10, 125, 57, 135, 125, 139, 184, 107, 91, 35, 105, 149, 170, 103, 45, 255, 52, 194, 232, 8, 79, 53, 215, 232, 147, 106, 193, 160, 171, 218, 107, 175, 146, 147, 58, 199, 14, 166, 56, 84, 245, 182, 133, 210, 141, 140, 145, 67, 39, 37, 81, 74, 50, 123, 175, 65, 108, 69, 184, 119, 111, 5, 220, 228, 215, 25, 152, 25, 193, 88, 112, 245, 131, 166, 241, 56, 25, 85, 116, 252, 118, 31, 45, 31, 57, 135, 25, 184, 240, 3, 165, 102, 184, 14, 203, 151, 32, 185, 137, 174, 228, 208, 147, 42, 192, 72, 194, 112, 51, 3, 58, 202, 143, 171, 116, 63, 28, 200, 1, 21, 28, 132, 83, 66, 47, 117, 147, 113, 37, 106, 80, 118, 217, 100, 229, 126, 182, 183, 183, 81, 65, 33, 181, 235, 223, 130, 118, 54, 177, 90, 10, 187, 200, 6, 102, 189, 93, 76, 254, 55, 69, 103, 130, 201, 57, 98, 207, 5, 152, 231, 64, 101, 0, 222, 78, 244, 13, 38, 248, 63, 163, 31, 175, 155, 203, 77, 249, 24, 139, 52, 224, 68, 199, 157, 103, 40, 131, 224, 242, 137, 225, 181, 131, 29, 128, 229, 242, 92, 42, 58, 85, 101, 69, 120, 167, 86, 99, 57, 220, 94, 231, 162, 99, 132, 221, 55, 37, 174, 194, 195, 194, 178, 232, 61, 38, 66, 42, 168, 182, 23, 106, 241, 198, 192, 217, 215, 50, 59, 225, 217, 8, 24, 147, 240, 54, 209, 158, 154, 47, 7, 212, 225, 38, 19, 4, 241, 170, 42, 2, 107, 13, 240, 77, 158, 228, 103, 237, 64, 173, 177, 143, 48, 208, 217, 140, 31, 108, 229, 140, 70, 10, 51, 122, 64, 75, 12, 145, 211, 165, 169, 145, 240, 228, 255, 115, 84, 244, 84, 125, 231, 86, 8, 52, 248, 112, 145, 221, 45, 53, 9, 92, 53, 66, 180, 172, 242, 22, 113, 106, 211, 138, 42, 63, 66, 178, 2, 160, 86, 191, 169, 237, 86, 87, 70, 78, 62, 1, 213, 97, 167, 104, 63, 60, 222, 61, 77, 55, 70, 198, 23, 8, 135, 250, 188, 93, 66, 134, 227, 192, 20, 182, 81, 129, 108, 60, 88, 141, 93, 205, 132, 52, 179, 95, 168, 181, 39, 38, 7, 206, 107, 214, 181, 101, 190, 56, 89, 60, 178, 166, 107, 99, 154, 3, 129, 39, 242, 99, 206, 124, 171, 178, 132, 138, 177, 200, 26, 11, 83, 208, 126, 142, 130, 38, 169, 82, 225, 242, 213, 101, 234, 176, 14, 229, 79, 19, 58, 72, 4, 201, 238, 77, 94, 151, 153, 10, 128, 254, 183, 134, 62, 42, 170, 39, 226, 231, 213, 223, 31, 74, 61, 94, 199, 136, 181, 153, 45, 48, 157, 50, 0, 60, 251, 155, 235, 37, 42, 168, 203, 8, 246, 116, 56, 66, 99, 34, 92, 170, 73, 29, 32, 185, 65, 23, 178, 124, 2, 254, 140, 196, 162, 33, 208, 190, 145, 237, 96, 137, 104, 94, 114, 2, 37, 83, 2, 59, 241, 115, 1, 208, 157, 193, 165, 118, 17, 156, 91, 135, 158, 192, 108, 229, 212, 236, 9, 28, 232, 75, 152, 109, 156, 152, 207, 180, 242, 34, 100, 12, 112, 243, 72, 166, 219, 31, 150, 89, 73, 243, 4, 219, 157, 46, 75, 247, 234, 143, 10, 88, 150, 67, 124, 219, 10, 6, 26, 15, 78, 177, 77, 114, 221, 121, 214, 54, 107, 254, 196, 239, 216, 168, 230, 230, 28, 94, 69, 11, 67, 161, 37, 39, 191, 18, 246, 116, 211, 14, 236, 250, 100, 23, 87, 174, 118, 164, 193, 229, 87, 38, 151, 122, 79, 217, 111, 231, 135, 82, 222, 183, 14, 208, 217, 233, 1, 121, 21, 121, 251, 162, 112, 186, 24, 65, 154, 7, 50, 186, 246, 24, 173, 198, 186, 89, 38, 117, 87, 26, 10, 94, 50, 193, 16, 135, 68, 167, 148, 251, 144, 115, 60, 48, 28, 187, 104, 161, 255, 192, 223, 214, 21, 143, 212, 214, 194, 44, 128, 162, 174, 96, 166, 91, 17, 247, 83, 230, 57, 106, 16, 104, 142, 57, 78, 235, 132, 164, 183, 174, 244, 56, 103, 113, 118, 96, 65, 40, 163, 7, 30, 134, 159, 76, 247, 31, 213, 30, 211, 203, 74, 188, 201, 38, 148, 123, 234, 157, 17, 192, 247, 26, 71, 201, 37, 226, 94, 89, 80, 180, 133, 94, 22, 94, 64, 39, 236, 227, 143, 163, 140, 126, 160, 125, 29, 99, 25, 56, 107, 89, 224, 93, 213, 48, 6, 174, 250, 127, 228, 165, 247, 193, 169, 53, 114, 176, 103, 191, 116, 118, 23, 97, 219, 73, 32, 245, 48, 81, 200, 42, 64, 190, 25, 126, 59, 198, 254, 136, 198, 30, 154, 159, 115, 133, 150, 85, 84, 81, 198, 220, 150, 67, 242, 28, 203, 189, 175, 18, 152, 74, 40, 37, 157, 101, 110, 50, 144, 94, 53, 103, 188, 60, 29, 26, 46, 38, 83, 193, 5, 41, 184, 184, 43, 65, 187, 143, 212, 123, 83, 233, 166, 99, 246, 45, 86, 5, 154, 252, 76, 189, 21, 225, 45, 46, 102, 104, 8, 225, 163, 7, 24, 22, 178, 179, 22, 211, 176, 8, 21, 171, 190, 105, 171, 201, 153, 254, 143, 184, 143, 79, 44, 99, 68, 83, 14, 221, 163, 40, 137, 30, 178, 150, 183, 168, 122, 148, 165, 126, 56, 195, 175, 162, 202, 69, 219, 175, 193, 166, 186, 252, 212, 135, 62, 240, 153, 66, 35, 240, 111, 129, 19, 45, 140, 227, 201, 185, 173, 12, 198, 97, 228, 10, 41, 101, 107, 165, 106, 140, 26, 165, 166, 212, 16, 53, 231, 73, 16, 53, 1, 76, 73, 68, 160, 75, 156, 36, 124, 36, 235, 158, 89, 98, 139, 130, 113, 19, 7, 232, 95, 112, 121, 125, 246, 130, 143, 5, 190, 216, 150, 246, 149, 254, 80, 102, 35, 174, 82, 169, 90, 189, 234, 242, 87, 91, 255, 78, 98, 197, 208, 42, 141, 31, 17, 233, 217, 151, 135, 31, 87, 71, 132, 255, 79, 98, 62, 168, 221, 172, 247, 225, 46, 155, 228, 196, 76, 95, 161, 68, 233, 203, 192, 236, 146, 149, 43, 85, 98, 110, 35, 242, 116, 216, 226, 78, 157, 114, 40, 157, 241, 33, 12, 14, 205, 192, 201, 12, 219, 255, 249, 6, 105, 86, 80, 101, 184, 26, 56, 101, 227, 25, 69, 140, 68, 35, 245, 46, 110, 221, 50, 51, 237, 20, 23, 174, 4, 137, 44, 207, 0, 201, 52, 147, 202, 111, 190, 72, 177, 228, 97, 210, 163, 150, 154, 2, 241, 97, 151, 93, 210, 199, 127, 218, 57, 45, 91, 96, 194, 160, 131, 205, 120, 102, 209, 51, 28, 68, 48, 199, 130, 77, 209, 13, 204, 141, 240, 217, 165, 87, 56, 119, 167, 53, 207, 74, 106, 163, 27, 100, 6, 252, 238, 114, 63, 40, 162, 86, 5, 153, 91, 98, 106, 124, 126, 91, 105, 173, 98, 74, 222, 85, 125, 64, 213, 102, 107, 3, 158, 243, 8, 167, 224, 50, 213, 167, 203, 19, 16, 235, 4, 43, 104, 115, 28, 1, 168, 41, 94, 241, 67, 161, 140, 45, 89, 118, 172, 162, 117, 224, 95, 245, 214, 214, 220, 117, 32, 163, 250, 84, 55, 174, 20, 7, 238, 213, 19, 177, 36, 105, 6, 75, 15, 72, 154, 18, 64, 85, 108, 213, 56, 86, 240, 124, 142, 134, 82, 100, 199, 198, 243, 12, 146, 80, 148, 251, 223, 79, 153, 181, 188, 100, 167, 228, 175, 227, 241, 164, 28, 120, 133, 170, 177, 202, 232, 101, 171, 207, 2, 32, 212, 173, 147, 117, 171, 218, 83, 216, 241, 94, 3, 103, 187, 230, 26, 168, 180, 159, 4, 173, 108, 61, 76, 182, 54, 115, 135, 144, 2, 39, 81, 126, 253, 172, 101, 144, 19, 3, 202, 12, 234, 87, 11, 222, 188, 82, 204, 27, 81, 216, 250, 163, 94, 103, 73, 149, 233, 251, 140, 172, 85, 138, 51, 203, 121, 30, 64, 184, 120, 46, 233, 199, 59, 106, 115, 123, 102, 145, 129, 213, 216, 74, 92, 11, 166, 50, 79, 3, 13, 80, 245, 241, 248, 193, 208, 78, 77, 229, 21, 67, 229, 192, 61, 115, 213, 93, 52, 225, 217, 147, 236, 135, 88, 184, 240, 49, 182, 109, 95, 67, 184, 204, 181, 176, 213, 34, 36, 149, 98, 143, 193, 225, 48, 180, 219, 69, 244, 64, 96, 234, 83, 5, 113, 122, 23, 115, 55, 87, 212, 130, 154, 96, 152, 92, 29, 136, 202, 217, 58, 236, 195, 153, 17, 14, 13, 213, 145, 36, 159, 163, 58, 191, 3, 11, 124, 34, 155, 237, 58, 57, 3, 144, 222, 25, 234, 107, 15, 183, 234, 160, 27, 44, 77, 149, 128, 57, 87, 142, 236, 113, 192, 44, 95, 140, 168, 65, 170, 167, 167, 38, 131, 33, 140, 27, 10, 248, 16, 71, 99, 115, 210, 177, 65, 198, 48, 11, 13, 1, 247, 24, 222, 248, 24, 73, 117, 11, 249, 29, 226, 114, 41, 64, 147, 58, 10, 52, 76, 19, 128, 25, 96, 78, 56, 108, 40, 200, 163, 225, 39, 179, 7, 84, 210, 59, 167, 133, 135, 35, 177, 111, 9, 96, 25, 142, 26, 71, 203, 43, 18, 176, 75, 224, 206, 24, 157, 10, 0, 133, 216, 218, 121, 210, 52, 164, 86, 148, 80, 18, 156, 150, 18, 197, 44, 74, 110, 158, 202, 194, 40, 132, 234, 166, 98, 208, 166, 193, 25, 225, 231, 118, 0, 136, 194, 251, 212, 237, 49, 94, 92, 250, 222, 143, 52, 229, 213, 147, 96, 189, 214, 182, 11, 149, 41, 202, 15, 64, 33, 216, 207, 177, 186, 8, 104, 161, 240, 145, 252, 200, 39, 45, 17, 161, 97, 92, 19, 73, 212, 7, 244, 26, 121, 77, 143, 178, 161, 48, 158, 113, 14, 2, 65, 152, 91, 51, 229, 240, 117, 52, 69, 236, 248, 75, 195, 136, 161, 56, 0, 23, 112, 252, 156, 183, 148, 116, 31, 215, 235, 78, 32, 227, 131, 219, 238, 212, 252, 43, 42, 128, 55, 12, 182, 80, 113, 168, 229, 158, 225, 54, 105, 162, 106, 41, 139, 28, 74, 213, 152, 209, 193, 3, 150, 77, 235, 193, 20, 105, 99, 66, 169, 242, 111, 229, 169, 14, 6, 26, 138, 220, 112, 172, 16, 75, 232, 233, 186, 153, 185, 253, 168, 242, 85, 202, 128, 167, 112, 84, 210, 132, 250, 61, 132, 1, 125, 51, 232, 128, 164, 2, 53, 141, 55, 237, 54, 114, 104, 0, 129, 0, 193, 109, 124, 129, 83, 48, 234, 47, 210, 47, 50, 95, 62, 156, 180, 113, 73, 81, 202, 149, 63, 161, 102, 201, 28, 165, 21, 108, 118, 205, 67, 107, 1, 242, 249, 196, 248, 179, 171, 198, 129, 145, 136, 228, 121, 198, 99, 87, 83, 133, 192, 17, 176, 12, 81, 54, 19, 66, 108, 58, 203, 110, 50, 112, 189, 12, 124, 32, 108, 70, 3, 184, 2, 11, 57, 206, 188, 255, 33, 137, 78, 63, 170, 63, 236, 212, 38, 102, 226, 116, 148, 26, 22, 30, 220, 80, 0, 244, 42, 166, 19, 192, 1, 151, 213, 35, 69, 244, 40, 88, 47, 251, 77, 95, 95, 77, 88, 40, 37, 119, 122, 50, 235, 233, 158, 215, 48, 199, 214, 84, 232, 211, 139, 193, 220, 144, 193, 94, 223, 110, 90, 146, 145, 98, 176, 143, 66, 215, 70, 157, 227, 114, 24, 187, 64, 249, 185, 134, 81, 219, 11, 187, 148, 239, 34, 232, 15, 29, 132, 225, 157, 46, 100, 93, 168, 237, 161, 86, 129, 132, 59, 67, 32, 58, 231, 132, 191, 42, 194, 2, 45, 50, 22, 180, 120, 142, 49, 191, 153, 215, 200, 224, 118, 235, 211, 196, 116, 27, 45, 116, 240, 68, 85, 168, 162, 100, 58, 10, 82, 102, 116, 177, 52, 16, 153, 61, 221, 111, 245, 128, 163, 191, 101, 108, 13, 58, 102, 171, 160, 161, 170, 129, 12, 197, 172, 228, 29, 225, 174, 214, 114, 97, 65, 160, 66, 90, 250, 229, 36, 204, 142, 163, 106, 182, 120, 67, 199, 184, 80, 147, 5, 167, 59, 117, 16, 135, 89, 69, 171, 210, 17, 226, 147, 117, 58, 33, 60, 80, 78, 103, 65, 79, 221, 48, 40, 148, 165, 149, 169, 106, 174, 50, 174, 186, 228, 122, 103, 65, 100, 3, 252, 57, 16, 176, 193, 199, 52, 103, 50, 146, 89, 87, 218, 84, 108, 175, 13, 195, 161, 111, 69, 128, 6, 191, 152, 120, 143, 177, 211, 94, 130, 41, 47, 136, 158, 165, 217, 25, 65, 234, 139, 212, 146, 51, 216, 59, 224, 4, 97, 77, 223, 128, 248, 95, 81, 39, 225, 183, 242, 69, 191, 48, 37, 177, 24, 119, 11, 227, 80, 254, 109, 164, 229, 55, 101, 88, 89, 168, 113, 244, 176, 100, 126, 79, 164, 212, 180, 241, 82, 196, 39, 81, 185, 106, 20, 3, 132, 98, 158, 244, 6, 125, 8, 77, 234, 34, 142, 170, 146, 224, 189, 127, 215, 124, 34, 24, 17, 243, 7, 74, 146, 166, 128, 179, 6, 98, 114, 190, 79, 67, 219, 171, 197, 129, 213, 239, 132, 144, 44, 234, 52, 230, 16, 94, 220, 92, 136, 0, 186, 244, 229, 53, 148, 233, 73, 249, 152, 217, 100, 6, 196, 77, 97, 138, 6, 5, 41, 196, 19, 142, 92, 46, 110, 54, 151, 156, 156, 177, 129, 2, 62, 200, 189, 193, 181, 93, 68, 60, 90, 149, 84, 203, 83, 201, 26, 18, 52, 156, 65, 179, 59, 3, 125, 19, 204, 236, 61, 163, 85, 36, 237, 47, 144, 140, 87, 154, 95, 60, 0, 22, 37, 155, 6, 7, 0, 176, 46, 247, 159, 37, 173, 224, 210, 12, 217, 248, 79, 132, 93, 138, 135, 78, 17, 227, 18, 45, 252, 48, 58, 254, 85, 36, 176, 69, 114, 1, 92, 207, 85, 193, 254, 112, 204, 78, 157, 146, 103, 123, 196, 100, 10, 46, 184, 161, 162, 78, 144, 141, 50, 86, 252, 50, 235, 184, 151, 55, 73, 187, 10, 37, 50, 198, 0, 207, 155, 104, 37, 137, 196, 54, 132, 15, 22, 93, 114, 237, 90, 250, 96, 61, 18, 152, 194, 63, 239, 16, 92, 110, 63, 209, 229, 27, 61, 154, 245, 208, 226, 145, 184, 219, 48, 187, 2, 193, 78, 24, 51, 81, 34, 172, 109, 33, 8, 23, 232, 115, 57, 152, 233, 140, 200, 196, 108, 8, 65, 251, 72, 68, 76, 181, 220, 62, 34, 119, 9, 126, 13, 186, 100, 214, 191, 149, 154, 131, 254, 200, 126, 152, 142, 103, 127, 57, 81, 255, 99, 129, 250, 33, 25, 183, 235, 134, 117, 115, 108, 95, 28, 86, 141, 217, 180, 116, 61, 201, 51, 90, 59, 160, 254, 213, 93, 21, 55, 204, 97, 62, 113, 100, 6, 107, 57, 64, 201, 157, 228, 173, 229, 35, 61, 235, 102, 161, 14, 189, 164, 112, 76, 75, 127, 18, 231, 145, 130, 79, 66, 150, 63, 30, 164, 181, 68, 176, 81, 217, 135, 54, 172, 66, 60, 232, 8, 206, 224, 245, 102, 177, 243, 64, 87, 233, 193, 244, 95, 68, 78, 255, 14, 144, 223, 147, 32, 36, 230, 212, 218, 185, 120, 243, 3, 64, 139, 233, 70, 90, 136, 5, 171, 221, 87, 98, 15, 43, 200, 131, 182, 75, 81, 139, 243, 233, 218, 246, 61, 246, 189, 204, 39, 168, 208, 131, 142, 200, 109, 158, 159, 54, 35, 91, 244, 135, 204, 241, 171, 25, 55, 255, 101, 15, 169, 221, 208, 223, 109, 244, 74, 78, 126, 25, 199, 151, 191, 110, 7, 74, 60, 169, 101, 212, 84, 228, 234, 187, 204, 110, 158, 131, 28, 21, 186, 158, 193, 129, 10, 199, 206, 160, 140, 85, 209, 196, 9, 167, 6, 157, 187, 234, 179, 190, 131, 250, 100, 34, 13, 98, 40, 94, 92, 80, 253, 7, 188, 233, 45, 45, 253, 101, 65, 250, 138, 64, 231, 109, 103, 163, 213, 33, 183, 99, 129, 181, 119, 96, 30, 234, 220, 121, 7, 109, 255, 191, 243, 188, 128, 33, 88, 16, 143, 190, 7, 175, 181, 7, 136, 203, 156, 61, 136, 2, 69, 232, 15, 168, 44, 87, 109, 95, 162, 79, 8, 203, 107, 170, 255, 6, 142, 43, 24, 69, 126, 184, 121, 213, 43, 132, 164, 198, 90, 213, 28, 144, 14, 208, 129, 24, 87, 170, 144, 6, 210, 3, 76, 220, 223, 12, 223, 191, 33, 42, 214, 218, 4, 236, 194, 78, 55, 215, 50, 24, 189, 64, 174, 166, 176, 110, 190, 23, 1, 240, 177, 109, 233, 48, 246, 116, 99, 168, 128, 246, 212, 113, 10, 168, 40, 72, 17, 184, 129, 191, 38, 158, 23, 192, 155, 21, 229, 218, 137, 168, 21, 5, 65, 28, 231, 85, 4, 162, 146, 77, 99, 228, 4, 175, 0, 27, 51, 79, 18, 111, 97, 103, 172, 198, 6, 91, 139, 38, 66, 197, 242, 219, 5, 14, 8, 127, 229, 156, 139, 219, 109, 240, 174, 20, 236, 133, 43, 9, 16, 154, 83, 150, 171, 193, 155, 217, 243, 153, 236, 53, 153, 145, 224, 243, 157, 117, 96, 254, 115, 134, 149, 101, 59, 101, 15, 198, 164, 71, 7, 151, 178, 173, 211, 235, 229, 9, 9, 216, 99, 178, 234, 127, 134, 80, 226, 219, 50, 22, 218, 153, 150, 38, 209, 194, 32, 66, 149, 30, 149, 124, 77, 60, 85, 118, 172, 161, 20, 91, 231, 157, 210, 37, 69, 134, 33, 41, 44, 94, 151, 67, 239, 251, 3, 113, 169, 83, 73, 192, 111, 144, 160, 228, 150, 146, 175, 125, 222, 155, 123, 120, 75, 181, 150, 133, 17, 143, 51, 247, 178, 66, 113, 249, 92, 118, 95, 180, 201, 132, 159, 86, 91, 191, 124, 12, 73, 198, 125, 183, 26, 228, 56, 235, 78, 33, 22, 9, 155, 187, 49, 250, 236, 170, 144, 254, 195, 101, 129, 204, 91, 228, 232, 83, 34, 133, 250, 46, 165, 21, 160, 235, 156, 158, 172, 126, 180, 15, 106, 81, 212, 178, 143, 108, 132, 145, 237, 39, 123, 72, 143, 134, 212, 135, 27, 181, 113, 35, 239, 62, 130, 93, 164, 198, 100, 252, 46, 187, 226, 50, 86, 186, 179, 196, 12, 114, 191, 240, 54, 83, 30, 201, 49, 217, 127, 202, 74, 23, 109, 216, 68, 15, 233, 13, 104, 156, 230, 200, 214, 101, 233, 175, 45, 5, 172, 142, 11, 77, 59, 228, 0, 66, 239, 70, 115, 148, 7, 67, 156, 0, 219, 132, 98, 27, 9, 144, 144, 30, 53, 134, 115, 149, 61, 197, 154, 111, 239, 224, 80, 8, 112, 195, 96, 237, 218, 127, 219, 175, 24, 53, 17, 216, 165, 180, 141, 129, 29, 101, 54, 56, 100, 229, 159, 192, 145, 52, 2, 153, 108, 127, 155, 32, 254, 200, 17, 46, 107, 205, 54, 29, 73, 214, 178, 101, 9, 180, 115, 31, 88, 253, 161, 26, 155, 120, 10, 213, 21, 61, 170, 228, 187, 227, 229, 20, 13, 78, 254, 11, 124, 55, 50, 212, 53, 166, 57, 186, 207, 11, 213, 242, 19, 215, 140, 210, 48, 136, 185, 131, 193, 183, 132, 145, 191, 195, 179, 86, 138, 83, 78, 219, 176, 27, 23, 80, 193, 113, 109, 148, 119, 97, 141, 92, 177, 70, 159, 13, 162, 139, 226, 84, 187, 120, 201, 21, 43, 242, 165, 195, 138, 70, 31, 24, 41, 58, 171, 25, 33, 30, 148, 108, 195, 238, 74, 70, 117, 66, 159, 139, 32, 185, 29, 159, 14, 174, 35, 224, 103, 147, 56, 1, 125, 46, 177, 13, 15, 3, 210, 81, 64, 203, 182, 202, 93, 111, 154, 2, 2, 86, 44, 152, 8, 167, 132, 60, 182, 67, 198, 182, 59, 84, 227, 96, 138, 251, 2, 21, 239, 58, 230, 57, 146, 193, 221, 12, 196, 61, 207, 231, 98, 11, 4, 177, 246, 216, 157, 89, 172, 178, 170, 175, 209, 162, 131, 47, 188, 103, 192, 165, 115, 97, 209, 252, 98, 231, 65, 187, 46, 16, 110, 192, 45, 167, 91, 57, 155, 96, 143, 39, 54, 55, 180, 107, 144, 184, 96, 68, 85, 87, 192, 17, 40, 90, 175, 225, 73, 82, 213, 27, 132, 105, 207, 130, 108, 238, 253, 31, 9, 225, 127, 214, 181, 236, 100, 148, 115, 164, 35, 73, 14, 16, 234, 43, 172, 86, 134, 180, 41, 169, 247, 54, 159, 144, 53, 44, 127, 207, 23, 253, 167, 50, 123, 106, 3, 74, 109, 111, 6, 105, 58, 228, 41, 2, 35, 131, 31, 117, 123, 73, 250, 146, 154, 175, 173, 76, 76, 196, 238, 132, 163, 150, 146, 219, 219, 162, 17, 80, 195, 1, 218, 225, 161, 23, 203, 47, 33, 130, 142, 104, 196, 107, 96, 40, 22, 79, 138, 143, 242, 139, 17, 13, 26, 49, 232, 163, 53, 24, 253, 191, 27, 53, 110, 165, 218, 243, 64, 82, 172, 181, 41, 86, 38, 50, 91, 32, 139, 109, 78, 246, 77, 178, 120, 213, 175, 168, 119, 85, 63, 220, 60, 161, 201, 134, 51, 147, 129, 22, 230, 17, 123, 201, 180, 236, 130, 33, 64, 141, 142, 12, 201, 155, 226, 224, 151, 19, 253, 200, 162, 85, 156, 199, 249, 221, 157, 217, 185, 123, 36, 209, 173, 203, 130, 132, 217, 6, 18, 248, 105, 46, 201, 184, 214, 35, 26, 85, 104, 33, 158, 236, 154, 152, 193, 82, 146, 188, 134, 42, 198, 199, 161, 4, 182, 101, 172, 233, 217, 160, 119, 161, 2, 90, 189, 238, 44, 85, 141, 207, 17, 249, 162, 228, 140, 189, 155, 68, 199, 162, 0, 132, 149, 176, 161, 112, 217, 249, 30, 64, 124, 242, 238, 62, 5, 87, 48, 254, 192, 199, 77, 152, 131, 116, 175, 242, 42, 211, 29, 157, 15, 182, 203, 230, 173, 217, 218, 88, 177, 68, 11, 33, 110, 198, 0, 105, 207, 231, 126, 70, 112, 244, 48, 89, 31, 101, 149, 200, 80, 177, 197, 120, 228, 183, 140, 107, 113, 148, 66, 159, 249, 136, 175, 156, 119, 43, 167, 238, 171, 11, 20, 101, 203, 192, 18, 167, 199, 29, 251, 102, 76, 232, 240, 168, 229, 75, 93, 95, 228, 194, 163, 91, 45, 178, 60, 161, 107, 85, 229, 36, 214, 247, 122, 140, 102, 109, 158, 125, 93, 248, 250, 188, 104, 44, 4, 222, 138, 241, 141, 40, 203, 30, 217, 206, 190, 170, 131, 112, 1, 69, 65, 14, 85, 36, 244, 2, 205, 80, 101, 222, 204, 48, 231, 92, 211, 65, 7, 227, 18, 31, 115, 153, 150, 78, 41, 226, 101, 210, 13, 110, 156, 132, 29, 245, 109, 49, 141, 108, 77, 166, 30, 11, 52, 79, 198, 110, 30, 15, 49, 55, 48, 13, 23, 185, 127, 78, 123, 135, 67, 15, 112, 114, 38, 222, 58, 98, 160, 206, 51, 76, 172, 101, 138, 116, 230, 163, 165, 233, 145, 62, 14, 124, 232, 137, 116, 177, 16, 22, 226, 104, 163, 35, 74, 61, 203, 245, 215, 72, 251, 49, 65, 7, 77, 7, 6, 138, 248, 242, 40, 136, 207, 167, 248, 67, 30, 30, 136, 55, 159, 249, 37, 174, 247, 63, 39, 253, 106, 206, 229, 75, 69, 189, 151, 181, 237, 72, 64, 125, 125, 232, 145, 140, 5, 99, 41, 42, 34, 117, 161, 73, 35, 72, 40, 188, 200, 69, 218, 45, 5, 149, 3, 137, 122, 109, 28, 57, 220, 58, 248, 252, 221, 14, 6, 21, 190, 98, 192, 220, 163, 225, 169, 23, 1, 133, 25, 85, 34, 126, 242, 240, 22, 158, 123, 116, 121, 129, 90, 72, 137, 80, 197, 206, 210, 141, 232, 107, 126, 235, 147, 34, 192, 217, 34, 110, 226, 16, 91, 2, 36, 156, 26, 187, 34, 68, 135, 197, 228, 157, 229, 166, 149, 134, 41, 163, 123, 119, 92, 136, 33, 73, 41, 246, 241, 122, 172, 240, 245, 6, 233, 221, 207, 2, 65, 153, 58, 47, 74, 210, 112, 19, 215, 194, 139, 148, 53, 188, 199, 134, 143, 188, 37, 27, 27, 0, 106, 213, 176, 59, 56, 180, 90, 175, 191, 202, 177, 181, 124, 101, 249, 87, 12, 177, 136, 127, 99, 141, 23, 131, 241, 241, 51, 40, 251, 127, 172, 55, 185, 112, 200, 105, 211, 95, 230, 55, 128, 199, 59, 150, 209, 84, 43, 66, 147, 102, 177, 240, 2, 51, 21, 170, 129, 145, 154, 228, 251, 62, 199, 21, 217, 126, 2, 9, 72, 23, 123, 67, 77, 145, 188, 116, 239, 164, 9, 180, 17, 229, 93, 167, 200, 35, 53, 20, 148, 11, 90, 7, 128, 38, 149, 96, 76, 211, 162, 86, 247, 47, 219, 153, 228, 208, 174, 1, 77, 130, 206, 8, 56, 77, 178, 126, 103, 64, 66, 173, 130, 178, 15, 157, 82, 151, 6, 31, 32, 24, 254, 116, 177, 125, 94, 103, 50, 23, 88, 167, 177, 178, 127, 154, 65, 221, 58, 221, 59, 226, 100, 212, 90, 195, 98, 94, 191, 30, 232, 150, 153, 106, 253, 109, 235, 75, 64, 207, 222, 250, 116, 71, 33, 65, 213, 195, 126, 156, 152, 66, 192, 144, 40, 227, 151, 193, 175, 99, 224, 91, 60, 164, 255, 6, 122, 7, 67, 247, 68, 73, 212, 29, 46, 88, 182, 8, 140, 159, 12, 53, 10, 134, 178, 137, 239, 153, 185, 79, 82, 248, 233, 246, 212, 236, 69, 141, 78, 223, 143, 137, 36, 152, 203, 115, 15, 73, 227, 247, 216, 141, 74, 85, 92, 252, 219, 11, 86, 24, 36, 132, 246, 133, 77, 210, 94, 247, 210, 48, 169, 100, 17, 141, 75, 195, 158, 42, 251, 39, 47, 60, 157, 65, 57, 125, 28, 71, 111, 42, 158, 47, 14, 42, 28, 117, 50, 96, 232, 48, 42, 244, 34, 57, 12, 138, 203, 106, 250, 25, 67, 23, 176, 220, 128, 5, 19, 7, 102, 171, 23, 9, 30, 96, 230, 35, 15, 34, 132, 122, 139, 178, 231, 226, 252, 122, 142, 51, 52, 11, 84, 228, 93, 72, 237, 102, 129, 75, 238, 112, 182, 84, 130, 158, 130, 41, 139, 174, 56, 166, 174, 139, 242, 44, 145, 148, 133, 123, 42, 62, 163, 116, 84, 154, 57, 28, 58, 32, 154, 34, 151, 21, 127, 143, 122, 136, 139, 252, 101, 165, 227, 105, 4, 244, 58, 116, 125, 45, 98, 76, 103, 94, 178, 138, 217, 234, 42, 40, 152, 61, 28, 185, 62, 43, 88, 177, 3, 57, 129, 36, 0, 238, 63, 194, 253, 71, 206, 114, 243, 137, 92, 79, 175, 23, 62, 120, 193, 114, 13, 142, 244, 4, 131, 205, 14, 186, 248, 29, 212, 164, 52, 12, 111, 31, 124, 143, 212, 208, 173, 96, 133, 27, 194, 239, 242, 62, 141, 119, 203, 52, 113, 243, 31, 84, 235, 5, 5, 64, 191, 252, 81, 217, 200, 232, 68, 61, 213, 171, 145, 221, 224, 102, 138, 6, 53, 167, 130, 6, 206, 196, 226, 4, 174, 108, 86, 154, 134, 37, 59, 110, 9, 191, 10, 117, 191, 133, 114, 72, 86, 93, 113, 19, 75, 34, 46, 2, 185, 169, 224, 240, 13, 200, 128, 24, 118, 36, 233, 120, 115, 6, 192, 92, 12, 228, 224, 111, 192, 137, 188, 16, 155, 62, 198, 60, 154, 52, 196, 125, 70, 58, 33, 43, 11, 168, 35, 190, 161, 124, 108, 153, 90, 186, 113, 57, 176, 154, 172, 202, 179, 55, 179, 115, 45, 183, 90, 4, 216, 112, 48, 228, 230, 219, 58, 70, 142, 78, 74, 9, 135, 22, 40, 70, 146, 224, 171, 128, 68, 8, 228, 90, 35, 220, 41, 184, 91, 212, 34, 57, 143, 189, 6, 215, 17, 90, 143, 19, 92, 97, 0, 32, 3, 71, 160, 179, 249, 172, 83, 31, 79, 228, 235, 186, 237, 88, 60, 223, 16, 150, 62, 200, 199, 30, 185, 44, 207, 192, 77, 194, 159, 154, 169, 139, 30, 66, 92, 141, 190, 237, 210, 202, 206, 242, 79, 195, 207, 22, 106, 63, 29, 195, 112, 209, 66, 25, 0, 132, 115, 0, 202, 40, 194, 111, 241, 33, 135, 53, 223, 250, 204, 154, 93, 179, 199, 141, 86, 243, 91, 194, 109, 181, 226, 69, 138, 254, 216, 121, 193, 63, 120, 2, 134, 176, 156, 166, 74, 11, 81, 70, 173, 20, 22, 53, 20, 94, 78, 223, 122, 51, 83, 235, 222, 40, 243, 124, 92, 42, 236, 168, 151, 228, 224, 219, 96, 235, 105, 253, 68, 151, 63, 159, 213, 61, 96, 8, 224, 24, 28, 90, 129, 156, 22, 25, 66, 66, 143, 239, 196, 171, 29, 13, 95, 163, 56, 87, 48, 212, 215, 72, 227, 81, 104, 53, 139, 236, 188, 128, 188, 39, 63, 223, 221, 87, 39, 250, 188, 147, 17, 199, 187, 191, 223, 149, 255, 172, 2, 174, 180, 30, 3, 20, 9, 179, 209, 14, 135, 177, 230, 230, 197, 6, 214, 127, 184, 220, 182, 147, 196, 1, 233, 166, 208, 117, 53, 27, 239, 167, 250, 146, 188, 191, 44, 63, 126, 25, 131, 251, 155, 209, 124, 244, 61, 128, 33, 161, 254, 124, 17, 223, 157, 9, 174, 72, 136, 130, 99, 2, 218, 76, 248, 115, 52, 140, 75, 220, 169, 145, 119, 90, 154, 55, 179, 3, 247, 245, 224, 97, 120, 11, 63, 95, 248, 227, 205, 148, 9, 156, 121, 111, 198, 183, 194, 240, 224, 127, 172, 161, 40, 176, 174, 198, 115, 39, 21, 135, 93, 120, 52, 77, 227, 203, 226, 47, 228, 208, 254, 86, 42, 178, 168, 118, 24, 219, 101, 28, 233, 205, 124, 126, 162, 249, 141, 40, 110, 247, 247, 167, 36, 186, 206, 2, 218, 68, 198, 144, 175, 3, 72, 97, 133, 245, 21, 59, 121, 75, 124, 96, 81, 44, 114, 14, 155, 78, 83, 4, 100, 18, 134, 220, 4, 88, 1, 176, 47, 235, 54, 199, 40, 55, 162, 55, 29, 186, 218, 192, 34, 234, 96, 241, 128, 217, 64, 204, 95, 238, 170, 235, 230, 242, 14, 87, 111, 159, 173, 38, 146, 75, 197, 5, 115, 239, 112, 251, 19, 178, 192, 186, 135, 123, 127, 45, 136, 135, 4, 78, 178, 164, 252, 8, 36, 171, 74, 21, 243, 236, 22, 204, 242, 123, 6, 114, 138, 102, 239, 74, 238, 255, 233, 3, 164, 62, 58, 143, 197, 248, 147, 172, 165, 4, 14, 1, 147, 251, 79, 85, 50, 48, 118, 108, 30, 77, 81, 140, 29, 143, 198, 121, 197, 19, 225, 49, 93, 53, 73, 33, 122, 100, 234, 165, 67, 183, 100, 195, 168, 123, 37, 235, 86, 147, 164, 71, 20, 232, 206, 20, 228, 22, 17, 177, 2, 116, 163, 136, 187, 43, 160, 176, 83, 52, 39, 224, 140, 250, 66, 232, 255, 36, 166, 132, 97, 252, 44, 246, 106, 21, 113, 16, 166, 70, 54, 222, 228, 10, 51, 19, 106, 141, 31, 102, 129, 132, 219, 84, 27, 192, 66, 145, 133, 208, 111, 137, 81, 145, 121, 176, 155, 133, 222, 27, 156, 93, 19, 244, 230, 154, 5, 113, 177, 247, 70, 125, 202, 138, 60, 3, 29, 182, 33, 211, 112, 136, 107, 223, 175, 131, 92, 13, 23, 133, 238, 136, 130, 231, 215, 211, 199, 47, 70, 75, 104, 253, 172, 61, 246, 99, 80, 154, 169, 205, 208, 105, 43, 2, 110, 203, 246, 16, 176, 11, 152, 190, 185, 100, 102, 6, 125, 63, 101, 184, 157, 6, 52, 237, 85, 121, 193, 4, 245, 227, 178, 121, 91, 208, 31, 149, 32, 198, 6, 44, 160, 127, 164, 97, 113, 61, 8, 129, 126, 48, 10, 29, 100, 71, 211, 225, 40, 9, 0, 3, 68, 93, 210, 80, 229, 218, 36, 186, 188, 107, 182, 149, 10, 6, 152, 149, 89, 117, 111, 83, 95, 195, 187, 170, 69, 248, 36, 46, 55, 27, 32, 176, 49, 156, 89, 40, 187, 234, 208, 124, 4, 208, 147, 55, 234, 237, 170, 226, 161, 111, 205, 227, 202, 198, 15, 149, 253, 102, 56, 203, 135, 155, 57, 133, 7, 109, 38, 45, 84, 8, 201, 120, 98, 237, 208, 163, 213, 53, 176, 121, 188, 246, 40, 141, 178, 27, 12, 74, 154, 55, 231, 250, 214, 249, 165, 18, 187, 143, 85, 131, 175, 192, 203, 220, 173, 219, 162, 181, 130, 100, 203, 31, 68, 146, 157, 10, 1, 49, 123, 56, 175, 34, 92, 31, 205, 201, 39, 97, 89, 162, 176, 166, 198, 242, 192, 212, 230, 208, 253, 110, 118, 141, 136, 68, 241, 174, 93, 119, 157, 164, 70, 52, 222, 125, 170, 235, 170, 115, 129, 254, 58, 191, 19, 12, 9, 76, 159, 116, 183, 185, 166, 169, 247, 179, 96, 43, 63, 202, 50, 91, 14, 150, 45, 142, 89, 161, 224, 94, 7, 25, 127, 143, 190, 148, 251, 243, 246, 157, 36, 116, 199, 185, 196, 245, 6, 4, 255, 135, 86, 236, 255, 223, 240, 191, 8, 186, 178, 34, 247, 77, 40, 193, 224, 191, 235, 56, 14, 246, 154, 127, 15, 214, 232, 95, 120, 83, 143, 147, 159, 97, 207, 96, 9, 174, 129, 106, 21, 250, 164, 65, 103, 111, 23, 160, 242, 127, 5, 172, 168, 68, 41, 119, 189, 125, 79, 82, 22, 58, 113, 205, 193, 107, 168, 144, 220, 34, 198, 164, 235, 153, 160, 200, 39, 196, 87, 81, 195, 247, 81, 215, 98, 5, 153, 67, 60, 255, 1, 229, 149, 1, 59, 195, 242, 114, 27, 7, 17, 7, 47, 7, 204, 54, 109, 29, 180, 46, 179, 74, 29, 223, 182, 12, 4, 150, 186, 216, 97, 205, 148, 220, 137, 99, 1, 226, 167, 248, 69, 252, 252, 16, 252, 207, 237, 252, 195, 115, 179, 238, 153, 117, 28, 162, 172, 225, 213, 224, 254, 157, 7, 227, 102, 38, 222, 95, 58, 21, 109, 253, 246, 148, 61, 255, 164, 173, 57, 68, 128, 104, 109, 187, 48, 126, 248, 136, 182, 233, 36, 8, 50, 172, 76, 188, 80, 3, 104, 109, 50, 69, 173, 106, 39, 220, 15, 180, 9, 64, 176, 18, 14, 184, 165, 14, 69, 131, 39, 237, 98, 6, 20, 109, 75, 21, 179, 5, 173, 107, 93, 162, 9, 85, 207, 37, 63, 213, 3, 179, 212, 113, 9, 243, 130, 154, 23, 104, 203, 84, 34, 200, 186, 236, 119, 100, 96, 222, 18, 161, 223, 113, 209, 186, 40, 217, 16, 151, 137, 161, 111, 194, 64, 21, 51, 36, 233, 84, 72, 194, 236, 158, 26, 208, 223, 9, 106, 85, 107, 223, 194, 64, 153, 58, 143, 18, 224, 250, 249, 142, 88, 61, 117, 199, 128, 182, 93, 255, 152, 129, 245, 109, 41, 188, 53, 235, 170, 26, 172, 197, 46, 145, 3, 18, 230, 70, 4, 73, 120, 45, 79, 243, 187, 115, 252, 142, 13, 73, 226, 228, 248, 29, 25, 30, 113, 140, 223, 113, 225, 145, 181, 150, 121, 36, 105, 223, 17, 226, 244, 29, 21, 212, 46, 214, 229, 162, 20, 136, 123, 126, 199, 171, 36, 237, 59, 151, 136, 165, 190, 227, 195, 99, 245, 142, 13, 188, 234, 29, 23, 38, 77, 145, 122, 199, 133, 122, 71, 5, 202, 61, 2, 129, 241, 20, 186, 246, 155, 166, 86, 135, 252, 127, 23, 242, 207, 119, 116, 232, 239, 1, 84, 211, 175, 104, 3, 132, 98, 118, 84, 87, 211, 240, 67, 86, 38, 94, 248, 80, 197, 12, 125, 190, 99, 195, 249, 165, 32, 127, 100, 231, 59, 46, 104, 36, 14, 210, 216, 35, 13, 218, 182, 105, 138, 30, 84, 51, 210, 249, 1, 144, 1, 191, 142, 229, 59, 46, 84, 75, 71, 155, 124, 199, 70, 132, 187, 6, 105, 202, 126, 135, 150, 140, 161, 44, 155, 113, 120, 4, 249, 2, 207, 73, 203, 132, 250, 173, 5, 66, 83, 246, 63, 32, 205, 146, 148, 143, 12, 239, 24, 0, 79, 180, 220, 17, 226, 17, 8, 108, 221, 113, 1, 97, 28, 69, 112, 220, 17, 34, 130, 227, 142, 10, 207, 76, 27, 57, 238, 216, 192, 113, 71, 7, 227, 142, 10, 212, 29, 21, 48, 76, 38, 119, 100, 216, 118, 124, 188, 122, 106, 71, 134, 212, 142, 142, 214, 86, 246, 188, 113, 66, 62, 193, 17, 210, 84, 123, 130, 35, 195, 154, 224, 216, 208, 223, 53, 193, 145, 193, 215, 4, 71, 138, 180, 239, 203, 208, 4, 199, 136, 53, 193, 177, 129, 147, 162, 9, 142, 144, 111, 218, 216, 177, 199, 57, 66, 56, 191, 204, 245, 245, 115, 57, 166, 143, 94, 213, 113, 253, 109, 231, 184, 224, 87, 226, 96, 190, 109, 59, 199, 5, 51, 109, 209, 130, 216, 126, 232, 97, 246, 217, 57, 62, 154, 198, 206, 241, 33, 105, 207, 193, 181, 165, 243, 166, 179, 209, 180, 237, 135, 184, 149, 184, 227, 189, 151, 65, 141, 29, 50, 49, 118, 57, 71, 137, 223, 229, 252, 201, 229, 28, 27, 174, 219, 218, 58, 71, 134, 71, 32, 180, 117, 142, 139, 138, 58, 71, 5, 237, 231, 169, 12, 41, 85, 231, 216, 64, 171, 36, 173, 107, 94, 156, 16, 123, 20, 141, 251, 147, 58, 71, 198, 243, 155, 150, 217, 164, 206, 241, 241, 164, 164, 206, 145, 65, 219, 171, 160, 164, 206, 31, 229, 28, 29, 30, 229, 28, 21, 92, 155, 150, 253, 112, 181, 16, 234, 64, 221, 93, 219, 45, 240, 135, 79, 218, 93, 81, 206, 17, 82, 81, 206, 81, 65, 49, 184, 108, 138, 35, 181, 199, 215, 82, 199, 31, 149, 102, 180, 170, 78, 74, 51, 131, 154, 187, 117, 193, 90, 43, 105, 208, 224, 77, 39, 106, 20, 135, 90, 186, 204, 239, 130, 212, 17, 226, 145, 236, 69, 155, 149, 107, 66, 167, 115, 124, 112, 93, 12, 9, 20, 67, 146, 86, 182, 223, 212, 33, 77, 233, 28, 27, 73, 21, 39, 228, 146, 61, 172, 126, 14, 46, 89, 132, 83, 218, 224, 17, 93, 75, 186, 198, 30, 65, 223, 170, 217, 31, 149, 124, 210, 200, 194, 15, 9, 231, 155, 166, 11, 125, 123, 164, 145, 171, 148, 33, 247, 196, 32, 57, 227, 201, 238, 68, 223, 236, 232, 96, 204, 11, 74, 219, 216, 209, 225, 105, 251, 89, 77, 99, 71, 135, 46, 111, 66, 68, 103, 99, 199, 134, 214, 137, 50, 118, 92, 244, 98, 199, 135, 54, 217, 58, 137, 104, 126, 126, 213, 46, 118, 100, 128, 189, 85, 236, 216, 224, 19, 18, 72, 32, 247, 136, 36, 177, 35, 3, 47, 47, 133, 175, 210, 134, 104, 125, 151, 42, 81, 4, 47, 132, 6, 62, 52, 78, 155, 216, 113, 1, 177, 248, 195, 147, 118, 177, 123, 56, 199, 181, 74, 210, 69, 172, 101, 36, 73, 113, 99, 160, 77, 30, 116, 61, 197, 236, 209, 182, 121, 139, 27, 7, 9, 201, 211, 28, 31, 146, 167, 57, 42, 184, 111, 142, 10, 200, 155, 99, 131, 36, 165, 163, 112, 115, 100, 184, 108, 10, 115, 115, 100, 56, 233, 149, 145, 104, 115, 108, 60, 21, 21, 217, 28, 25, 60, 146, 208, 163, 153, 44, 24, 102, 21, 194, 134, 181, 255, 80, 227, 38, 91, 185, 108, 142, 14, 109, 126, 127, 248, 133, 104, 115, 66, 207, 142, 35, 151, 205, 209, 65, 146, 205, 209, 177, 46, 221, 51, 199, 197, 163, 241, 62, 184, 182, 82, 137, 220, 51, 199, 9, 231, 152, 163, 194, 2, 2, 52, 60, 72, 82, 58, 199, 153, 153, 163, 163, 109, 101, 217, 114, 92, 168, 109, 222, 114, 100, 104, 222, 114, 116, 104, 222, 114, 84, 144, 108, 227, 229, 200, 144, 120, 57, 42, 160, 131, 98, 88, 111, 137, 52, 237, 114, 116, 52, 56, 213, 229, 184, 240, 128, 216, 92, 142, 193, 98, 239, 52, 124, 83, 214, 184, 119, 210, 20, 77, 84, 45, 104, 69, 13, 244, 115, 57, 46, 184, 46, 34, 48, 56, 158, 203, 113, 161, 105, 185, 28, 23, 30, 102, 35, 36, 204, 206, 162, 148, 134, 135, 217, 119, 160, 67, 227, 253, 85, 104, 201, 229, 40, 225, 45, 149, 73, 28, 23, 189, 112, 165, 206, 173, 196, 177, 193, 163, 98, 29, 29, 235, 45, 91, 223, 215, 209, 49, 233, 117, 84, 208, 247, 46, 225, 176, 233, 36, 228, 104, 220, 214, 113, 65, 219, 46, 138, 182, 6, 40, 157, 35, 132, 64, 15, 179, 11, 60, 130, 30, 102, 23, 80, 197, 152, 39, 5, 165, 212, 160, 111, 130, 58, 151, 92, 30, 58, 23, 93, 21, 21, 75, 113, 240, 180, 239, 251, 249, 30, 1, 65, 58, 254, 192, 251, 46, 167, 238, 17, 193, 249, 151, 172, 108, 217, 163, 237, 138, 240, 134, 55, 78, 11, 89, 176, 114, 242, 104, 134, 96, 172, 28, 216, 176, 62, 177, 117, 100, 104, 238, 86, 132, 176, 215, 154, 117, 100, 128, 124, 83, 233, 42, 160, 253, 190, 161, 117, 101, 107, 214, 113, 209, 154, 117, 116, 180, 62, 179, 142, 12, 207, 172, 163, 130, 170, 117, 132, 172, 201, 115, 28, 23, 214, 254, 123, 52, 172, 124, 19, 20, 65, 212, 122, 236, 56, 50, 60, 59, 142, 10, 142, 167, 211, 104, 118, 28, 29, 170, 184, 161, 117, 137, 30, 102, 29, 59, 142, 16, 21, 93, 142, 227, 194, 163, 18, 244, 77, 39, 202, 214, 113, 108, 176, 146, 117, 28, 23, 158, 103, 214, 113, 100, 240, 8, 4, 213, 234, 184, 164, 21, 133, 224, 17, 73, 82, 39, 61, 191, 9, 15, 117, 153, 28, 50, 105, 138, 214, 82, 199, 177, 225, 208, 180, 92, 212, 113, 124, 64, 13, 236, 121, 58, 142, 12, 174, 211, 113, 92, 112, 28, 27, 186, 150, 81, 215, 88, 249, 38, 168, 175, 124, 19, 212, 97, 229, 155, 160, 143, 99, 8, 91, 199, 145, 132, 54, 94, 216, 208, 250, 228, 114, 40, 37, 233, 56, 66, 58, 35, 232, 193, 35, 43, 225, 67, 66, 58, 142, 10, 186, 150, 65, 19, 72, 16, 33, 29, 199, 135, 174, 101, 16, 4, 233, 56, 54, 32, 72, 199, 81, 193, 35, 16, 210, 113, 100, 216, 149, 80, 69, 49, 142, 12, 71, 135, 117, 217, 80, 196, 171, 171, 243, 234, 216, 96, 235, 56, 146, 64, 175, 142, 13, 43, 39, 105, 27, 179, 78, 7, 189, 58, 46, 104, 253, 215, 6, 189, 58, 58, 84, 181, 250, 74, 24, 35, 154, 182, 146, 196, 107, 65, 175, 142, 144, 135, 89, 232, 78, 90, 29, 25, 144, 36, 229, 251, 55, 101, 141, 157, 127, 30, 96, 245, 212, 219, 235, 6, 238, 177, 78, 74, 211, 182, 105, 242, 145, 118, 1, 92, 55, 1, 234, 75, 153, 109, 88, 229, 167, 114, 74, 34, 159, 224, 136, 129, 132, 183, 62, 185, 80, 170, 133, 229, 66, 105, 151, 54, 69, 91, 171, 67, 174, 139, 27, 177, 92, 2, 72, 188, 74, 210, 91, 208, 55, 101, 186, 84, 123, 139, 83, 26, 96, 146, 130, 244, 115, 19, 187, 59, 120, 64, 105, 214, 37, 106, 224, 174, 171, 29, 144, 136, 101, 73, 32, 1, 4, 81, 81, 213, 246, 209, 56, 237, 36, 25, 164, 147, 86, 199, 134, 110, 116, 63, 60, 130, 248, 25, 52, 246, 8, 62, 60, 204, 166, 230, 160, 88, 204, 78, 146, 152, 57, 236, 74, 168, 65, 43, 118, 233, 155, 160, 142, 141, 9, 234, 168, 224, 87, 242, 174, 239, 192, 174, 162, 232, 233, 111, 187, 156, 71, 168, 103, 66, 154, 154, 126, 83, 199, 134, 181, 201, 84, 83, 71, 13, 106, 187, 81, 189, 139, 106, 234, 200, 240, 181, 255, 32, 143, 196, 67, 3, 132, 54, 203, 248, 126, 58, 122, 215, 79, 237, 70, 0, 12, 179, 10, 181, 78, 152, 58, 62, 84, 47, 196, 93, 23, 218, 231, 9, 237, 123, 240, 2, 248, 47, 99, 140, 0, 132, 240, 38, 31, 97, 68, 235, 100, 91, 45, 74, 145, 152, 232, 140, 32, 109, 188, 216, 219, 166, 75, 29, 31, 104, 11, 173, 216, 134, 50, 117, 34, 124, 210, 21, 13, 66, 254, 216, 240, 202, 14, 249, 227, 194, 53, 135, 252, 145, 193, 31, 29, 143, 11, 127, 84, 210, 144, 63, 50, 248, 87, 146, 88, 146, 152, 57, 137, 43, 140, 8, 151, 208, 207, 110, 214, 33, 129, 114, 201, 144, 63, 50, 52, 12, 143, 13, 73, 98, 134, 34, 139, 111, 234, 218, 14, 249, 34, 127, 108, 240, 71, 136, 251, 163, 99, 77, 112, 92, 118, 131, 252, 49, 194, 31, 33, 159, 212, 85, 20, 249, 99, 227, 155, 170, 134, 63, 62, 30, 31, 210, 249, 35, 69, 243, 211, 143, 11, 191, 79, 63, 46, 240, 163, 167, 31, 33, 218, 219, 9, 61, 253, 216, 64, 198, 171, 99, 175, 31, 23, 186, 24, 230, 245, 227, 194, 249, 135, 33, 125, 253, 216, 112, 154, 199, 253, 200, 48, 225, 107, 255, 73, 124, 69, 31, 165, 100, 185, 31, 35, 86, 238, 100, 251, 17, 130, 165, 46, 72, 151, 219, 126, 124, 184, 182, 93, 19, 239, 52, 219, 74, 27, 156, 97, 56, 194, 181, 237, 98, 219, 143, 18, 108, 251, 81, 193, 35, 216, 160, 208, 229, 165, 86, 247, 188, 166, 229, 246, 227, 130, 135, 217, 69, 106, 143, 47, 85, 204, 28, 107, 173, 164, 225, 218, 104, 63, 66, 218, 166, 147, 144, 131, 122, 235, 36, 251, 23, 226, 17, 228, 160, 178, 253, 201, 22, 64, 120, 68, 226, 175, 142, 84, 83, 42, 73, 217, 143, 11, 250, 45, 154, 225, 155, 118, 58, 77, 217, 143, 143, 9, 34, 232, 71, 5, 167, 121, 252, 8, 113, 210, 227, 199, 133, 206, 110, 126, 148, 112, 207, 229, 240, 205, 254, 205, 142, 86, 166, 109, 120, 177, 227, 71, 136, 135, 217, 229, 216, 70, 60, 32, 131, 29, 63, 42, 116, 46, 142, 31, 25, 60, 2, 1, 29, 17, 64, 136, 64, 4, 61, 204, 46, 198, 143, 144, 197, 248, 81, 161, 43, 150, 209, 84, 194, 143, 144, 214, 101, 246, 155, 170, 229, 71, 72, 227, 69, 8, 126, 100, 120, 4, 225, 67, 215, 50, 19, 196, 143, 140, 9, 48, 255, 16, 63, 46, 38, 240, 109, 31, 226, 231, 199, 5, 226, 71, 7, 63, 50, 248, 29, 248, 145, 81, 113, 136, 17, 63, 226, 71, 7, 196, 207, 143, 14, 136, 49, 13, 226, 199, 136, 71, 4, 9, 159, 188, 30, 23, 46, 241, 240, 163, 195, 245, 249, 77, 224, 71, 136, 79, 133, 248, 17, 226, 154, 150, 157, 132, 248, 209, 193, 143, 13, 216, 120, 103, 112, 120, 224, 71, 136, 8, 72, 0, 1, 4, 237, 145, 193, 177, 199, 135, 147, 62, 217, 35, 131, 71, 212, 122, 92, 88, 191, 143, 14, 93, 191, 15, 113, 213, 50, 223, 237, 59, 183, 143, 140, 213, 111, 161, 79, 223, 4, 77, 236, 105, 251, 184, 208, 79, 197, 104, 94, 156, 148, 186, 231, 159, 190, 9, 14, 39, 181, 50, 136, 199, 144, 52, 51, 168, 23, 196, 253, 59, 168, 177, 71, 28, 244, 115, 49, 109, 209, 211, 246, 27, 78, 74, 125, 154, 100, 37, 5, 253, 50, 198, 73, 98, 49, 39, 122, 218, 62, 62, 124, 179, 179, 125, 92, 48, 182, 143, 10, 16, 146, 196, 12, 105, 227, 138, 6, 143, 32, 109, 92, 129, 12, 199, 87, 20, 121, 63, 204, 70, 120, 51, 180, 74, 210, 58, 116, 240, 104, 117, 170, 18, 143, 64, 224, 38, 29, 218, 184, 2, 82, 89, 230, 129, 97, 86, 33, 101, 251, 216, 120, 152, 85, 107, 31, 23, 143, 36, 237, 227, 194, 227, 146, 246, 156, 71, 6, 73, 202, 133, 194, 237, 60, 54, 92, 50, 200, 195, 55, 237, 126, 169, 113, 66, 19, 17, 156, 230, 113, 59, 143, 12, 93, 255, 17, 77, 251, 228, 118, 30, 25, 40, 205, 120, 102, 219, 121, 100, 128, 88, 118, 169, 119, 136, 83, 56, 147, 5, 57, 174, 12, 57, 168, 182, 243, 184, 224, 11, 149, 218, 206, 99, 3, 83, 30, 61, 223, 235, 60, 58, 218, 58, 143, 144, 196, 74, 91, 157, 127, 152, 109, 234, 60, 62, 158, 165, 169, 243, 200, 224, 12, 106, 234, 60, 46, 154, 182, 76, 157, 199, 197, 62, 164, 76, 157, 71, 134, 164, 61, 230, 113, 97, 237, 191, 6, 186, 94, 35, 138, 111, 187, 190, 162, 143, 140, 215, 206, 132, 14, 141, 247, 51, 98, 2, 136, 249, 55, 193, 160, 129, 97, 86, 161, 175, 232, 127, 69, 31, 29, 173, 206, 235, 35, 195, 186, 68, 107, 179, 253, 183, 189, 72, 131, 197, 222, 65, 190, 152, 159, 1, 50, 244, 209, 225, 161, 139, 93, 31, 33, 239, 250, 168, 160, 205, 9, 69, 120, 4, 2, 66, 22, 180, 122, 235, 35, 131, 132, 130, 24, 100, 183, 62, 62, 154, 63, 219, 54, 233, 36, 126, 37, 144, 214, 214, 114, 65, 11, 31, 180, 98, 29, 177, 214, 199, 134, 71, 84, 113, 115, 255, 14, 114, 215, 213, 52, 53, 125, 108, 240, 56, 166, 143, 11, 17, 160, 215, 150, 177, 242, 231, 152, 62, 62, 120, 58, 155, 27, 74, 159, 92, 171, 31, 196, 49, 125, 100, 232, 111, 83, 124, 193, 244, 177, 225, 152, 62, 42, 188, 182, 165, 143, 13, 223, 236, 38, 26, 123, 132, 201, 110, 116, 233, 35, 195, 229, 55, 222, 181, 169, 62, 54, 84, 160, 169, 62, 66, 28, 31, 40, 245, 231, 210, 99, 195, 35, 163, 241, 46, 140, 211, 35, 196, 251, 174, 181, 86, 34, 241, 124, 100, 116, 231, 163, 130, 51, 168, 243, 145, 65, 93, 190, 203, 199, 69, 82, 231, 200, 229, 35, 227, 31, 35, 151, 143, 11, 201, 202, 87, 73, 62, 50, 220, 147, 106, 75, 89, 155, 143, 143, 181, 249, 168, 176, 168, 135, 97, 242, 113, 225, 141, 31, 39, 229, 35, 3, 53, 127, 174, 183, 228, 35, 196, 146, 191, 228, 35, 195, 55, 123, 67, 43, 246, 1, 162, 107, 201, 199, 5, 93, 75, 46, 75, 62, 50, 28, 183, 126, 91, 7, 173, 16, 30, 97, 250, 254, 56, 50, 126, 37, 169, 61, 142, 139, 228, 24, 16, 39, 189, 50, 142, 164, 21, 69, 169, 61, 142, 141, 199, 113, 66, 205, 8, 31, 84, 251, 31, 17, 200, 208, 234, 150, 226, 200, 128, 142, 68, 113, 116, 60, 73, 113, 84, 240, 8, 98, 157, 20, 119, 73, 113, 108, 68, 128, 144, 120, 95, 133, 30, 246, 57, 124, 49, 191, 127, 126, 195, 202, 77, 203, 48, 220, 32, 177, 242, 200, 91, 140, 78, 26, 71, 124, 83, 135, 38, 41, 142, 15, 138, 163, 99, 1, 117, 82, 38, 109, 135, 40, 142, 15, 245, 87, 105, 38, 142, 11, 100, 52, 246, 102, 226, 200, 192, 205, 196, 81, 1, 33, 30, 197, 203, 211, 58, 209, 8, 154, 137, 99, 3, 243, 31, 97, 225, 17, 8, 159, 116, 169, 59, 174, 153, 57, 159, 14, 66, 51, 113, 156, 240, 8, 132, 102, 210, 250, 107, 25, 8, 205, 164, 105, 235, 169, 16, 154, 137, 99, 131, 3, 133, 190, 9, 226, 247, 38, 31, 53, 19, 71, 70, 3, 140, 114, 136, 243, 19, 16, 222, 76, 28, 25, 120, 147, 139, 193, 136, 86, 73, 46, 168, 153, 56, 54, 90, 183, 66, 23, 148, 118, 121, 9, 241, 163, 212, 137, 154, 137, 99, 131, 111, 157, 56, 62, 154, 57, 142, 137, 170, 8, 73, 82, 136, 131, 254, 210, 137, 35, 195, 163, 147, 126, 142, 144, 149, 219, 253, 28, 23, 254, 218, 144, 166, 100, 250, 57, 66, 220, 162, 148, 86, 247, 56, 19, 254, 205, 206, 161, 217, 119, 242, 174, 13, 151, 207, 248, 244, 58, 237, 231, 63, 190, 162, 143, 32, 79, 5, 66, 66, 146, 152, 161, 86, 247, 28, 29, 250, 220, 90, 25, 123, 142, 142, 86, 73, 82, 39, 177, 183, 248, 112, 95, 116, 54, 207, 113, 161, 178, 12, 243, 28, 25, 222, 49, 110, 247, 96, 245, 28, 29, 234, 217, 233, 57, 46, 220, 53, 165, 231, 232, 240, 21, 253, 252, 229, 57, 50, 232, 122, 222, 151, 231, 200, 144, 180, 245, 229, 57, 46, 156, 130, 188, 241, 190, 91, 96, 31, 66, 137, 9, 95, 158, 227, 163, 81, 88, 65, 208, 210, 137, 174, 229, 57, 66, 120, 175, 90, 158, 227, 162, 233, 92, 158, 35, 131, 123, 18, 126, 254, 116, 189, 94, 223, 200, 151, 225, 219, 46, 26, 247, 127, 202, 180, 140, 63, 81, 227, 254, 6, 14, 220, 147, 59, 52, 35, 64, 53, 63, 184, 246, 251, 84, 6, 41, 109, 15, 113, 99, 64, 235, 59, 205, 58, 7, 80, 127, 74, 155, 91, 179, 136, 27, 202, 149, 84, 65, 208, 236, 12, 248, 66, 249, 2, 184, 39, 71, 15, 60, 112, 109, 187, 84, 237, 107, 144, 123, 250, 0, 220, 147, 35, 2, 184, 107, 82, 7, 90, 85, 115, 11, 192, 61, 37, 115, 212, 170, 154, 145, 3, 22, 123, 7, 45, 120, 32, 128, 32, 81, 195, 37, 41, 29, 237, 101, 26, 21, 104, 88, 169, 152, 61, 18, 21, 143, 32, 229, 240, 198, 105, 145, 122, 43, 39, 186, 158, 127, 124, 210, 72, 219, 254, 79, 116, 40, 140, 144, 32, 225, 239, 119, 92, 248, 179, 28, 104, 218, 62, 51, 237, 135, 86, 214, 204, 240, 98, 128, 20, 202, 224, 252, 75, 180, 250, 233, 63, 102, 30, 153, 240, 111, 234, 9, 57, 199, 82, 251, 157, 113, 13, 140, 23, 228, 214, 91, 34, 87, 177, 96, 169, 253, 144, 87, 119, 201, 26, 254, 201, 139, 121, 152, 149, 192, 21, 61, 204, 186, 238, 195, 236, 195, 236, 54, 109, 21, 39, 85, 21, 112, 248, 206, 119, 167, 217, 102, 219, 191, 192, 51, 186, 216, 246, 59, 88, 43, 25, 248, 206, 247, 7, 170, 169, 74, 7, 1, 130, 90, 202, 179, 26, 35, 182, 253, 252, 139, 189, 131, 220, 246, 63, 203, 195, 243, 219, 185, 150, 173, 59, 176, 64, 83, 46, 167, 20, 148, 134, 116, 46, 18, 218, 217, 239, 179, 49, 104, 240, 140, 174, 8, 38, 64, 142, 167, 227, 224, 120, 58, 145, 133, 81, 68, 131, 210, 135, 198, 235, 176, 80, 1, 244, 179, 225, 238, 231, 104, 101, 191, 39, 242, 69, 7, 152, 52, 157, 232, 129, 12, 255, 203, 244, 211, 246, 59, 46, 32, 105, 235, 173, 107, 113, 67, 244, 233, 155, 240, 4, 216, 144, 137, 39, 168, 144, 120, 130, 10, 58, 35, 232, 181, 9, 46, 252, 29, 183, 9, 50, 76, 88, 19, 84, 208, 120, 43, 118, 130, 12, 238, 105, 85, 91, 10, 69, 4, 125, 147, 110, 38, 14, 145, 20, 87, 81, 108, 39, 8, 161, 191, 19, 84, 104, 188, 190, 19, 100, 240, 8, 66, 212, 119, 130, 10, 107, 255, 33, 223, 9, 50, 180, 237, 82, 182, 143, 124, 39, 8, 65, 190, 19, 124, 48, 112, 201, 30, 38, 220, 249, 116, 74, 89, 182, 7, 211, 95, 119, 72, 180, 102, 221, 19, 65, 214, 211, 118, 130, 11, 205, 159, 169, 149, 225, 3, 143, 32, 195, 35, 16, 254, 39, 14, 12, 197, 145, 71, 30, 19, 208, 69, 30, 121, 112, 60, 23, 211, 224, 75, 39, 186, 208, 243, 187, 242, 77, 120, 192, 53, 245, 99, 119, 192, 151, 131, 150, 237, 159, 240, 8, 4, 198, 167, 212, 126, 168, 218, 9, 66, 48, 230, 10, 6, 15, 30, 36, 41, 223, 181, 211, 241, 5, 12, 180, 254, 103, 242, 7, 223, 74, 162, 206, 197, 78, 66, 215, 233, 100, 63, 155, 131, 182, 93, 170, 105, 163, 139, 223, 215, 137, 112, 143, 187, 233, 92, 154, 187, 21, 162, 181, 109, 106, 39, 7, 218, 156, 190, 211, 105, 240, 156, 56, 72, 210, 190, 235, 82, 45, 211, 132, 182, 93, 18, 175, 27, 60, 47, 135, 42, 12, 209, 185, 60, 124, 43, 8, 242, 52, 127, 218, 9, 46, 222, 217, 153, 224, 2, 196, 55, 187, 163, 213, 193, 61, 164, 218, 50, 72, 215, 50, 147, 9, 46, 52, 119, 235, 4, 25, 20, 197, 61, 221, 59, 18, 191, 234, 37, 122, 224, 77, 41, 85, 235, 4, 27, 75, 83, 235, 4, 25, 60, 2, 161, 53, 171, 166, 19, 92, 120, 196, 1, 61, 191, 137, 151, 78, 16, 66, 61, 94, 73, 53, 83, 28, 150, 27, 55, 79, 156, 53, 51, 202, 182, 225, 141, 23, 37, 83, 135, 129, 227, 178, 27, 109, 154, 252, 65, 87, 38, 87, 182, 223, 94, 67, 26, 237, 198, 187, 116, 201, 229, 104, 125, 109, 215, 250, 109, 31, 39, 117, 182, 174, 227, 192, 218, 184, 131, 166, 102, 198, 209, 120, 31, 38, 19, 15, 119, 110, 136, 93, 9, 101, 163, 19, 100, 100, 163, 19, 84, 80, 157, 32, 100, 130, 12, 175, 128, 203, 52, 193, 134, 167, 115, 130, 10, 157, 19, 108, 124, 219, 206, 9, 50, 48, 204, 42, 132, 13, 223, 114, 130, 10, 17, 173, 18, 79, 230, 160, 50, 215, 218, 150, 19, 132, 80, 8, 142, 88, 249, 38, 120, 228, 177, 16, 84, 178, 203, 129, 74, 118, 161, 6, 14, 60, 152, 160, 104, 101, 152, 183, 72, 168, 100, 23, 98, 176, 16, 34, 90, 213, 45, 192, 92, 107, 64, 63, 87, 63, 164, 32, 86, 63, 181, 43, 39, 232, 160, 159, 10, 237, 202, 9, 54, 114, 50, 129, 9, 46, 38, 48, 65, 136, 9, 50, 36, 158, 12, 77, 144, 65, 117, 242, 226, 30, 21, 164, 106, 125, 87, 66, 19, 140, 152, 160, 195, 109, 197, 67, 133, 8, 38, 106, 223, 67, 6, 8, 212, 190, 135, 11, 13, 17, 76, 22, 234, 157, 206, 241, 56, 236, 123, 8, 209, 247, 80, 129, 110, 255, 195, 133, 138, 54, 218, 13, 154, 254, 231, 98, 144, 43, 199, 134, 135, 89, 8, 107, 31, 162, 154, 254, 163, 162, 104, 237, 63, 92, 172, 253, 135, 10, 170, 56, 53, 125, 184, 67, 255, 89, 208, 4, 152, 127, 8, 49, 1, 230, 31, 42, 72, 128, 249, 135, 10, 58, 1, 196, 252, 67, 135, 212, 30, 71, 13, 202, 178, 49, 190, 105, 147, 249, 202, 80, 51, 118, 26, 254, 104, 114, 65, 232, 208, 234, 15, 21, 182, 223, 209, 238, 11, 213, 30, 123, 103, 82, 181, 142, 212, 31, 62, 90, 33, 148, 50, 230, 10, 164, 90, 162, 150, 14, 66, 27, 35, 102, 202, 212, 183, 164, 200, 85, 202, 26, 251, 250, 195, 9, 72, 43, 99, 139, 52, 53, 51, 73, 25, 70, 145, 182, 83, 85, 72, 253, 97, 131, 230, 79, 186, 40, 32, 143, 227, 228, 118, 73, 48, 218, 72, 146, 114, 121, 8, 225, 188, 149, 136, 87, 247, 68, 234, 15, 27, 234, 15, 21, 44, 254, 80, 193, 202, 244, 126, 216, 224, 253, 80, 193, 154, 208, 15, 21, 34, 152, 64, 61, 23, 203, 174, 213, 15, 25, 218, 114, 100, 245, 195, 133, 227, 233, 172, 126, 184, 192, 6, 59, 64, 154, 183, 252, 105, 125, 19, 208, 171, 55, 44, 224, 44, 59, 93, 132, 171, 104, 163, 189, 250, 97, 3, 210, 90, 255, 31, 158, 168, 31, 82, 160, 163, 45, 71, 208, 234, 135, 140, 213, 15, 21, 84, 182, 31, 42, 108, 63, 124, 120, 100, 251, 225, 130, 55, 232, 239, 218, 126, 24, 225, 17, 180, 253, 144, 1, 181, 58, 215, 52, 247, 112, 241, 188, 220, 195, 133, 215, 70, 45, 5, 105, 103, 194, 8, 135, 214, 7, 231, 213, 82, 208, 63, 215, 86, 130, 97, 86, 61, 36, 73, 157, 132, 32, 250, 169, 220, 67, 134, 134, 23, 82, 238, 61, 92, 104, 117, 12, 136, 58, 72, 64, 149, 78, 232, 225, 182, 162, 61, 92, 80, 75, 247, 105, 15, 23, 248, 208, 30, 54, 190, 162, 13, 41, 253, 124, 111, 15, 27, 94, 189, 61, 124, 80, 178, 219, 195, 133, 246, 144, 161, 110, 93, 123, 200, 192, 154, 219, 195, 5, 199, 83, 87, 123, 232, 240, 48, 91, 217, 246, 112, 225, 88, 162, 202, 118, 163, 28, 30, 65, 234, 81, 101, 219, 67, 136, 135, 89, 200, 162, 148, 5, 86, 191, 134, 167, 68, 144, 115, 137, 146, 37, 20, 14, 86, 122, 235, 100, 219, 67, 8, 143, 64, 248, 109, 15, 23, 238, 96, 125, 39, 15, 30, 102, 29, 88, 64, 0, 46, 153, 195, 39, 117, 222, 86, 98, 173, 7, 173, 207, 36, 82, 109, 129, 111, 123, 24, 241, 174, 189, 237, 225, 162, 87, 33, 199, 244, 31, 38, 24, 171, 150, 221, 128, 12, 124, 194, 182, 135, 11, 106, 39, 108, 123, 200, 48, 97, 219, 67, 133, 214, 111, 203, 110, 219, 67, 135, 190, 149, 19, 212, 120, 219, 195, 135, 210, 111, 118, 142, 6, 6, 160, 146, 9, 160, 41, 153, 198, 15, 144, 174, 29, 128, 166, 100, 56, 37, 83, 0, 77, 201, 124, 203, 247, 198, 15, 48, 160, 41, 153, 3, 184, 68, 190, 237, 225, 130, 8, 109, 219, 52, 117, 240, 166, 19, 41, 93, 102, 219, 67, 8, 195, 172, 218, 246, 84, 109, 123, 216, 208, 237, 135, 44, 207, 35, 30, 3, 184, 174, 132, 2, 158, 244, 201, 8, 144, 44, 41, 114, 101, 217, 208, 243, 173, 169, 65, 93, 38, 215, 246, 144, 209, 42, 201, 159, 104, 149, 228, 67, 136, 104, 85, 201, 11, 248, 91, 238, 193, 249, 116, 143, 74, 150, 149, 208, 230, 228, 14, 237, 231, 174, 237, 80, 171, 106, 15, 29, 148, 73, 103, 84, 181, 135, 141, 246, 144, 129, 123, 106, 15, 23, 42, 218, 104, 35, 231, 211, 161, 212, 30, 58, 68, 112, 91, 177, 180, 135, 14, 58, 217, 95, 182, 237, 80, 133, 151, 246, 240, 161, 61, 100, 172, 156, 40, 106, 15, 23, 205, 171, 96, 15, 23, 150, 61, 124, 44, 123, 168, 64, 177, 135, 10, 36, 158, 236, 225, 66, 227, 254, 245, 144, 65, 237, 122, 168, 176, 30, 6, 96, 178, 15, 21, 252, 74, 246, 225, 66, 4, 181, 15, 21, 148, 73, 71, 106, 31, 50, 30, 102, 27, 238, 137, 159, 66, 39, 233, 19, 30, 113, 69, 216, 120, 239, 101, 210, 195, 5, 63, 183, 107, 93, 30, 54, 60, 130, 242, 85, 60, 50, 188, 58, 195, 48, 170, 120, 108, 60, 206, 61, 143, 11, 30, 65, 236, 158, 199, 5, 106, 102, 30, 104, 26, 196, 155, 246, 48, 235, 158, 199, 134, 149, 105, 221, 243, 184, 104, 176, 246, 31, 197, 3, 111, 204, 24, 39, 180, 128, 171, 132, 39, 242, 72, 99, 199, 61, 143, 19, 173, 191, 77, 81, 247, 60, 58, 212, 151, 162, 235, 249, 70, 99, 135, 104, 236, 238, 65, 232, 67, 72, 103, 222, 117, 1, 228, 74, 37, 204, 14, 242, 149, 208, 74, 214, 60, 128, 166, 173, 82, 117, 196, 154, 117, 27, 98, 253, 128, 53, 35, 134, 39, 48, 91, 104, 106, 102, 184, 29, 242, 150, 142, 52, 37, 227, 192, 91, 58, 106, 234, 24, 105, 74, 38, 187, 213, 191, 49, 67, 154, 146, 81, 247, 60, 78, 168, 66, 137, 25, 44, 195, 131, 191, 66, 79, 118, 167, 242, 8, 4, 134, 35, 245, 174, 173, 34, 190, 213, 61, 17, 242, 104, 155, 78, 98, 120, 161, 44, 155, 123, 152, 134, 186, 231, 37, 26, 190, 105, 99, 247, 60, 58, 168, 123, 30, 21, 22, 171, 60, 42, 68, 168, 60, 42, 96, 207, 17, 83, 30, 23, 207, 148, 199, 199, 47, 229, 81, 65, 219, 82, 30, 23, 184, 83, 50, 8, 109, 41, 143, 14, 86, 181, 19, 8, 69, 98, 17, 13, 188, 107, 41, 143, 12, 190, 210, 189, 86, 168, 89, 202, 227, 132, 195, 70, 152, 41, 229, 113, 225, 17, 8, 173, 21, 170, 148, 71, 199, 99, 237, 63, 228, 176, 82, 182, 87, 165, 60, 54, 188, 169, 82, 30, 31, 90, 87, 191, 71, 6, 252, 61, 130, 152, 126, 143, 13, 151, 180, 93, 14, 111, 94, 250, 61, 50, 112, 220, 145, 99, 105, 107, 239, 31, 218, 247, 8, 241, 252, 99, 227, 249, 71, 5, 17, 26, 12, 195, 20, 198, 179, 70, 96, 254, 113, 161, 77, 219, 126, 252, 145, 145, 94, 145, 63, 46, 220, 243, 71, 5, 215, 149, 246, 59, 157, 63, 62, 146, 253, 81, 97, 49, 127, 84, 104, 120, 193, 191, 179, 177, 167, 212, 134, 52, 164, 87, 7, 131, 165, 45, 189, 73, 225, 128, 12, 203, 46, 127, 92, 208, 37, 73, 235, 143, 139, 138, 242, 71, 5, 229, 143, 10, 220, 249, 116, 201, 31, 25, 14, 184, 243, 233, 144, 131, 63, 197, 117, 45, 131, 146, 63, 54, 146, 63, 42, 80, 150, 254, 184, 208, 216, 35, 16, 242, 83, 65, 240, 71, 72, 115, 5, 249, 35, 131, 127, 179, 171, 40, 82, 234, 175, 61, 228, 143, 17, 234, 158, 95, 234, 143, 15, 228, 143, 17, 141, 27, 67, 221, 243, 14, 239, 137, 212, 31, 27, 252, 17, 162, 105, 109, 153, 164, 74, 5, 50, 84, 42, 48, 0, 170, 229, 251, 171, 192, 69, 107, 5, 54, 90, 85, 211, 174, 192, 5, 99, 174, 64, 135, 71, 32, 104, 227, 10, 92, 84, 224, 194, 35, 203, 174, 10, 100, 72, 237, 241, 198, 195, 236, 178, 171, 2, 31, 150, 93, 21, 168, 224, 254, 29, 180, 128, 189, 126, 111, 251, 128, 175, 132, 36, 218, 74, 220, 86, 32, 131, 171, 226, 228, 182, 2, 25, 110, 43, 208, 209, 171, 144, 219, 10, 92, 76, 96, 220, 90, 129, 12, 222, 180, 229, 214, 10, 116, 224, 119, 90, 129, 11, 90, 129, 140, 181, 184, 147, 55, 173, 192, 134, 227, 207, 161, 166, 21, 200, 240, 71, 77, 43, 208, 193, 149, 101, 5, 46, 168, 111, 179, 178, 2, 27, 222, 119, 101, 235, 247, 96, 195, 189, 7, 21, 120, 36, 177, 218, 247, 32, 99, 223, 131, 10, 84, 115, 242, 85, 40, 66, 155, 19, 90, 234, 159, 127, 176, 209, 238, 104, 125, 114, 57, 132, 14, 78, 122, 252, 224, 194, 147, 206, 15, 46, 240, 131, 1, 104, 15, 6, 224, 65, 199, 235, 245, 160, 130, 71, 30, 84, 208, 158, 132, 171, 165, 251, 32, 132, 155, 235, 131, 11, 239, 250, 15, 136, 230, 79, 172, 80, 75, 198, 250, 96, 195, 123, 234, 131, 11, 157, 250, 160, 66, 91, 230, 158, 30, 92, 172, 138, 124, 80, 97, 85, 188, 124, 112, 65, 194, 236, 180, 206, 7, 25, 204, 53, 212, 252, 208, 207, 180, 203, 61, 165, 10, 162, 117, 62, 248, 160, 61, 7, 136, 47, 252, 203, 198, 77, 231, 131, 141, 197, 236, 242, 65, 6, 143, 160, 202, 99, 249, 32, 163, 85, 37, 63, 190, 237, 106, 120, 100, 209, 152, 132, 22, 203, 135, 241, 251, 75, 136, 129, 126, 79, 180, 88, 62, 248, 192, 242, 65, 5, 15, 46, 210, 202, 7, 21, 158, 36, 31, 84, 216, 215, 124, 112, 161, 241, 230, 131, 143, 54, 1, 8, 30, 84, 64, 15, 62, 252, 193, 199, 162, 176, 225, 17, 199, 211, 169, 84, 144, 177, 48, 147, 10, 42, 32, 164, 130, 13, 137, 95, 6, 177, 214, 175, 224, 3, 107, 253, 10, 46, 184, 123, 5, 31, 238, 21, 84, 224, 17, 8, 206, 167, 67, 206, 167, 171, 84, 112, 33, 185, 94, 172, 130, 12, 203, 29, 185, 127, 103, 177, 10, 74, 104, 59, 114, 176, 196, 106, 177, 10, 50, 44, 86, 193, 134, 119, 58, 105, 177, 10, 50, 22, 171, 68, 88, 172, 194, 82, 251, 181, 185, 130, 42, 184, 192, 85, 113, 163, 153, 85, 80, 194, 35, 104, 177, 10, 50, 176, 10, 54, 240, 187, 167, 19, 90, 172, 130, 142, 183, 160, 197, 42, 8, 177, 88, 5, 21, 248, 170, 60, 199, 14, 85, 124, 85, 176, 161, 226, 171, 130, 10, 30, 241, 85, 193, 5, 134, 217, 85, 193, 133, 8, 237, 84, 80, 161, 157, 10, 62, 36, 137, 25, 106, 167, 130, 140, 118, 42, 168, 64, 21, 55, 196, 173, 21, 108, 44, 85, 65, 5, 189, 202, 241, 236, 71, 141, 170, 32, 164, 87, 169, 231, 130, 26, 85, 193, 135, 126, 170, 74, 165, 130, 11, 30, 137, 80, 65, 133, 9, 36, 136, 80, 65, 133, 231, 118, 200, 189, 130, 42, 157, 28, 61, 217, 168, 130, 13, 141, 247, 83, 123, 76, 131, 47, 170, 160, 195, 35, 13, 91, 84, 193, 6, 93, 75, 254, 42, 69, 21, 116, 60, 21, 21, 143, 130, 11, 19, 64, 204, 83, 112, 193, 41, 24, 128, 197, 242, 89, 44, 31, 72, 35, 113, 232, 161, 177, 71, 28, 107, 25, 244, 64, 127, 155, 130, 11, 78, 122, 109, 10, 50, 56, 169, 105, 83, 144, 65, 215, 190, 203, 166, 32, 131, 129, 194, 197, 226, 160, 39, 101, 163, 107, 0, 217, 20, 108, 180, 174, 166, 101, 83, 144, 177, 46, 29, 133, 130, 12, 201, 53, 106, 117, 52, 176, 78, 6, 181, 82, 88, 181, 117, 160, 56, 156, 165, 74, 52, 109, 255, 177, 186, 77, 250, 224, 12, 154, 182, 78, 202, 164, 237, 156, 3, 9, 109, 134, 52, 181, 228, 2, 235, 42, 170, 214, 190, 6, 7, 239, 153, 84, 114, 63, 144, 218, 227, 72, 181, 199, 221, 72, 82, 46, 168, 194, 139, 164, 153, 130, 13, 60, 226, 178, 41, 46, 155, 162, 154, 41, 200, 112, 217, 148, 134, 106, 166, 160, 35, 37, 141, 41, 184, 32, 129, 9, 60, 204, 98, 10, 82, 44, 236, 53, 10, 46, 84, 36, 20, 84, 192, 40, 199, 191, 216, 59, 18, 74, 83, 199, 14, 206, 47, 5, 27, 36, 212, 73, 153, 212, 45, 5, 31, 34, 26, 94, 254, 248, 55, 59, 1, 172, 205, 254, 86, 151, 110, 81, 220, 52, 102, 15, 188, 21, 14, 142, 231, 59, 132, 100, 189, 5, 61, 171, 105, 120, 77, 164, 125, 207, 165, 11, 116, 45, 131, 208, 179, 54, 213, 3, 39, 125, 82, 212, 227, 149, 144, 68, 227, 247, 7, 95, 204, 143, 212, 196, 83, 225, 118, 200, 217, 61, 88, 201, 16, 188, 16, 133, 85, 91, 10, 50, 104, 233, 164, 182, 20, 92, 244, 127, 182, 165, 224, 66, 61, 117, 105, 163, 182, 20, 124, 72, 154, 25, 212, 150, 130, 12, 181, 150, 130, 14, 181, 150, 130, 15, 102, 41, 168, 64, 155, 90, 10, 62, 190, 181, 45, 106, 210, 82, 208, 209, 180, 109, 237, 53, 90, 244, 56, 20, 156, 120, 178, 59, 35, 188, 189, 70, 13, 204, 49, 116, 61, 197, 12, 162, 238, 121, 212, 246, 215, 62, 9, 165, 21, 94, 208, 2, 39, 173, 67, 193, 133, 87, 135, 130, 143, 71, 165, 54, 98, 172, 80, 83, 135, 130, 14, 77, 29, 10, 42, 44, 85, 135, 130, 11, 104, 129, 213, 207, 161, 238, 121, 101, 203, 156, 244, 202, 64, 26, 202, 167, 67, 193, 7, 231, 27, 210, 161, 160, 35, 130, 9, 120, 67, 193, 5, 165, 19, 110, 199, 22, 189, 54, 20, 108, 120, 109, 40, 168, 128, 13, 71, 107, 181, 85, 10, 50, 124, 231, 187, 68, 149, 130, 13, 137, 230, 135, 89, 73, 74, 202, 162, 20, 116, 172, 9, 190, 40, 5, 25, 36, 64, 240, 80, 202, 178, 25, 4, 129, 141, 244, 173, 77, 107, 231, 226, 120, 248, 138, 182, 7, 232, 233, 215, 22, 128, 196, 87, 177, 108, 212, 252, 153, 252, 49, 11, 175, 108, 173, 175, 77, 43, 115, 60, 29, 36, 129, 98, 16, 13, 175, 199, 194, 171, 65, 223, 236, 216, 46, 240, 236, 176, 227, 159, 172, 185, 129, 75, 218, 115, 18, 114, 252, 45, 6, 73, 82, 186, 237, 111, 138, 158, 213, 184, 178, 204, 3, 18, 19, 101, 128, 156, 234, 131, 136, 207, 212, 120, 193, 62, 218, 166, 147, 26, 90, 151, 106, 90, 177, 222, 64, 171, 90, 219, 100, 243, 230, 45, 239, 202, 108, 75, 134, 252, 213, 189, 129, 59, 224, 194, 27, 175, 47, 181, 139, 82, 80, 98, 53, 139, 82, 36, 190, 49, 179, 40, 5, 27, 22, 165, 224, 2, 222, 71, 196, 162, 20, 92, 96, 146, 106, 81, 10, 50, 104, 115, 66, 252, 238, 233, 180, 40, 101, 81, 10, 46, 180, 109, 211, 36, 44, 74, 65, 10, 239, 69, 41, 72, 225, 154, 210, 45, 74, 65, 135, 175, 44, 22, 165, 32, 100, 81, 10, 50, 240, 8, 242, 198, 187, 40, 5, 35, 42, 234, 82, 41, 144, 100, 146, 84, 10, 66, 188, 94, 72, 146, 74, 65, 135, 212, 158, 198, 0, 210, 73, 204, 34, 18, 154, 214, 41, 3, 7, 90, 63, 98, 162, 1, 175, 162, 32, 133, 162, 96, 0, 222, 179, 201, 68, 193, 6, 255, 182, 236, 158, 164, 96, 163, 105, 249, 36, 133, 233, 231, 58, 73, 10, 54, 168, 199, 188, 116, 162, 10, 53, 246, 79, 10, 50, 240, 181, 255, 30, 146, 169, 147, 28, 34, 183, 245, 183, 19, 146, 208, 182, 171, 245, 147, 130, 141, 8, 19, 146, 148, 174, 241, 48, 235, 164, 79, 10, 46, 160, 131, 118, 82, 80, 161, 105, 73, 65, 135, 171, 100, 37, 5, 25, 122, 149, 100, 37, 5, 23, 206, 167, 67, 238, 65, 36, 41, 23, 36, 89, 73, 193, 134, 100, 37, 5, 21, 26, 163, 223, 164, 224, 98, 177, 10, 74, 18, 40, 24, 161, 44, 219, 163, 18, 148, 36, 80, 240, 177, 240, 90, 80, 146, 64, 65, 70, 99, 143, 32, 10, 50, 84, 42, 19, 84, 224, 21, 125, 19, 84, 209, 55, 153, 112, 181, 116, 25, 228, 146, 61, 184, 231, 74, 168, 162, 111, 130, 14, 7, 92, 100, 235, 155, 224, 66, 3, 238, 218, 78, 223, 4, 25, 250, 38, 216, 80, 7, 143, 56, 233, 113, 4, 3, 119, 201, 32, 28, 18, 65, 146, 214, 233, 167, 66, 17, 52, 37, 138, 160, 111, 130, 15, 173, 43, 223, 247, 78, 146, 255, 162, 31, 255, 42, 125, 79, 254, 199, 227, 220, 190, 3, 145, 0, 130, 8, 68, 112, 109, 160, 23, 44, 253, 8, 105, 155, 137, 67, 107, 235, 210, 113, 180, 114, 19, 75, 60, 42, 249, 102, 167, 181, 85, 53, 109, 254, 181, 184, 147, 35, 125, 147, 201, 126, 210, 94, 69, 241, 248, 54, 243, 109, 55, 225, 34, 160, 198, 187, 191, 94, 190, 50, 164, 47, 45, 122, 186, 177, 39, 115, 60, 21, 47, 71, 171, 199, 65, 79, 69, 174, 198, 255, 111, 65, 30, 161, 88, 169, 152, 33, 143, 52, 19, 215, 223, 182, 76, 91, 138, 79, 217, 95, 81, 212, 38, 0, 193, 182, 9, 64, 176, 140, 38, 191, 209, 213, 48, 55, 13, 116, 45, 249, 72, 49, 55, 218, 180, 178, 149, 15, 190, 41, 107, 178, 25, 214, 204, 60, 154, 54, 137, 213, 50, 85, 250, 169, 60, 2, 193, 143, 190, 61, 214, 149, 48, 59, 154, 23, 55, 20, 51, 85, 172, 56, 130, 195, 179, 26, 163, 135, 39, 41, 41, 73, 187, 82, 68, 2, 30, 102, 95, 223, 132, 129, 54, 210, 245, 32, 192, 193, 174, 5, 30, 249, 78, 231, 241, 38, 8, 225, 127, 15, 74, 255, 57, 198, 9, 165, 246, 184, 4, 175, 197, 206, 225, 105, 255, 89, 217, 18, 233, 155, 96, 3, 179, 56, 244, 19, 100, 208, 55, 217, 126, 14, 2, 232, 39, 251, 138, 254, 67, 243, 156, 175, 230, 248, 138, 126, 1, 22, 63, 240, 77, 119, 165, 5, 201, 117, 99, 143, 56, 48, 192, 222, 97, 224, 233, 87, 166, 75, 31, 185, 39, 164, 138, 147, 79, 112, 1, 77, 62, 65, 5, 215, 245, 186, 39, 184, 192, 41, 60, 65, 5, 125, 250, 38, 32, 10, 79, 176, 225, 12, 162, 240, 4, 25, 86, 186, 230, 9, 50, 168, 229, 73, 137, 145, 168, 100, 171, 73, 227, 131, 196, 233, 68, 30, 6, 57, 144, 67, 202, 49, 165, 142, 202, 6, 147, 17, 40, 210, 3, 97, 44, 20, 137, 2, 73, 21, 133, 15, 20, 0, 3, 14, 64, 173, 25, 205, 76, 19, 164, 76, 169, 170, 13, 64, 16, 0, 4, 109, 75, 111, 237, 120, 170, 176, 201, 1, 78, 65, 242, 207, 98, 231, 248, 155, 37, 98, 142, 118, 116, 122, 6, 69, 240, 26, 157, 196, 61, 207, 229, 171, 211, 118, 68, 198, 142, 40, 103, 168, 102, 48, 188, 43, 26, 45, 249, 235, 140, 168, 165, 124, 54, 255, 142, 34, 25, 28, 15, 15, 7, 51, 179, 7, 109, 171, 165, 175, 67, 121, 9, 25, 190, 128, 198, 47, 71, 166, 61, 171, 12, 194, 125, 81, 62, 133, 61, 176, 25, 172, 66, 207, 46, 240, 250, 136, 21, 95, 93, 21, 109, 2, 45, 170, 136, 127, 78, 167, 63, 71, 118, 198, 110, 67, 39, 244, 24, 31, 119, 14, 61, 110, 109, 68, 17, 154, 243, 229, 149, 199, 135, 120, 58, 46, 81, 50, 71, 174, 122, 85, 31, 36, 158, 218, 166, 121, 26, 120, 230, 52, 172, 117, 155, 193, 237, 43, 141, 84, 148, 247, 191, 123, 49, 197, 218, 15, 73, 29, 124, 250, 198, 47, 7, 129, 50, 172, 194, 193, 55, 97, 35, 146, 73, 103, 73, 25, 137, 248, 242, 119, 10, 222, 11, 114, 8, 161, 29, 217, 2, 31, 195, 156, 139, 31, 144, 19, 49, 77, 243, 250, 250, 158, 29, 91, 131, 133, 11, 173, 87, 119, 15, 209, 216, 4, 111, 201, 119, 204, 170, 12, 229, 220, 185, 218, 97, 208, 149, 132, 246, 107, 162, 130, 91, 222, 97, 123, 201, 73, 22, 157, 3, 139, 213, 122, 136, 16, 211, 171, 145, 253, 126, 175, 213, 63, 36, 80, 40, 74, 46, 229, 152, 185, 30, 29, 213, 127, 236, 167, 160, 71, 141, 178, 173, 45, 2, 4, 65, 100, 96, 16, 109, 18, 223, 179, 37, 88, 62, 97, 198, 128, 89, 31, 28, 171, 155, 67, 234, 24, 166, 229, 210, 1, 36, 125, 123, 33, 32, 159, 235, 21, 154, 114, 49, 161, 209, 38, 248, 131, 160, 239, 52, 206, 165, 78, 153, 191, 179, 16, 42, 160, 128, 112, 38, 251, 192, 90, 206, 130, 88, 119, 70, 252, 18, 19, 179, 240, 5, 100, 198, 75, 115, 52, 66, 150, 128, 138, 172, 98, 221, 8, 158, 17, 246, 14, 141, 120, 235, 229, 96, 229, 38, 166, 254, 35, 123, 81, 186, 64, 22, 66, 16, 101, 234, 75, 141, 194, 154, 204, 160, 33, 197, 1, 164, 244, 196, 56, 52, 1, 230, 17, 165, 50, 203, 106, 231, 107, 255, 71, 126, 255, 83, 70, 32, 14, 208, 139, 229, 226, 138, 222, 163, 27, 134, 240, 219, 246, 188, 154, 62, 151, 167, 106, 0, 111, 96, 182, 220, 50, 223, 221, 34, 135, 240, 83, 156, 114, 29, 53, 107, 46, 148, 169, 111, 250, 153, 57, 135, 197, 216, 102, 163, 127, 53, 245, 203, 58, 142, 97, 151, 166, 77, 26, 90, 165, 113, 133, 3, 211, 169, 168, 233, 135, 37, 226, 23, 139, 175, 179, 198, 136, 20, 22, 109, 224, 185, 222, 51, 2, 77, 1, 21, 91, 58, 141, 1, 254, 39, 222, 220, 161, 150, 232, 214, 206, 133, 116, 175, 101, 131, 104, 229, 86, 114, 173, 94, 26, 84, 77, 121, 235, 211, 159, 120, 165, 227, 125, 45, 11, 6, 120, 215, 203, 97, 132, 167, 107, 114, 2, 63, 167, 80, 100, 118, 8, 168, 20, 10, 88, 130, 247, 36, 104, 167, 86, 49, 242, 147, 141, 55, 121, 206, 224, 73, 188, 54, 218, 224, 30, 234, 52, 66, 117, 125, 196, 8, 206, 95, 111, 5, 137, 155, 199, 14, 204, 128, 209, 175, 40, 9, 170, 39, 57, 63, 34, 25, 41, 144, 20, 52, 191, 143, 140, 47, 200, 15, 254, 180, 209, 74, 88, 18, 237, 88, 104, 188, 136, 146, 188, 32, 113, 74, 111, 82, 169, 247, 76, 73, 222, 208, 129, 181, 51, 131, 210, 3, 142, 9, 254, 221, 46, 51, 186, 85, 24, 193, 137, 43, 2, 177, 133, 141, 182, 235, 30, 173, 240, 78, 104, 184, 120, 239, 75, 106, 178, 243, 105, 169, 57, 11, 252, 172, 139, 247, 36, 4, 3, 60, 142, 188, 214, 138, 149, 137, 212, 43, 30, 208, 251, 181, 41, 81, 153, 107, 139, 70, 60, 202, 192, 178, 31, 69, 153, 26, 178, 170, 5, 27, 159, 164, 135, 6, 75, 231, 231, 210, 179, 22, 92, 107, 192, 110, 86, 174, 53, 125, 52, 210, 243, 11, 243, 206, 53, 185, 58, 34, 50, 117, 222, 30, 26, 97, 122, 209, 129, 141, 246, 76, 101, 208, 79, 111, 243, 217, 105, 178, 227, 88, 219, 40, 54, 211, 46, 12, 238, 22, 201, 176, 24, 246, 117, 145, 177, 7, 158, 173, 6, 203, 30, 67, 205, 203, 18, 44, 171, 177, 238, 84, 167, 123, 168, 52, 65, 199, 170, 77, 117, 50, 201, 0, 42, 105, 27, 193, 91, 60, 152, 238, 83, 218, 246, 151, 33, 138, 16, 172, 65, 228, 30, 38, 200, 137, 214, 31, 140, 12, 227, 197, 164, 80, 251, 215, 153, 59, 87, 118, 248, 74, 117, 152, 44, 112, 169, 155, 66, 63, 219, 82, 190, 113, 213, 217, 15, 80, 28, 133, 75, 234, 156, 56, 109, 240, 28, 229, 19, 244, 25, 106, 11, 28, 210, 191, 115, 178, 226, 128, 7, 130, 213, 90, 188, 33, 63, 184, 31, 99, 153, 36, 128, 28, 123, 36, 197, 40, 166, 51, 83, 234, 195, 42, 92, 172, 162, 110, 231, 8, 171, 250, 65, 99, 198, 137, 235, 224, 73, 81, 207, 4, 250, 204, 78, 72, 102, 82, 141, 85, 202, 92, 226, 36, 230, 22, 137, 67, 234, 142, 136, 96, 14, 83, 162, 53, 9, 7, 165, 66, 241, 199, 74, 141, 188, 63, 253, 107, 148, 2, 248, 65, 138, 123, 227, 220, 48, 249, 213, 32, 2, 252, 42, 190, 107, 99, 205, 110, 239, 3, 119, 218, 246, 52, 167, 46, 50, 232, 66, 164, 80, 68, 64, 194, 41, 8, 0, 25, 216, 162, 206, 222, 137, 107, 149, 114, 205, 198, 16, 67, 146, 212, 141, 181, 149, 247, 252, 14, 66, 173, 223, 125, 254, 126, 152, 34, 75, 107, 91, 204, 195, 185, 206, 199, 232, 6, 226, 128, 104, 142, 209, 160, 21, 238, 81, 44, 113, 3, 230, 250, 236, 161, 142, 124, 40, 106, 132, 206, 233, 89, 99, 100, 226, 246, 177, 31, 127, 158, 221, 200, 67, 35, 143, 140, 9, 22, 99, 102, 143, 127, 120, 255, 225, 234, 103, 88, 205, 128, 128, 156, 166, 127, 60, 20, 180, 231, 246, 237, 66, 13, 97, 121, 166, 188, 236, 4, 62, 227, 174, 89, 64, 34, 176, 95, 159, 49, 41, 137, 69, 199, 48, 188, 93, 219, 103, 140, 33, 11, 199, 65, 241, 100, 133, 160, 3, 18, 26, 119, 136, 229, 38, 129, 136, 121, 34, 168, 144, 85, 241, 96, 72, 29, 93, 16, 4, 136, 97, 53, 59, 183, 36, 44, 141, 140, 136, 131, 91, 74, 19, 4, 207, 189, 0, 227, 93, 81, 151, 91, 67, 216, 122, 118, 153, 22, 246, 242, 231, 69, 102, 95, 173, 97, 72, 66, 136, 12, 217, 206, 79, 140, 24, 11, 79, 251, 209, 203, 35, 198, 121, 231, 229, 6, 214, 88, 132, 224, 126, 255, 176, 129, 36, 204, 94, 130, 235, 86, 226, 14, 197, 149, 44, 136, 165, 139, 195, 229, 180, 195, 241, 164, 112, 219, 37, 62, 195, 245, 100, 77, 180, 229, 144, 60, 222, 135, 160, 63, 106, 78, 34, 17, 216, 152, 173, 81, 27, 1, 44, 232, 36, 81, 104, 58, 47, 32, 100, 164, 211, 188, 125, 238, 219, 179, 131, 97, 199, 137, 25, 205, 162, 200, 145, 197, 38, 220, 24, 102, 152, 150, 158, 43, 234, 238, 66, 49, 90, 131, 174, 97, 219, 26, 117, 38, 36, 82, 247, 130, 156, 205, 161, 248, 80, 56, 181, 70, 137, 146, 17, 103, 30, 168, 35, 99, 3, 7, 215, 81, 169, 118, 55, 162, 131, 132, 124, 156, 193, 241, 85, 147, 187, 47, 54, 51, 125, 20, 241, 20, 2, 41, 229, 62, 1, 73, 240, 126, 190, 178, 71, 69, 141, 94, 180, 131, 67, 102, 8, 233, 80, 73, 0, 137, 161, 142, 175, 0, 181, 86, 206, 144, 205, 103, 78, 53, 100, 139, 158, 99, 187, 111, 238, 109, 201, 241, 130, 246, 174, 163, 51, 123, 115, 225, 33, 255, 12, 41, 84, 69, 209, 109, 151, 96, 244, 151, 3, 201, 255, 96, 125, 221, 123, 239, 163, 182, 138, 138, 211, 200, 82, 228, 110, 239, 131, 44, 191, 123, 159, 156, 94, 133, 218, 142, 212, 20, 204, 53, 39, 71, 138, 197, 147, 130, 27, 240, 124, 116, 113, 175, 215, 58, 106, 133, 224, 9, 122, 175, 33, 23, 20, 105, 244, 166, 1, 167, 118, 19, 156, 50, 192, 195, 128, 104, 11, 14, 245, 88, 3, 174, 184, 169, 6, 74, 156, 128, 16, 68, 121, 198, 229, 50, 42, 176, 176, 144, 44, 60, 112, 243, 55, 105, 196, 184, 102, 91, 98, 202, 57, 77, 55, 3, 38, 102, 130, 51, 111, 14, 71, 16, 118, 208, 180, 36, 59, 37, 237, 59, 13, 253, 193, 65, 175, 92, 79, 64, 11, 31, 18, 22, 69, 86, 156, 188, 165, 63, 50, 105, 49, 18, 243, 114, 12, 222, 78, 3, 228, 175, 206, 231, 72, 59, 227, 42, 144, 198, 225, 19, 67, 27, 120, 192, 164, 5, 65, 42, 224, 33, 69, 218, 64, 176, 6, 217, 104, 169, 68, 229, 218, 167, 153, 63, 26, 41, 17, 202, 243, 12, 158, 44, 126, 84, 25, 123, 196, 72, 197, 135, 197, 101, 122, 191, 150, 226, 170, 135, 18, 107, 234, 63, 237, 94, 236, 227, 111, 120, 82, 193, 182, 52, 206, 104, 46, 234, 81, 23, 88, 116, 248, 108, 48, 1, 48, 224, 78, 162, 208, 197, 208, 223, 130, 202, 206, 60, 16, 56, 168, 240, 8, 236, 142, 216, 107, 200, 76, 111, 113, 208, 32, 13, 125, 137, 223, 163, 172, 14, 38, 32, 22, 177, 74, 204, 99, 133, 115, 241, 136, 232, 253, 159, 254, 10, 251, 114, 134, 179, 0, 161, 120, 211, 89, 35, 171, 183, 203, 244, 93, 1, 68, 226, 185, 162, 79, 90, 158, 189, 50, 138, 140, 213, 157, 193, 44, 153, 98, 228, 165, 31, 125, 231, 218, 227, 247, 27, 144, 177, 87, 202, 76, 177, 177, 53, 109, 142, 205, 233, 240, 33, 1, 99, 37, 93, 6, 131, 91, 90, 96, 193, 79, 93, 148, 73, 192, 197, 20, 52, 223, 108, 236, 179, 19, 132, 66, 186, 56, 102, 179, 253, 89, 73, 2, 235, 83, 198, 40, 96, 44, 102, 146, 46, 169, 83, 199, 47, 246, 150, 46, 109, 108, 22, 254, 126, 150, 9, 178, 41, 89, 64, 250, 213, 59, 79, 1, 244, 241, 234, 115, 98, 254, 65, 255, 57, 170, 52, 107, 66, 220, 186, 201, 89, 168, 10, 172, 179, 35, 64, 249, 77, 10, 247, 2, 18, 172, 205, 249, 222, 139, 12, 100, 170, 19, 227, 128, 16, 6, 114, 119, 238, 186, 239, 137, 248, 167, 92, 234, 55, 185, 107, 53, 153, 93, 155, 192, 110, 179, 205, 8, 153, 194, 237, 243, 203, 164, 98, 16, 217, 19, 56, 31, 248, 92, 68, 233, 200, 21, 182, 81, 250, 9, 20, 50, 144, 187, 251, 15, 112, 203, 42, 187, 23, 72, 60, 64, 191, 61, 86, 64, 158, 58, 196, 8, 154, 174, 30, 134, 63, 47, 75, 34, 37, 64, 70, 28, 71, 45, 126, 101, 5, 53, 224, 55, 131, 48, 193, 101, 47, 134, 186, 42, 33, 139, 111, 155, 224, 118, 149, 39, 113, 5, 115, 233, 10, 234, 171, 166, 229, 119, 156, 46, 142, 251, 136, 104, 141, 89, 204, 70, 186, 163, 201, 194, 100, 91, 202, 104, 186, 138, 59, 146, 178, 205, 30, 65, 180, 84, 252, 209, 3, 104, 240, 87, 70, 186, 159, 42, 177, 146, 202, 224, 12, 212, 201, 213, 153, 210, 57, 210, 248, 98, 254, 29, 32, 97, 185, 161, 108, 163, 129, 30, 7, 194, 181, 208, 198, 166, 212, 199, 224, 41, 38, 39, 135, 165, 0, 170, 159, 11, 89, 254, 21, 62, 205, 234, 106, 0, 34, 211, 99, 251, 21, 19, 96, 2, 87, 230, 112, 58, 22, 118, 90, 88, 169, 121, 193, 135, 88, 231, 199, 126, 92, 130, 166, 96, 54, 94, 15, 242, 32, 154, 89, 104, 68, 205, 96, 62, 26, 208, 50, 54, 157, 233, 33, 81, 119, 9, 160, 106, 227, 212, 41, 212, 67, 184, 103, 48, 192, 238, 84, 165, 216, 147, 210, 115, 111, 204, 27, 228, 166, 65, 203, 22, 59, 95, 190, 99, 11, 75, 78, 247, 225, 101, 151, 132, 170, 49, 180, 158, 246, 37, 201, 39, 123, 135, 220, 27, 11, 167, 112, 80, 230, 106, 222, 6, 247, 225, 31, 194, 71, 200, 131, 231, 45, 90, 156, 154, 232, 167, 170, 177, 237, 227, 119, 28, 55, 228, 236, 238, 39, 217, 50, 119, 196, 118, 58, 251, 215, 242, 158, 99, 185, 144, 92, 100, 54, 70, 46, 55, 75, 34, 7, 229, 14, 230, 142, 197, 187, 70, 205, 184, 84, 165, 174, 106, 88, 14, 34, 61, 31, 182, 23, 253, 12, 162, 15, 75, 97, 250, 12, 121, 46, 20, 228, 134, 253, 99, 234, 77, 215, 60, 79, 136, 31, 237, 138, 29, 140, 41, 23, 161, 248, 114, 31, 204, 57, 68, 251, 57, 129, 254, 238, 80, 121, 3, 36, 131, 95, 224, 238, 82, 171, 251, 120, 36, 54, 132, 51, 252, 54, 51, 224, 92, 147, 71, 59, 163, 0, 220, 235, 240, 63, 9, 64, 53, 216, 243, 45, 197, 172, 8, 128, 90, 142, 111, 253, 211, 246, 132, 135, 69, 238, 108, 176, 0, 27, 170, 29, 128, 185, 79, 0, 28, 20, 203, 187, 210, 42, 103, 117, 37, 146, 173, 238, 50, 71, 89, 168, 56, 153, 195, 240, 73, 243, 54, 132, 77, 86, 4, 67, 144, 18, 43, 22, 201, 42, 47, 112, 148, 26, 36, 248, 106, 102, 149, 109, 22, 239, 49, 125, 40, 207, 63, 170, 109, 250, 137, 124, 138, 162, 59, 181, 59, 104, 92, 84, 204, 41, 243, 11, 238, 140, 251, 124, 96, 34, 103, 205, 15, 103, 28, 31, 135, 135, 169, 109, 156, 15, 146, 88, 56, 32, 145, 202, 98, 26, 220, 183, 103, 206, 155, 153, 12, 229, 242, 159, 2, 27, 76, 236, 62, 111, 155, 67, 193, 137, 153, 4, 113, 139, 114, 34, 3, 174, 131, 14, 248, 85, 206, 93, 53, 27, 60, 145, 134, 206, 139, 234, 95, 197, 100, 141, 251, 244, 126, 224, 138, 66, 147, 145, 126, 144, 176, 161, 253, 52, 211, 112, 130, 203, 246, 230, 28, 196, 111, 224, 187, 29, 169, 176, 54, 64, 148, 77, 105, 80, 11, 172, 27, 133, 66, 74, 239, 14, 248, 40, 15, 40, 51, 180, 174, 93, 198, 216, 116, 169, 66, 249, 86, 118, 41, 141, 203, 30, 46, 196, 104, 50, 116, 140, 148, 22, 236, 95, 123, 212, 133, 132, 226, 136, 121, 83, 160, 218, 8, 155, 241, 141, 216, 16, 103, 212, 72, 246, 184, 233, 174, 42, 10, 148, 249, 214, 70, 76, 108, 133, 117, 170, 234, 183, 183, 58, 174, 67, 204, 100, 227, 57, 44, 236, 152, 74, 15, 225, 72, 92, 196, 93, 40, 1, 68, 53, 254, 128, 78, 178, 93, 193, 234, 133, 86, 160, 31, 139, 64, 123, 190, 94, 76, 221, 66, 83, 115, 217, 144, 195, 72, 109, 213, 158, 3, 33, 247, 113, 166, 29, 144, 125, 218, 141, 165, 149, 54, 227, 59, 230, 115, 153, 148, 226, 141, 61, 180, 247, 171, 103, 219, 88, 37, 1, 74, 64, 37, 55, 162, 27, 236, 34, 45, 24, 136, 71, 228, 211, 55, 5, 134, 137, 162, 166, 175, 75, 13, 230, 120, 212, 54, 133, 213, 13, 212, 4, 75, 141, 17, 248, 142, 201, 250, 5, 221, 163, 237, 12, 161, 28, 238, 54, 158, 171, 228, 241, 92, 6, 0, 81, 232, 157, 213, 166, 240, 149, 3, 113, 11, 68, 217, 104, 163, 44, 113, 158, 213, 129, 142, 169, 83, 128, 174, 159, 118, 192, 38, 166, 163, 1, 198, 235, 155, 12, 16, 156, 12, 21, 244, 216, 229, 30, 161, 210, 22, 35, 22, 117, 126, 237, 94, 7, 217, 143, 145, 188, 52, 104, 98, 103, 53, 225, 105, 49, 246, 72, 3, 53, 240, 210, 195, 27, 186, 43, 247, 24, 204, 81, 229, 242, 32, 97, 84, 239, 144, 247, 4, 84, 158, 212, 187, 14, 18, 4, 12, 88, 248, 37, 10, 225, 196, 28, 170, 41, 138, 32, 149, 30, 134, 240, 43, 63, 144, 55, 220, 192, 49, 179, 137, 88, 163, 118, 187, 115, 167, 230, 99, 71, 225, 136, 190, 250, 55, 29, 186, 209, 106, 249, 128, 137, 153, 173, 182, 206, 68, 108, 38, 17, 165, 211, 69, 183, 74, 75, 43, 189, 59, 81, 189, 108, 108, 161, 183, 4, 24, 213, 237, 145, 162, 209, 80, 110, 35, 125, 172, 242, 209, 135, 3, 47, 212, 183, 137, 131, 95, 148, 95, 62, 211, 138, 17, 206, 113, 108, 150, 15, 132, 147, 227, 65, 39, 108, 224, 222, 148, 167, 68, 47, 10, 35, 104, 77, 79, 57, 240, 199, 184, 236, 76, 184, 130, 167, 150, 221, 17, 116, 132, 135, 128, 90, 63, 149, 158, 32, 27, 228, 82, 235, 61, 29, 137, 135, 245, 134, 183, 172, 78, 150, 234, 243, 196, 68, 162, 80, 79, 63, 108, 251, 114, 40, 250, 180, 84, 215, 162, 255, 38, 126, 85, 181, 5, 122, 4, 46, 93, 4, 68, 237, 84, 160, 191, 255, 46, 160, 103, 118, 242, 126, 40, 214, 157, 129, 245, 101, 13, 236, 36, 243, 11, 0, 91, 229, 253, 187, 217, 117, 133, 3, 22, 84, 25, 68, 237, 53, 127, 36, 59, 0, 69, 6, 33, 119, 202, 100, 131, 170, 240, 138, 178, 10, 104, 63, 129, 237, 145, 53, 80, 160, 152, 191, 62, 87, 0, 46, 14, 44, 15, 181, 64, 114, 89, 156, 238, 183, 153, 199, 9, 4, 31, 41, 91, 240, 109, 188, 209, 54, 125, 214, 86, 210, 150, 231, 193, 192, 70, 103, 109, 220, 148, 144, 50, 100, 184, 197, 35, 4, 22, 39, 246, 65, 168, 134, 144, 151, 125, 65, 42, 9, 167, 46, 35, 220, 208, 188, 211, 115, 84, 28, 221, 254, 21, 54, 67, 63, 235, 214, 42, 108, 118, 91, 172, 249, 252, 172, 208, 154, 238, 152, 19, 3, 16, 227, 124, 68, 72, 176, 240, 36, 48, 13, 194, 216, 227, 147, 231, 16, 242, 32, 42, 23, 93, 204, 3, 206, 10, 141, 255, 94, 43, 37, 107, 174, 61, 165, 221, 27, 52, 144, 8, 138, 50, 46, 64, 184, 168, 144, 13, 240, 20, 72, 174, 105, 84, 5, 79, 112, 55, 230, 170, 37, 229, 197, 61, 209, 24, 171, 3, 35, 170, 168, 96, 254, 84, 149, 170, 114, 252, 101, 78, 60, 21, 88, 69, 214, 79, 140, 244, 150, 181, 197, 17, 69, 184, 194, 144, 32, 18, 202, 36, 146, 124, 28, 46, 218, 237, 137, 139, 169, 242, 0, 122, 218, 44, 162, 77, 23, 221, 129, 111, 172, 145, 215, 86, 43, 197, 176, 242, 197, 38, 224, 189, 169, 229, 0, 20, 96, 50, 139, 4, 13, 213, 152, 45, 231, 24, 122, 11, 106, 2, 244, 114, 179, 184, 10, 12, 244, 131, 160, 22, 145, 48, 136, 195, 101, 65, 8, 210, 237, 182, 111, 4, 42, 50, 190, 43, 134, 121, 52, 197, 165, 89, 188, 30, 226, 161, 50, 182, 104, 200, 166, 254, 251, 178, 9, 14, 69, 204, 74, 147, 182, 204, 18, 97, 247, 255, 10, 191, 221, 122, 72, 106, 173, 224, 247, 239, 23, 93, 79, 108, 207, 58, 202, 143, 217, 194, 55, 131, 147, 192, 171, 139, 19, 49, 204, 51, 137, 63, 238, 115, 140, 41, 12, 27, 194, 16, 50, 168, 155, 208, 27, 33, 229, 87, 219, 56, 37, 100, 62, 97, 215, 183, 41, 134, 54, 211, 199, 33, 109, 83, 184, 155, 13, 156, 140, 180, 220, 142, 220, 57, 232, 80, 151, 241, 250, 170, 52, 224, 59, 38, 10, 214, 33, 219, 21, 82, 10, 227, 243, 215, 241, 165, 244, 248, 115, 103, 1, 28, 111, 6, 135, 178, 161, 167, 193, 5, 39, 62, 100, 216, 217, 155, 211, 203, 128, 81, 161, 77, 44, 82, 85, 255, 30, 80, 161, 236, 128, 216, 9, 229, 56, 174, 224, 68, 69, 25, 119, 169, 240, 7, 229, 5, 149, 141, 47, 195, 102, 190, 163, 179, 195, 80, 207, 61, 154, 71, 100, 111, 192, 98, 205, 22, 243, 108, 217, 14, 228, 118, 44, 87, 247, 34, 171, 180, 164, 124, 187, 194, 161, 39, 140, 22, 63, 147, 114, 190, 241, 248, 33, 44, 226, 29, 195, 99, 36, 213, 180, 66, 3, 7, 91, 49, 150, 140, 233, 99, 57, 0, 197, 106, 6, 93, 147, 230, 140, 51, 124, 154, 97, 181, 225, 247, 163, 35, 64, 5, 127, 110, 225, 62, 121, 23, 180, 214, 110, 230, 61, 127, 57, 36, 180, 102, 130, 75, 102, 155, 195, 154, 204, 254, 189, 198, 20, 142, 55, 155, 172, 181, 221, 78, 98, 177, 117, 165, 40, 52, 57, 72, 1, 246, 213, 159, 72, 190, 31, 1, 130, 136, 177, 107, 25, 127, 211, 228, 27, 115, 158, 59, 21, 83, 96, 82, 83, 78, 151, 73, 224, 226, 200, 79, 24, 11, 139, 201, 166, 188, 99, 228, 10, 203, 185, 161, 36, 167, 119, 158, 107, 165, 221, 161, 174, 87, 61, 239, 20, 255, 96, 122, 181, 239, 138, 8, 155, 82, 37, 24, 168, 227, 21, 177, 28, 252, 190, 236, 89, 243, 60, 232, 103, 12, 126, 129, 246, 143, 27, 220, 252, 141, 96, 57, 123, 250, 121, 43, 212, 247, 125, 148, 33, 204, 137, 190, 145, 57, 101, 52, 101, 78, 219, 199, 194, 126, 106, 250, 86, 44, 141, 40, 54, 67, 131, 80, 228, 105, 117, 39, 240, 128, 208, 17, 215, 11, 32, 205, 2, 75, 200, 89, 219, 28, 205, 141, 117, 3, 36, 58, 156, 18, 95, 7, 220, 252, 7, 146, 100, 221, 69, 120, 42, 233, 247, 2, 143, 214, 188, 58, 214, 99, 212, 91, 176, 9, 117, 105, 22, 0, 54, 26, 131, 171, 61, 54, 73, 51, 100, 178, 32, 183, 148, 180, 44, 211, 42, 251, 138, 157, 218, 244, 165, 0, 136, 40, 235, 192, 96, 65, 41, 8, 116, 114, 238, 41, 69, 200, 36, 38, 75, 46, 49, 233, 130, 9, 192, 57, 3, 132, 31, 129, 229, 96, 211, 88, 150, 88, 135, 115, 51, 242, 53, 239, 34, 181, 206, 166, 191, 126, 161, 78, 134, 189, 234, 187, 73, 54, 177, 160, 242, 183, 54, 231, 36, 57, 127, 88, 252, 167, 112, 141, 34, 51, 11, 9, 242, 221, 44, 252, 147, 250, 150, 130, 253, 149, 211, 14, 128, 75, 230, 68, 63, 2, 101, 233, 1, 58, 32, 24, 141, 146, 26, 21, 234, 83, 111, 16, 230, 187, 229, 152, 84, 156, 173, 80, 81, 249, 76, 162, 41, 213, 27, 116, 151, 13, 3, 101, 21, 10, 86, 12, 80, 192, 118, 104, 133, 14, 0, 19, 94, 45, 238, 229, 92, 229, 32, 159, 80, 84, 178, 110, 14, 102, 97, 127, 136, 172, 5, 180, 38, 114, 82, 196, 67, 140, 218, 180, 253, 26, 217, 160, 0, 125, 2, 211, 3, 173, 198, 92, 217, 167, 195, 177, 114, 214, 11, 169, 243, 69, 112, 238, 2, 121, 54, 163, 138, 43, 144, 39, 96, 145, 201, 251, 165, 166, 228, 248, 51, 55, 230, 24, 194, 83, 112, 125, 245, 213, 36, 79, 51, 79, 168, 198, 164, 236, 143, 176, 131, 243, 161, 201, 46, 54, 132, 9, 14, 154, 182, 31, 122, 35, 238, 233, 115, 224, 83, 44, 176, 26, 15, 31, 1, 160, 104, 18, 235, 103, 107, 1, 35, 221, 74, 206, 8, 207, 168, 166, 147, 51, 189, 213, 6, 244, 172, 145, 114, 56, 83, 121, 231, 215, 136, 174, 58, 174, 7, 7, 197, 1, 1, 125, 219, 115, 221, 25, 96, 85, 3, 84, 218, 47, 191, 148, 134, 97, 114, 195, 228, 121, 5, 246, 10, 236, 83, 85, 149, 179, 42, 154, 148, 51, 43, 192, 175, 226, 7, 128, 38, 31, 224, 253, 76, 199, 37, 214, 163, 56, 83, 74, 238, 47, 117, 139, 224, 68, 75, 114, 0, 161, 88, 29, 134, 54, 0, 209, 128, 171, 150, 147, 177, 37, 136, 69, 253, 89, 179, 182, 182, 129, 43, 66, 66, 166, 122, 229, 14, 203, 70, 224, 38, 57, 147, 253, 178, 93, 201, 209, 3, 61, 29, 201, 12, 224, 69, 215, 123, 221, 204, 40, 198, 0, 60, 131, 98, 92, 63, 215, 92, 84, 230, 186, 64, 76, 239, 206, 243, 182, 224, 248, 52, 68, 151, 193, 126, 238, 86, 66, 89, 164, 231, 3, 68, 92, 5, 133, 241, 173, 96, 244, 149, 127, 102, 188, 225, 225, 199, 181, 57, 58, 236, 245, 151, 65, 26, 41, 47, 84, 34, 18, 220, 240, 249, 129, 83, 195, 163, 216, 167, 229, 159, 139, 254, 230, 24, 95, 17, 3, 212, 112, 22, 132, 55, 235, 139, 43, 52, 5, 180, 64, 156, 237, 225, 44, 76, 230, 113, 77, 39, 249, 183, 75, 245, 23, 229, 33, 3, 255, 236, 41, 64, 197, 104, 98, 86, 113, 10, 97, 25, 232, 124, 28, 28, 13, 28, 5, 0, 76, 223, 89, 151, 78, 120, 139, 143, 23, 80, 70, 17, 185, 14, 76, 220, 4, 140, 132, 111, 71, 40, 67, 166, 146, 48, 10, 199, 51, 72, 10, 207, 66, 236, 30, 131, 16, 199, 104, 159, 95, 112, 223, 199, 155, 158, 231, 212, 162, 86, 80, 72, 203, 7, 71, 69, 143, 120, 84, 39, 69, 20, 19, 129, 61, 83, 135, 140, 137, 135, 203, 237, 204, 128, 97, 253, 214, 98, 104, 214, 57, 104, 31, 185, 67, 108, 147, 133, 178, 191, 153, 253, 17, 91, 149, 88, 215, 128, 103, 204, 95, 44, 137, 163, 117, 134, 129, 225, 185, 62, 180, 16, 71, 75, 123, 94, 10, 140, 37, 137, 217, 1, 204, 195, 70, 85, 57, 15, 47, 16, 22, 62, 22, 152, 207, 75, 135, 103, 142, 1, 10, 166, 177, 174, 152, 62, 125, 202, 98, 92, 153, 103, 19, 164, 53, 181, 76, 113, 146, 65, 17, 185, 94, 193, 156, 254, 185, 59, 100, 173, 227, 33, 17, 202, 189, 127, 255, 246, 97, 167, 94, 48, 168, 119, 119, 141, 122, 205, 213, 26, 16, 231, 11, 86, 94, 38, 116, 105, 177, 52, 147, 41, 211, 150, 137, 95, 237, 18, 245, 10, 209, 100, 209, 3, 84, 180, 213, 47, 251, 48, 51, 81, 101, 188, 67, 111, 243, 231, 65, 95, 163, 138, 2, 156, 129, 245, 98, 146, 246, 212, 166, 160, 147, 75, 176, 2, 193, 65, 230, 199, 117, 21, 56, 134, 163, 186, 115, 148, 207, 251, 145, 153, 232, 227, 97, 195, 93, 243, 90, 112, 35, 168, 151, 232, 225, 196, 156, 207, 188, 208, 79, 109, 82, 148, 83, 159, 63, 96, 211, 132, 178, 248, 83, 106, 231, 202, 1, 7, 57, 62, 177, 220, 133, 160, 136, 150, 242, 53, 20, 186, 201, 19, 90, 9, 216, 62, 193, 83, 199, 46, 14, 248, 154, 58, 3, 168, 45, 5, 40, 209, 223, 233, 69, 232, 67, 167, 163, 56, 59, 160, 53, 125, 231, 88, 116, 243, 171, 250, 109, 195, 85, 109, 125, 29, 163, 168, 124, 240, 24, 154, 38, 51, 221, 131, 223, 34, 172, 147, 3, 222, 255, 25, 202, 143, 78, 171, 22, 185, 198, 161, 51, 41, 108, 112, 84, 23, 98, 76, 54, 251, 149, 141, 211, 163, 249, 138, 135, 107, 206, 114, 177, 202, 1, 181, 2, 200, 131, 83, 148, 69, 170, 248, 81, 208, 38, 194, 73, 128, 147, 121, 166, 212, 43, 71, 243, 66, 197, 248, 75, 128, 23, 175, 106, 130, 202, 207, 162, 252, 11, 28, 152, 130, 64, 238, 200, 95, 112, 141, 48, 51, 201, 198, 145, 66, 173, 213, 142, 29, 159, 241, 183, 190, 244, 33, 236, 73, 234, 210, 67, 128, 185, 62, 249, 26, 192, 136, 142, 49, 17, 23, 71, 95, 254, 136, 134, 169, 83, 138, 250, 134, 239, 52, 180, 27, 199, 12, 33, 45, 121, 247, 201, 26, 151, 111, 26, 185, 154, 195, 200, 32, 233, 88, 215, 70, 140, 137, 124, 98, 40, 137, 70, 94, 2, 129, 6, 69, 219, 11, 11, 233, 157, 3, 191, 98, 89, 118, 17, 185, 8, 218, 170, 105, 36, 64, 202, 56, 13, 248, 35, 219, 17, 234, 34, 182, 212, 127, 153, 2, 20, 139, 136, 15, 162, 250, 152, 212, 24, 100, 193, 202, 238, 233, 111, 141, 233, 246, 127, 82, 31, 77, 32, 129, 81, 34, 227, 203, 50, 1, 179, 148, 50, 159, 28, 148, 197, 236, 248, 181, 16, 232, 45, 6, 212, 121, 53, 231, 179, 97, 176, 66, 68, 178, 176, 64, 206, 122, 146, 46, 86, 100, 43, 125, 98, 238, 201, 108, 167, 87, 246, 20, 70, 167, 9, 98, 115, 253, 11, 122, 70, 219, 71, 20, 11, 184, 196, 181, 104, 159, 124, 33, 228, 107, 190, 30, 77, 220, 233, 77, 37, 8, 32, 61, 168, 19, 112, 200, 59, 212, 26, 93, 215, 190, 221, 58, 10, 159, 81, 98, 31, 5, 64, 55, 137, 23, 19, 47, 105, 61, 92, 73, 37, 192, 86, 225, 7, 69, 208, 234, 164, 138, 196, 241, 187, 83, 240, 59, 239, 135, 10, 9, 157, 63, 26, 207, 125, 55, 146, 102, 164, 92, 105, 98, 234, 147, 100, 146, 131, 164, 153, 222, 32, 242, 137, 137, 6, 93, 194, 25, 4, 85, 69, 116, 155, 46, 107, 181, 14, 170, 101, 166, 210, 11, 124, 190, 214, 186, 48, 124, 38, 153, 128, 95, 244, 227, 65, 191, 230, 171, 15, 192, 252, 21, 253, 26, 222, 25, 201, 58, 59, 2, 65, 191, 108, 219, 99, 75, 201, 251, 137, 57, 123, 47, 114, 85, 163, 249, 196, 216, 235, 49, 27, 141, 95, 18, 62, 102, 174, 81, 173, 56, 102, 34, 47, 156, 77, 3, 232, 149, 155, 227, 226, 254, 41, 105, 252, 134, 212, 44, 64, 9, 34, 166, 234, 46, 3, 50, 132, 105, 178, 110, 38, 86, 139, 8, 239, 218, 122, 32, 241, 79, 43, 149, 192, 90, 108, 28, 35, 47, 26, 227, 169, 92, 150, 131, 155, 226, 250, 239, 73, 67, 151, 84, 92, 173, 115, 7, 36, 103, 184, 10, 160, 237, 247, 189, 188, 145, 114, 181, 151, 28, 71, 251, 238, 90, 0, 26, 208, 123, 104, 136, 144, 214, 242, 137, 178, 119, 23, 84, 98, 7, 239, 17, 195, 130, 185, 135, 27, 23, 111, 205, 19, 52, 140, 121, 134, 18, 50, 32, 141, 79, 134, 177, 59, 5, 190, 232, 112, 128, 96, 165, 99, 88, 167, 240, 186, 170, 216, 176, 130, 24, 214, 56, 223, 20, 188, 0, 30, 31, 66, 71, 110, 3, 233, 80, 220, 147, 135, 90, 24, 160, 137, 158, 58, 134, 240, 221, 75, 243, 151, 214, 28, 4, 150, 8, 15, 202, 178, 240, 122, 231, 219, 197, 46, 240, 70, 92, 232, 184, 178, 56, 64, 249, 10, 207, 230, 172, 181, 0, 23, 112, 50, 205, 183, 16, 58, 140, 50, 242, 197, 108, 158, 39, 225, 184, 211, 246, 21, 255, 56, 232, 67, 5, 130, 161, 104, 6, 176, 142, 184, 21, 42, 246, 172, 246, 236, 28, 255, 231, 163, 19, 126, 17, 176, 37, 121, 72, 202, 113, 71, 188, 184, 196, 105, 45, 64, 221, 191, 53, 81, 32, 160, 112, 0, 36, 243, 56, 127, 157, 117, 150, 212, 134, 150, 112, 210, 162, 214, 122, 87, 222, 74, 153, 116, 238, 170, 81, 103, 63, 230, 46, 69, 31, 223, 12, 32, 81, 157, 2, 65, 40, 142, 77, 92, 190, 214, 70, 94, 248, 87, 30, 148, 92, 243, 200, 146, 220, 185, 135, 174, 232, 81, 8, 126, 130, 15, 250, 76, 19, 112, 155, 218, 8, 166, 137, 248, 134, 156, 22, 173, 131, 44, 96, 115, 211, 148, 140, 95, 14, 189, 54, 32, 240, 150, 75, 99, 191, 74, 189, 29, 52, 209, 168, 229, 100, 80, 228, 100, 220, 176, 104, 115, 202, 29, 34, 136, 103, 39, 79, 14, 221, 51, 130, 152, 197, 87, 140, 92, 107, 3 }; +const compressed_data = [_]u8{ 40, 181, 47, 253, 164, 156, 121, 2, 0, 148, 101, 6, 158, 128, 11, 130, 29, 50, 176, 110, 136, 168, 13, 197, 255, 138, 8, 111, 46, 215, 144, 108, 221, 73, 168, 182, 179, 179, 179, 179, 179, 179, 51, 237, 133, 67, 129, 22, 40, 149, 155, 13, 77, 238, 238, 175, 34, 93, 183, 136, 45, 12, 248, 199, 52, 72, 79, 1, 55, 29, 153, 29, 166, 29, 235, 37, 92, 124, 219, 151, 239, 224, 193, 181, 73, 119, 101, 17, 191, 237, 69, 28, 40, 90, 23, 246, 210, 75, 200, 80, 249, 38, 68, 112, 232, 47, 107, 117, 80, 218, 229, 37, 108, 104, 236, 17, 254, 137, 39, 108, 176, 212, 110, 10, 196, 195, 108, 211, 246, 97, 118, 226, 9, 27, 38, 158, 208, 49, 241, 132, 10, 152, 126, 158, 112, 225, 61, 161, 130, 79, 135, 226, 158, 112, 225, 158, 176, 193, 216, 61, 225, 2, 187, 39, 84, 240, 134, 111, 218, 233, 144, 178, 116, 7, 148, 108, 39, 125, 178, 111, 202, 94, 211, 137, 94, 27, 180, 246, 223, 2, 14, 11, 126, 189, 100, 84, 49, 80, 154, 90, 78, 84, 54, 224, 150, 205, 61, 225, 162, 45, 115, 127, 45, 35, 238, 9, 25, 223, 152, 113, 79, 216, 144, 176, 177, 48, 78, 238, 9, 23, 205, 139, 147, 123, 122, 169, 139, 123, 194, 7, 4, 247, 132, 142, 79, 135, 178, 214, 50, 79, 99, 135, 188, 35, 222, 202, 73, 175, 126, 173, 191, 237, 233, 100, 63, 27, 106, 204, 180, 116, 190, 217, 241, 214, 138, 109, 42, 225, 111, 245, 78, 55, 209, 76, 241, 73, 151, 186, 39, 108, 124, 82, 197, 173, 85, 146, 210, 77, 128, 56, 32, 97, 118, 180, 57, 33, 135, 239, 130, 144, 164, 246, 130, 180, 237, 242, 8, 114, 223, 95, 72, 4, 181, 69, 238, 9, 31, 216, 113, 152, 120, 167, 89, 165, 56, 88, 79, 3, 39, 189, 246, 63, 208, 138, 117, 244, 141, 153, 111, 204, 32, 247, 132, 12, 215, 109, 125, 19, 144, 123, 194, 137, 214, 111, 118, 148, 43, 169, 66, 238, 9, 25, 184, 178, 108, 14, 174, 154, 41, 143, 74, 60, 161, 4, 114, 79, 216, 224, 158, 80, 193, 90, 234, 60, 161, 68, 115, 5, 156, 123, 66, 5, 247, 132, 141, 102, 104, 42, 225, 111, 218, 170, 150, 77, 225, 120, 58, 15, 136, 43, 226, 164, 138, 19, 106, 165, 18, 69, 48, 131, 235, 218, 198, 187, 167, 19, 46, 124, 211, 73, 4, 136, 219, 10, 228, 158, 147, 134, 219, 138, 246, 38, 34, 220, 185, 31, 147, 166, 13, 119, 238, 132, 18, 30, 105, 180, 58, 199, 157, 112, 209, 236, 160, 13, 221, 9, 31, 141, 59, 161, 130, 183, 254, 202, 180, 191, 157, 84, 103, 66, 191, 74, 59, 33, 4, 51, 52, 119, 107, 83, 231, 221, 115, 37, 9, 231, 18, 125, 74, 109, 136, 37, 61, 247, 143, 41, 156, 75, 244, 21, 109, 15, 109, 43, 203, 32, 41, 153, 243, 112, 60, 29, 101, 217, 76, 171, 163, 5, 141, 247, 153, 57, 56, 42, 41, 210, 79, 237, 132, 143, 8, 18, 82, 39, 132, 68, 144, 128, 82, 39, 100, 72, 157, 80, 65, 42, 150, 157, 144, 161, 65, 118, 66, 200, 227, 18, 42, 168, 184, 132, 10, 158, 75, 8, 105, 151, 80, 65, 196, 181, 132, 24, 151, 80, 66, 215, 50, 200, 37, 92, 248, 90, 141, 245, 150, 150, 239, 139, 208, 193, 243, 155, 144, 126, 190, 55, 64, 68, 64, 252, 72, 2, 98, 95, 244, 72, 120, 227, 180, 168, 201, 197, 160, 167, 243, 83, 161, 7, 162, 56, 161, 167, 191, 61, 174, 80, 182, 143, 84, 75, 228, 186, 253, 237, 113, 194, 6, 232, 219, 83, 201, 14, 44, 115, 78, 156, 144, 193, 155, 19, 42, 168, 69, 141, 155, 19, 58, 168, 236, 198, 61, 7, 84, 170, 147, 234, 158, 71, 30, 209, 230, 135, 246, 115, 16, 228, 17, 164, 141, 84, 155, 19, 62, 164, 125, 231, 214, 228, 42, 8, 14, 193, 117, 13, 160, 77, 254, 174, 9, 206, 64, 39, 173, 222, 180, 237, 116, 252, 129, 206, 197, 223, 231, 187, 3, 138, 238, 100, 81, 10, 106, 32, 109, 227, 165, 136, 208, 218, 212, 49, 210, 181, 12, 3, 11, 156, 75, 180, 192, 178, 203, 121, 31, 78, 122, 101, 82, 219, 65, 173, 102, 10, 226, 181, 212, 65, 206, 53, 120, 200, 9, 171, 230, 132, 11, 215, 181, 204, 4, 226, 71, 95, 97, 208, 171, 80, 132, 196, 243, 27, 143, 123, 80, 133, 30, 199, 9, 33, 30, 199, 9, 21, 124, 161, 107, 25, 199, 55, 245, 198, 233, 43, 175, 161, 5, 16, 14, 13, 157, 17, 132, 14, 231, 151, 130, 62, 237, 167, 93, 172, 245, 28, 84, 169, 168, 131, 190, 117, 194, 30, 65, 252, 104, 105, 170, 232, 2, 247, 132, 190, 37, 244, 215, 50, 236, 203, 24, 63, 56, 192, 183, 117, 252, 219, 46, 119, 160, 117, 97, 218, 128, 54, 39, 111, 64, 82, 87, 0, 2, 236, 74, 11, 48, 126, 6, 58, 215, 107, 90, 162, 7, 208, 202, 198, 251, 77, 39, 141, 19, 50, 200, 102, 120, 94, 174, 2, 253, 184, 241, 254, 2, 186, 150, 124, 109, 89, 106, 127, 131, 36, 229, 187, 51, 90, 159, 92, 218, 188, 30, 211, 120, 63, 187, 89, 138, 111, 202, 22, 172, 199, 68, 180, 123, 30, 130, 158, 231, 183, 95, 82, 23, 128, 175, 66, 19, 184, 112, 62, 29, 242, 6, 102, 218, 162, 118, 240, 85, 188, 173, 14, 41, 109, 155, 255, 192, 63, 189, 126, 103, 60, 204, 58, 133, 46, 199, 109, 191, 229, 59, 168, 103, 66, 223, 242, 35, 152, 224, 147, 23, 131, 152, 182, 14, 37, 92, 233, 167, 218, 9, 253, 84, 187, 216, 91, 62, 132, 134, 125, 142, 214, 111, 219, 14, 233, 90, 242, 23, 52, 188, 34, 28, 45, 238, 6, 185, 216, 91, 167, 67, 237, 49, 3, 165, 16, 255, 88, 217, 190, 86, 236, 210, 55, 65, 253, 65, 69, 155, 4, 81, 60, 173, 111, 194, 114, 108, 29, 53, 46, 66, 253, 165, 83, 204, 36, 24, 180, 46, 209, 211, 252, 190, 78, 3, 142, 231, 98, 26, 180, 159, 55, 165, 104, 88, 229, 167, 122, 112, 192, 133, 175, 92, 120, 53, 8, 53, 109, 253, 49, 141, 19, 62, 200, 212, 44, 211, 222, 147, 161, 102, 153, 150, 78, 66, 16, 100, 96, 26, 39, 84, 152, 112, 109, 187, 40, 218, 144, 122, 83, 213, 56, 97, 132, 166, 150, 170, 249, 209, 146, 233, 68, 63, 155, 62, 220, 37, 115, 126, 41, 12, 26, 92, 50, 228, 64, 6, 138, 238, 4, 241, 183, 213, 127, 14, 156, 173, 66, 250, 47, 226, 174, 189, 64, 227, 135, 174, 101, 221, 181, 33, 77, 62, 114, 215, 118, 215, 134, 248, 164, 145, 229, 57, 82, 237, 65, 48, 97, 150, 131, 154, 29, 124, 83, 135, 180, 101, 42, 81, 171, 75, 168, 175, 126, 14, 77, 149, 242, 142, 219, 61, 252, 182, 58, 223, 116, 18, 225, 164, 84, 213, 118, 65, 21, 93, 206, 225, 109, 43, 203, 144, 123, 58, 136, 198, 235, 173, 147, 7, 95, 253, 90, 39, 76, 221, 97, 45, 77, 72, 233, 2, 196, 96, 45, 77, 16, 93, 77, 75, 132, 13, 173, 173, 170, 105, 35, 73, 39, 123, 208, 202, 232, 85, 141, 202, 50, 218, 14, 57, 159, 78, 162, 225, 133, 26, 55, 180, 93, 80, 227, 236, 141, 48, 248, 182, 171, 105, 197, 190, 227, 125, 25, 227, 132, 139, 138, 54, 218, 13, 14, 241, 77, 25, 227, 132, 144, 197, 252, 72, 219, 174, 8, 127, 223, 138, 34, 213, 28, 92, 223, 202, 9, 82, 154, 140, 113, 66, 6, 17, 32, 212, 131, 75, 38, 225, 109, 23, 198, 9, 29, 30, 102, 27, 123, 139, 19, 54, 250, 49, 186, 206, 59, 218, 186, 100, 12, 213, 249, 26, 197, 32, 137, 176, 104, 126, 228, 210, 52, 106, 246, 78, 247, 120, 223, 133, 148, 101, 123, 80, 150, 13, 194, 48, 171, 28, 223, 58, 105, 156, 80, 243, 226, 132, 13, 191, 190, 19, 8, 151, 12, 53, 94, 7, 143, 64, 112, 104, 147, 173, 19, 78, 104, 2, 19, 244, 73, 215, 74, 244, 73, 215, 226, 9, 253, 117, 40, 72, 221, 229, 90, 156, 144, 162, 45, 39, 116, 52, 156, 80, 193, 195, 108, 163, 65, 149, 97, 56, 33, 131, 219, 95, 204, 143, 42, 238, 96, 237, 63, 84, 225, 69, 181, 116, 85, 156, 208, 1, 109, 210, 49, 188, 181, 81, 120, 29, 127, 141, 207, 134, 230, 110, 157, 64, 170, 56, 97, 132, 175, 205, 70, 141, 57, 113, 66, 200, 210, 253, 148, 36, 78, 216, 120, 146, 235, 74, 78, 200, 248, 77, 10, 226, 132, 11, 245, 135, 56, 33, 67, 246, 87, 20, 57, 131, 56, 225, 131, 113, 51, 136, 19, 58, 180, 50, 170, 16, 39, 100, 32, 78, 216, 120, 20, 47, 136, 19, 46, 56, 225, 163, 178, 204, 179, 131, 216, 58, 142, 20, 75, 248, 160, 88, 194, 134, 214, 247, 183, 18, 58, 236, 91, 9, 21, 42, 190, 18, 42, 180, 166, 236, 111, 228, 43, 225, 67, 169, 132, 217, 65, 190, 18, 58, 144, 175, 132, 144, 167, 179, 45, 107, 102, 114, 49, 14, 255, 166, 19, 125, 80, 120, 169, 199, 43, 225, 195, 90, 6, 189, 171, 179, 58, 175, 132, 11, 103, 240, 207, 247, 135, 122, 99, 231, 14, 78, 85, 65, 180, 241, 74, 184, 144, 120, 37, 84, 216, 183, 43, 225, 194, 3, 121, 28, 39, 228, 160, 58, 121, 113, 187, 18, 54, 24, 102, 87, 194, 5, 111, 188, 238, 234, 232, 155, 62, 56, 175, 150, 210, 164, 191, 134, 126, 166, 246, 250, 95, 62, 36, 172, 132, 14, 230, 219, 182, 163, 232, 78, 180, 29, 74, 40, 209, 250, 204, 12, 154, 112, 215, 110, 16, 178, 75, 39, 191, 11, 163, 41, 36, 41, 255, 241, 234, 13, 72, 179, 220, 57, 24, 109, 244, 219, 52, 172, 126, 45, 117, 37, 116, 240, 8, 67, 196, 90, 143, 65, 174, 15, 141, 194, 10, 81, 228, 167, 210, 230, 132, 90, 173, 132, 13, 87, 150, 205, 225, 17, 8, 239, 187, 124, 151, 196, 103, 130, 208, 216, 35, 104, 129, 7, 95, 251, 239, 193, 64, 107, 196, 251, 46, 135, 47, 67, 53, 253, 138, 34, 196, 229, 74, 168, 32, 193, 167, 212, 126, 240, 198, 251, 217, 14, 68, 208, 104, 254, 85, 42, 73, 200, 104, 236, 145, 132, 11, 173, 21, 93, 200, 35, 9, 33, 252, 173, 202, 110, 253, 166, 137, 65, 154, 70, 81, 51, 131, 26, 123, 100, 193, 211, 185, 94, 234, 77, 184, 128, 122, 46, 8, 31, 223, 54, 161, 130, 171, 77, 168, 160, 54, 161, 195, 59, 39, 8, 109, 66, 136, 133, 35, 104, 19, 54, 76, 154, 162, 77, 200, 160, 24, 36, 237, 57, 9, 25, 240, 8, 210, 37, 73, 235, 144, 4, 123, 203, 128, 52, 120, 223, 133, 92, 233, 231, 122, 76, 27, 240, 197, 252, 19, 85, 14, 82, 45, 44, 23, 114, 74, 34, 141, 240, 8, 74, 198, 237, 36, 108, 116, 163, 176, 147, 144, 97, 87, 66, 157, 106, 37, 236, 36, 132, 184, 166, 101, 39, 97, 68, 43, 102, 78, 66, 134, 10, 52, 124, 69, 213, 90, 39, 97, 68, 219, 124, 238, 137, 58, 9, 29, 188, 173, 234, 36, 92, 184, 183, 96, 143, 65, 161, 205, 239, 223, 116, 87, 138, 240, 102, 214, 220, 173, 72, 226, 11, 225, 186, 146, 164, 78, 66, 9, 39, 125, 82, 144, 75, 117, 18, 62, 36, 105, 37, 13, 198, 92, 49, 225, 75, 151, 92, 249, 169, 184, 181, 68, 30, 121, 164, 138, 219, 68, 243, 226, 212, 240, 77, 25, 51, 6, 30, 249, 247, 253, 78, 39, 33, 227, 213, 59, 157, 132, 11, 214, 233, 36, 92, 80, 187, 114, 210, 22, 105, 106, 218, 202, 104, 51, 0, 241, 164, 108, 116, 61, 136, 96, 177, 119, 144, 3, 215, 253, 253, 166, 168, 245, 83, 118, 58, 9, 37, 58, 157, 132, 14, 136, 138, 54, 218, 107, 25, 212, 240, 114, 240, 160, 158, 9, 105, 211, 82, 75, 39, 33, 67, 75, 39, 161, 194, 174, 212, 234, 144, 172, 116, 18, 46, 176, 108, 73, 58, 9, 23, 148, 244, 214, 28, 212, 190, 231, 186, 206, 29, 74, 191, 217, 157, 170, 66, 20, 94, 43, 29, 111, 160, 146, 93, 141, 198, 30, 137, 168, 122, 43, 85, 20, 162, 236, 169, 104, 202, 152, 161, 108, 95, 63, 85, 67, 91, 22, 190, 233, 36, 124, 72, 154, 153, 132, 11, 254, 141, 153, 132, 12, 223, 118, 161, 198, 36, 100, 76, 154, 50, 9, 23, 22, 38, 161, 2, 143, 64, 88, 120, 45, 136, 73, 232, 104, 205, 174, 68, 173, 223, 52, 33, 164, 241, 126, 126, 211, 109, 70, 107, 105, 66, 8, 253, 236, 69, 151, 38, 108, 248, 4, 36, 42, 225, 194, 87, 82, 66, 5, 100, 104, 154, 151, 132, 11, 188, 36, 108, 52, 47, 9, 21, 40, 153, 80, 129, 175, 119, 58, 159, 9, 27, 43, 159, 103, 66, 6, 198, 10, 57, 158, 9, 25, 206, 231, 122, 83, 71, 234, 153, 208, 0, 234, 153, 80, 161, 237, 226, 153, 144, 161, 117, 187, 51, 225, 130, 87, 103, 194, 133, 149, 109, 85, 103, 66, 134, 234, 165, 19, 119, 240, 41, 181, 81, 3, 255, 166, 173, 241, 210, 153, 48, 226, 183, 162, 72, 251, 61, 47, 228, 109, 243, 93, 38, 132, 172, 108, 118, 153, 112, 145, 191, 46, 19, 66, 154, 73, 203, 132, 11, 191, 12, 114, 120, 78, 24, 180, 98, 87, 166, 109, 252, 187, 32, 139, 114, 172, 75, 164, 254, 150, 177, 66, 234, 79, 210, 118, 177, 199, 81, 203, 132, 143, 39, 151, 227, 127, 137, 90, 38, 132, 104, 197, 50, 212, 51, 53, 212, 51, 161, 165, 44, 19, 58, 84, 115, 210, 70, 250, 235, 15, 106, 81, 171, 254, 186, 182, 174, 149, 9, 25, 240, 193, 1, 162, 218, 46, 104, 173, 76, 216, 112, 139, 82, 154, 137, 67, 154, 230, 26, 117, 145, 6, 102, 27, 4, 241, 86, 183, 43, 19, 50, 180, 151, 93, 153, 112, 129, 14, 250, 169, 86, 38, 92, 52, 10, 55, 116, 178, 159, 75, 81, 68, 184, 39, 97, 94, 72, 215, 146, 16, 46, 41, 238, 206, 167, 243, 85, 218, 15, 124, 149, 54, 175, 227, 233, 32, 103, 208, 130, 214, 38, 91, 178, 134, 166, 223, 56, 73, 168, 231, 130, 142, 9, 36, 12, 128, 66, 16, 33, 161, 130, 250, 82, 60, 194, 82, 251, 33, 142, 47, 35, 233, 34, 215, 127, 30, 92, 255, 89, 112, 65, 255, 89, 208, 161, 21, 235, 13, 231, 155, 166, 11, 233, 63, 11, 62, 244, 159, 5, 21, 180, 237, 122, 22, 100, 240, 8, 114, 75, 89, 112, 241, 240, 226, 111, 65, 6, 254, 237, 126, 11, 46, 52, 101, 191, 66, 220, 80, 69, 49, 190, 224, 249, 215, 118, 46, 61, 114, 60, 223, 27, 94, 19, 45, 159, 124, 218, 91, 144, 193, 73, 159, 148, 199, 82, 237, 45, 216, 208, 222, 130, 10, 146, 173, 183, 224, 66, 54, 237, 68, 107, 189, 5, 29, 107, 189, 5, 21, 156, 225, 170, 56, 33, 127, 223, 246, 215, 38, 107, 172, 253, 71, 209, 90, 255, 211, 225, 3, 165, 153, 183, 224, 194, 218, 127, 190, 144, 164, 116, 146, 100, 30, 97, 52, 74, 58, 71, 74, 29, 154, 43, 79, 219, 201, 3, 255, 2, 103, 235, 56, 68, 189, 117, 162, 253, 244, 77, 128, 168, 91, 167, 234, 36, 214, 90, 230, 49, 129, 59, 188, 65, 217, 62, 250, 150, 43, 223, 4, 93, 64, 29, 148, 73, 111, 15, 77, 36, 94, 43, 81, 43, 195, 188, 5, 33, 15, 179, 186, 150, 183, 32, 67, 127, 23, 74, 254, 5, 27, 201, 191, 160, 66, 99, 95, 80, 65, 146, 212, 73, 19, 144, 192, 23, 108, 76, 64, 2, 95, 80, 161, 213, 57, 125, 71, 190, 160, 163, 249, 147, 70, 218, 162, 87, 231, 182, 57, 242, 5, 39, 92, 221, 38, 109, 228, 11, 58, 124, 193, 134, 36, 229, 251, 174, 132, 220, 181, 221, 147, 144, 3, 73, 202, 247, 86, 167, 64, 190, 105, 147, 173, 254, 208, 251, 46, 111, 117, 138, 239, 122, 44, 187, 42, 30, 102, 23, 180, 102, 253, 33, 189, 27, 123, 4, 105, 147, 146, 148, 174, 193, 202, 135, 217, 137, 149, 223, 148, 105, 167, 182, 232, 97, 214, 25, 212, 224, 170, 208, 195, 108, 171, 227, 54, 161, 135, 89, 71, 241, 48, 235, 144, 164, 116, 237, 73, 18, 47, 228, 75, 126, 196, 62, 148, 218, 227, 186, 235, 119, 57, 111, 88, 196, 143, 88, 106, 191, 235, 90, 82, 165, 118, 3, 202, 246, 219, 65, 12, 36, 41, 29, 68, 21, 55, 212, 44, 65, 173, 132, 183, 170, 84, 167, 93, 107, 211, 150, 153, 152, 52, 125, 124, 210, 87, 229, 224, 173, 78, 225, 109, 202, 195, 195, 236, 106, 222, 59, 133, 75, 214, 234, 173, 255, 174, 204, 182, 100, 72, 215, 243, 222, 128, 162, 239, 13, 142, 167, 131, 182, 93, 181, 31, 81, 120, 185, 75, 134, 220, 211, 221, 91, 139, 187, 105, 235, 200, 61, 189, 179, 251, 166, 11, 48, 211, 22, 169, 226, 22, 209, 218, 94, 2, 90, 43, 118, 37, 107, 110, 104, 1, 237, 164, 232, 82, 106, 153, 174, 101, 22, 52, 111, 81, 229, 208, 224, 51, 53, 78, 15, 238, 9, 181, 212, 149, 90, 215, 58, 111, 217, 255, 64, 127, 155, 194, 96, 226, 18, 75, 91, 123, 12, 82, 44, 209, 46, 78, 137, 123, 193, 9, 103, 122, 65, 5, 213, 76, 105, 184, 167, 163, 111, 203, 78, 146, 218, 11, 62, 56, 175, 82, 123, 65, 135, 247, 76, 189, 32, 131, 68, 57, 114, 82, 203, 94, 208, 177, 40, 5, 169, 246, 183, 205, 94, 176, 193, 25, 26, 175, 183, 236, 5, 31, 116, 41, 197, 12, 53, 230, 22, 124, 52, 188, 239, 114, 110, 65, 6, 111, 156, 182, 194, 11, 50, 154, 86, 120, 193, 5, 137, 170, 240, 130, 144, 79, 234, 21, 94, 176, 161, 149, 226, 17, 135, 82, 120, 65, 136, 182, 126, 188, 32, 195, 167, 54, 4, 105, 188, 244, 227, 5, 23, 106, 223, 163, 240, 71, 37, 232, 151, 49, 242, 181, 255, 30, 52, 222, 207, 102, 39, 217, 208, 163, 18, 119, 93, 15, 60, 157, 170, 61, 110, 14, 143, 232, 250, 231, 5, 25, 142, 55, 47, 184, 224, 142, 23, 84, 112, 210, 39, 197, 81, 225, 229, 125, 215, 202, 167, 80, 4, 12, 244, 77, 26, 116, 53, 13, 127, 171, 218, 229, 233, 14, 15, 179, 207, 13, 194, 27, 167, 125, 208, 79, 69, 241, 172, 198, 200, 93, 162, 85, 146, 214, 53, 47, 78, 104, 129, 203, 126, 111, 84, 120, 121, 230, 5, 23, 76, 225, 97, 22, 23, 186, 120, 65, 5, 73, 226, 5, 177, 88, 5, 61, 60, 138, 23, 124, 60, 138, 23, 84, 72, 170, 120, 193, 133, 102, 196, 11, 62, 218, 130, 1, 240, 8, 114, 108, 65, 6, 199, 211, 233, 183, 22, 100, 44, 199, 30, 34, 129, 98, 143, 133, 215, 130, 248, 145, 231, 164, 101, 66, 142, 173, 190, 181, 32, 131, 167, 95, 27, 169, 222, 69, 223, 90, 208, 225, 169, 124, 34, 135, 210, 69, 132, 6, 8, 58, 172, 253, 215, 248, 69, 236, 224, 216, 163, 133, 215, 99, 225, 181, 96, 3, 195, 172, 66, 146, 182, 107, 65, 199, 178, 253, 141, 19, 82, 234, 174, 107, 193, 7, 143, 168, 36, 215, 130, 139, 247, 93, 146, 148, 107, 193, 198, 90, 48, 0, 191, 11, 54, 210, 54, 102, 218, 24, 196, 178, 11, 105, 187, 99, 212, 150, 211, 239, 130, 15, 93, 74, 45, 229, 209, 239, 130, 143, 9, 38, 112, 187, 224, 2, 5, 36, 184, 93, 112, 33, 2, 9, 64, 224, 118, 65, 6, 151, 77, 89, 184, 106, 191, 99, 47, 210, 240, 166, 173, 82, 236, 188, 50, 20, 89, 24, 194, 97, 173, 68, 170, 237, 130, 140, 221, 228, 217, 118, 65, 198, 68, 226, 208, 208, 44, 211, 56, 161, 230, 238, 101, 20, 17, 234, 153, 208, 227, 233, 108, 187, 32, 67, 196, 163, 245, 215, 50, 200, 155, 92, 12, 154, 192, 4, 181, 93, 112, 66, 146, 210, 161, 182, 11, 50, 60, 2, 161, 217, 5, 33, 202, 246, 63, 27, 53, 187, 224, 162, 217, 5, 29, 141, 61, 130, 154, 93, 144, 209, 218, 232, 183, 69, 205, 46, 248, 240, 8, 90, 181, 11, 46, 244, 233, 155, 0, 113, 62, 221, 68, 115, 236, 248, 85, 47, 17, 115, 13, 194, 19, 43, 212, 250, 175, 11, 70, 184, 173, 120, 215, 5, 23, 75, 221, 117, 65, 6, 109, 90, 54, 146, 32, 129, 211, 5, 31, 223, 116, 65, 5, 73, 39, 115, 82, 211, 5, 27, 173, 191, 116, 65, 134, 86, 167, 186, 32, 131, 46, 216, 88, 118, 33, 180, 28, 66, 234, 185, 32, 4, 193, 4, 69, 0, 69, 192, 17, 66, 78, 66, 42, 73, 186, 160, 2, 34, 72, 112, 146, 46, 200, 208, 57, 65, 79, 69, 46, 164, 212, 130, 16, 143, 48, 60, 162, 138, 27, 106, 120, 247, 116, 90, 144, 193, 35, 170, 56, 45, 11, 50, 36, 112, 69, 206, 231, 130, 140, 198, 251, 235, 12, 209, 180, 85, 42, 221, 67, 219, 166, 147, 57, 252, 227, 39, 151, 218, 110, 144, 123, 114, 111, 94, 28, 90, 179, 43, 145, 123, 114, 79, 238, 185, 224, 194, 61, 211, 248, 151, 40, 173, 231, 130, 18, 11, 175, 6, 57, 158, 11, 54, 86, 191, 8, 38, 104, 168, 141, 96, 130, 8, 38, 136, 96, 2, 138, 134, 45, 138, 96, 130, 8, 38, 136, 48, 129, 58, 132, 70, 211, 8, 18, 42, 12, 18, 207, 215, 230, 119, 135, 55, 184, 254, 227, 78, 233, 92, 89, 54, 7, 247, 73, 83, 134, 68, 179, 76, 155, 80, 103, 199, 24, 242, 224, 174, 137, 219, 161, 93, 9, 169, 51, 38, 77, 103, 35, 130, 9, 144, 122, 46, 184, 72, 219, 223, 52, 61, 157, 11, 46, 236, 74, 40, 155, 174, 92, 208, 161, 169, 229, 202, 5, 29, 212, 173, 107, 114, 193, 133, 54, 217, 52, 185, 160, 195, 251, 46, 228, 170, 153, 162, 114, 193, 134, 182, 141, 202, 5, 25, 60, 226, 248, 29, 142, 231, 114, 73, 202, 5, 27, 30, 169, 52, 98, 24, 8, 47, 56, 151, 232, 153, 108, 165, 255, 218, 120, 59, 25, 132, 255, 245, 103, 201, 5, 194, 4, 171, 246, 26, 188, 162, 205, 21, 49, 208, 198, 139, 36, 229, 130, 12, 39, 229, 242, 44, 185, 96, 163, 241, 122, 150, 92, 112, 241, 48, 203, 144, 36, 117, 210, 90, 153, 220, 246, 4, 78, 250, 164, 60, 36, 43, 41, 234, 158, 71, 227, 149, 170, 229, 59, 68, 131, 195, 155, 188, 9, 3, 17, 32, 64, 218, 228, 59, 133, 115, 57, 65, 225, 229, 145, 133, 153, 52, 237, 126, 175, 174, 189, 150, 121, 22, 59, 120, 238, 202, 244, 214, 201, 182, 167, 150, 39, 136, 31, 73, 146, 58, 9, 41, 237, 92, 73, 85, 123, 15, 180, 190, 111, 163, 29, 65, 115, 107, 182, 162, 223, 56, 33, 237, 125, 19, 18, 144, 203, 105, 55, 64, 89, 54, 109, 213, 158, 2, 18, 224, 174, 162, 141, 118, 3, 180, 249, 81, 63, 167, 169, 31, 51, 75, 29, 85, 60, 242, 233, 24, 39, 3, 44, 128, 1, 147, 166, 72, 21, 183, 150, 186, 152, 151, 4, 52, 109, 215, 178, 14, 1, 2, 9, 174, 84, 34, 157, 236, 191, 164, 222, 56, 185, 237, 119, 68, 225, 197, 40, 96, 1, 16, 36, 60, 64, 130, 4, 170, 56, 109, 123, 12, 171, 123, 222, 1, 16, 168, 104, 163, 141, 30, 73, 218, 247, 6, 44, 160, 213, 61, 87, 76, 89, 54, 196, 48, 106, 102, 30, 149, 32, 253, 76, 187, 220, 83, 77, 219, 126, 170, 28, 160, 244, 159, 99, 12, 129, 171, 123, 174, 212, 180, 117, 128, 82, 199, 201, 145, 36, 241, 90, 34, 144, 0, 130, 8, 68, 112, 69, 8, 64, 0, 1, 20, 128, 90, 157, 203, 166, 32, 166, 239, 143, 35, 143, 36, 197, 239, 17, 104, 125, 215, 247, 100, 140, 83, 211, 118, 109, 246, 63, 192, 181, 19, 80, 241, 136, 106, 187, 32, 2, 80, 120, 49, 223, 8, 112, 188, 21, 117, 64, 1, 248, 1, 254, 244, 250, 189, 113, 66, 238, 185, 146, 163, 74, 126, 123, 12, 224, 146, 33, 10, 230, 118, 160, 189, 20, 109, 93, 236, 141, 83, 46, 109, 137, 102, 226, 186, 235, 219, 54, 109, 18, 43, 203, 134, 82, 177, 108, 137, 214, 172, 243, 115, 187, 231, 91, 29, 183, 139, 48, 223, 118, 20, 202, 178, 33, 73, 123, 78, 66, 206, 167, 107, 125, 101, 217, 233, 6, 160, 44, 219, 186, 178, 108, 72, 87, 211, 146, 13, 224, 249, 109, 203, 180, 85, 170, 58, 95, 211, 216, 183, 221, 46, 166, 241, 126, 182, 101, 187, 84, 165, 42, 6, 28, 192, 219, 254, 218, 183, 160, 135, 217, 182, 204, 153, 2, 28, 79, 197, 107, 98, 169, 98, 134, 38, 168, 226, 17, 181, 249, 169, 144, 78, 152, 105, 31, 192, 91, 151, 89, 197, 12, 85, 60, 210, 76, 220, 117, 45, 185, 157, 19, 244, 77, 89, 227, 222, 73, 83, 6, 76, 154, 62, 171, 111, 118, 108, 162, 162, 22, 66, 181, 29, 210, 182, 171, 45, 242, 206, 101, 177, 119, 154, 124, 228, 192, 35, 13, 172, 156, 68, 52, 222, 231, 92, 235, 24, 39, 180, 46, 91, 23, 166, 10, 104, 230, 160, 156, 168, 137, 42, 6, 154, 183, 232, 3, 111, 12, 210, 79, 181, 192, 221, 83, 211, 86, 45, 102, 208, 183, 100, 175, 41, 122, 111, 12, 180, 145, 178, 108, 79, 46, 231, 171, 10, 224, 74, 37, 119, 74, 214, 170, 146, 33, 239, 137, 248, 209, 202, 214, 223, 69, 241, 174, 17, 111, 112, 199, 237, 144, 54, 173, 12, 85, 60, 130, 244, 77, 6, 176, 28, 63, 154, 236, 155, 160, 200, 151, 129, 231, 183, 179, 113, 183, 139, 113, 192, 61, 87, 106, 188, 170, 120, 185, 74, 3, 242, 173, 156, 168, 75, 134, 180, 45, 163, 170, 129, 126, 54, 186, 84, 161, 181, 50, 45, 80, 241, 8, 250, 148, 218, 15, 120, 243, 103, 115, 82, 133, 30, 102, 85, 219, 5, 9, 224, 225, 219, 46, 87, 136, 182, 67, 21, 67, 236, 74, 168, 177, 116, 201, 5, 23, 150, 46, 207, 178, 228, 130, 140, 206, 37, 23, 92, 208, 223, 133, 94, 4, 19, 44, 216, 136, 96, 130, 5, 21, 52, 44, 207, 129, 252, 59, 232, 121, 39, 32, 212, 115, 65, 110, 2, 75, 244, 188, 72, 251, 85, 184, 227, 137, 170, 5, 141, 25, 227, 4, 97, 157, 72, 251, 85, 36, 74, 60, 173, 111, 2, 170, 36, 58, 252, 178, 93, 72, 63, 187, 178, 12, 122, 42, 220, 142, 173, 111, 14, 73, 98, 38, 209, 218, 52, 188, 32, 46, 97, 118, 30, 16, 13, 47, 212, 188, 69, 213, 67, 103, 68, 87, 194, 220, 96, 194, 121, 43, 137, 11, 173, 90, 209, 74, 34, 195, 121, 43, 137, 34, 112, 74, 162, 35, 2, 167, 52, 239, 236, 22, 172, 9, 254, 48, 119, 109, 87, 81, 10, 109, 78, 72, 162, 28, 61, 217, 21, 72, 107, 214, 37, 137, 25, 68, 146, 152, 73, 148, 35, 167, 36, 78, 104, 243, 59, 98, 217, 233, 144, 83, 18, 31, 36, 202, 145, 166, 157, 168, 66, 207, 18, 204, 180, 69, 78, 73, 100, 52, 127, 210, 214, 56, 33, 167, 36, 50, 240, 157, 144, 83, 18, 23, 143, 79, 169, 141, 156, 146, 24, 81, 217, 181, 148, 68, 6, 109, 236, 184, 137, 247, 92, 200, 117, 178, 216, 181, 209, 179, 26, 23, 96, 178, 159, 173, 142, 237, 2, 169, 61, 94, 84, 33, 101, 236, 74, 73, 116, 224, 84, 151, 107, 179, 227, 146, 169, 63, 188, 247, 50, 191, 73, 73, 124, 36, 159, 36, 42, 84, 242, 115, 146, 200, 224, 106, 201, 181, 12, 126, 219, 162, 156, 36, 50, 114, 146, 168, 224, 157, 102, 151, 211, 172, 131, 222, 181, 105, 222, 2, 173, 88, 127, 215, 230, 127, 137, 140, 137, 214, 202, 50, 218, 142, 255, 37, 66, 248, 95, 226, 163, 85, 210, 118, 57, 154, 70, 145, 82, 11, 250, 169, 237, 17, 8, 250, 186, 28, 227, 135, 198, 173, 101, 226, 127, 137, 142, 134, 151, 54, 45, 157, 228, 160, 218, 46, 136, 255, 37, 54, 92, 55, 237, 98, 135, 84, 51, 197, 61, 93, 131, 93, 9, 61, 188, 156, 42, 20, 1, 231, 95, 34, 132, 243, 47, 241, 177, 9, 253, 170, 151, 200, 240, 198, 235, 188, 234, 37, 66, 160, 254, 79, 124, 56, 213, 229, 144, 5, 165, 101, 252, 137, 14, 78, 209, 157, 160, 166, 14, 105, 74, 231, 136, 241, 39, 82, 232, 239, 66, 11, 127, 98, 99, 225, 79, 84, 72, 254, 68, 133, 117, 217, 212, 113, 196, 83, 34, 168, 229, 186, 231, 250, 196, 6, 110, 143, 44, 244, 115, 149, 50, 182, 175, 222, 128, 101, 167, 123, 215, 158, 240, 71, 37, 16, 214, 254, 131, 240, 251, 168, 68, 37, 187, 86, 34, 181, 199, 83, 251, 121, 251, 101, 187, 24, 118, 82, 42, 3, 39, 165, 62, 217, 157, 16, 214, 254, 163, 208, 167, 111, 2, 132, 199, 47, 219, 181, 116, 173, 236, 116, 16, 214, 126, 123, 232, 87, 223, 202, 201, 132, 190, 149, 19, 93, 255, 220, 206, 59, 40, 99, 95, 255, 234, 144, 166, 161, 167, 95, 251, 233, 215, 126, 248, 42, 109, 125, 250, 38, 160, 137, 138, 254, 99, 188, 28, 90, 127, 217, 174, 134, 21, 65, 18, 230, 182, 201, 88, 33, 9, 115, 132, 55, 72, 152, 29, 244, 91, 121, 104, 253, 95, 166, 223, 116, 34, 225, 164, 212, 198, 14, 117, 82, 38, 36, 241, 85, 16, 19, 79, 168, 145, 218, 227, 137, 11, 148, 247, 68, 5, 10, 47, 6, 185, 186, 199, 65, 189, 117, 2, 97, 205, 204, 123, 98, 131, 122, 235, 36, 251, 209, 163, 146, 54, 225, 235, 41, 134, 104, 109, 101, 218, 162, 252, 84, 206, 28, 190, 120, 97, 143, 163, 214, 172, 123, 162, 195, 2, 127, 117, 127, 208, 120, 191, 27, 239, 59, 118, 80, 197, 13, 77, 124, 171, 59, 131, 40, 116, 169, 150, 206, 131, 51, 72, 215, 194, 212, 61, 241, 209, 180, 109, 85, 77, 91, 219, 161, 215, 230, 60, 113, 34, 2, 19, 136, 32, 65, 98, 26, 121, 4, 2, 4, 205, 249, 221, 211, 137, 121, 34, 196, 19, 27, 118, 165, 221, 228, 203, 90, 153, 60, 209, 209, 233, 137, 10, 46, 61, 81, 33, 91, 122, 226, 130, 174, 37, 31, 121, 34, 195, 19, 27, 79, 118, 39, 242, 68, 134, 242, 207, 119, 212, 224, 105, 93, 107, 191, 19, 27, 223, 137, 16, 95, 57, 217, 238, 68, 198, 195, 108, 119, 34, 195, 164, 233, 78, 92, 248, 148, 142, 113, 66, 79, 191, 35, 102, 209, 195, 48, 235, 146, 77, 56, 41, 181, 185, 233, 187, 100, 159, 171, 65, 69, 85, 91, 213, 30, 64, 80, 247, 60, 63, 183, 131, 192, 96, 194, 182, 151, 154, 126, 83, 143, 120, 7, 77, 253, 248, 155, 221, 161, 105, 151, 47, 134, 121, 78, 131, 235, 182, 122, 122, 74, 91, 155, 150, 221, 169, 15, 218, 180, 236, 135, 78, 152, 185, 100, 141, 247, 92, 14, 253, 108, 253, 198, 251, 73, 189, 245, 37, 86, 238, 111, 91, 134, 43, 170, 218, 54, 253, 134, 207, 53, 81, 81, 213, 22, 65, 168, 182, 140, 163, 245, 215, 50, 14, 79, 235, 100, 229, 155, 160, 143, 86, 134, 89, 5, 145, 164, 92, 208, 147, 221, 137, 142, 198, 219, 94, 195, 37, 197, 245, 243, 185, 81, 119, 162, 131, 97, 86, 161, 238, 68, 70, 67, 207, 111, 39, 46, 158, 214, 55, 1, 229, 118, 162, 67, 169, 106, 250, 21, 69, 254, 77, 217, 107, 58, 81, 226, 201, 238, 244, 166, 19, 27, 222, 116, 162, 130, 122, 167, 107, 58, 145, 17, 161, 113, 211, 137, 12, 78, 211, 137, 10, 77, 39, 42, 80, 170, 147, 117, 79, 135, 180, 19, 27, 240, 181, 255, 144, 67, 51, 212, 61, 143, 116, 178, 78, 234, 68, 72, 46, 220, 46, 145, 193, 223, 105, 214, 219, 78, 56, 159, 14, 53, 203, 52, 78, 104, 57, 151, 216, 96, 31, 63, 14, 84, 113, 170, 64, 40, 172, 218, 126, 211, 38, 23, 165, 44, 104, 254, 100, 252, 47, 247, 45, 128, 154, 86, 236, 127, 179, 115, 207, 29, 90, 155, 230, 45, 170, 144, 62, 51, 109, 6, 17, 82, 50, 137, 148, 204, 153, 194, 57, 98, 81, 235, 144, 36, 35, 193, 238, 218, 206, 149, 129, 50, 110, 39, 77, 168, 231, 34, 209, 58, 217, 86, 11, 22, 149, 136, 189, 117, 46, 209, 161, 238, 121, 176, 102, 198, 91, 246, 67, 60, 173, 111, 2, 164, 149, 97, 222, 130, 84, 211, 6, 213, 212, 185, 196, 71, 195, 148, 115, 137, 12, 30, 241, 94, 229, 92, 98, 195, 145, 164, 237, 98, 160, 138, 155, 174, 101, 8, 224, 234, 120, 118, 196, 174, 212, 128, 154, 38, 231, 18, 27, 18, 229, 188, 56, 151, 232, 224, 239, 179, 211, 185, 196, 134, 243, 233, 26, 122, 21, 122, 230, 70, 206, 37, 66, 218, 46, 168, 85, 173, 125, 11, 114, 46, 241, 65, 130, 238, 239, 218, 127, 16, 77, 219, 148, 253, 147, 166, 77, 91, 95, 165, 221, 58, 105, 245, 7, 146, 182, 11, 181, 54, 13, 39, 83, 39, 185, 68, 115, 183, 106, 115, 66, 146, 182, 11, 194, 73, 159, 11, 146, 180, 93, 146, 182, 235, 225, 205, 221, 218, 192, 188, 133, 159, 219, 161, 166, 237, 55, 59, 109, 164, 109, 155, 166, 249, 169, 34, 212, 61, 63, 128, 39, 101, 163, 11, 81, 120, 49, 104, 129, 87, 215, 118, 232, 155, 238, 218, 213, 240, 190, 222, 234, 218, 46, 64, 20, 234, 164, 76, 42, 121, 185, 135, 38, 222, 153, 23, 8, 175, 197, 46, 209, 161, 185, 68, 5, 154, 94, 250, 186, 68, 70, 98, 181, 46, 145, 65, 157, 148, 105, 93, 34, 67, 127, 21, 183, 227, 18, 27, 21, 117, 137, 14, 9, 20, 115, 188, 123, 58, 81, 184, 59, 145, 58, 41, 93, 34, 196, 37, 6, 192, 223, 245, 209, 115, 226, 196, 55, 251, 211, 18, 23, 78, 250, 100, 79, 75, 100, 172, 165, 142, 163, 167, 37, 66, 168, 111, 75, 124, 248, 51, 34, 232, 245, 45, 145, 65, 215, 46, 204, 30, 142, 59, 161, 134, 109, 131, 71, 158, 84, 72, 125, 75, 124, 160, 190, 37, 42, 232, 155, 160, 214, 172, 171, 66, 223, 18, 29, 24, 131, 123, 21, 88, 111, 173, 170, 61, 135, 79, 169, 141, 248, 23, 123, 7, 241, 67, 88, 235, 235, 122, 222, 157, 230, 113, 59, 175, 146, 237, 119, 137, 87, 215, 118, 84, 180, 209, 214, 102, 248, 55, 101, 77, 54, 227, 174, 169, 233, 155, 160, 142, 212, 101, 114, 93, 192, 86, 49, 90, 62, 169, 225, 205, 139, 83, 243, 226, 228, 80, 139, 245, 173, 134, 36, 229, 162, 240, 90, 250, 52, 232, 175, 67, 81, 218, 142, 252, 166, 77, 50, 135, 166, 218, 13, 164, 229, 147, 244, 61, 36, 41, 215, 210, 44, 104, 189, 37, 66, 214, 91, 162, 66, 171, 183, 196, 5, 101, 217, 12, 106, 188, 14, 248, 145, 146, 112, 79, 16, 240, 209, 182, 225, 133, 86, 110, 98, 71, 149, 5, 170, 56, 245, 4, 84, 105, 73, 90, 247, 185, 24, 84, 145, 136, 224, 105, 223, 211, 254, 67, 237, 123, 40, 66, 67, 235, 123, 242, 163, 8, 18, 79, 134, 190, 162, 143, 34, 72, 168, 116, 218, 239, 179, 53, 235, 40, 66, 163, 176, 114, 220, 10, 125, 210, 165, 190, 191, 30, 67, 17, 28, 208, 165, 22, 181, 186, 106, 63, 59, 218, 247, 184, 209, 190, 8, 181, 221, 160, 125, 46, 251, 253, 153, 23, 180, 143, 226, 155, 54, 118, 140, 19, 82, 237, 31, 128, 235, 90, 6, 1, 250, 185, 188, 101, 71, 56, 233, 241, 55, 252, 46, 231, 107, 113, 39, 7, 173, 216, 223, 150, 14, 161, 255, 184, 181, 117, 45, 89, 177, 174, 237, 18, 74, 4, 57, 72, 106, 25, 69, 112, 254, 37, 79, 184, 36, 49, 115, 136, 149, 219, 250, 201, 22, 212, 180, 85, 201, 107, 93, 162, 69, 41, 232, 105, 102, 202, 80, 123, 32, 241, 100, 13, 109, 2, 16, 44, 100, 177, 119, 38, 156, 102, 157, 8, 173, 239, 106, 59, 194, 117, 53, 204, 77, 243, 80, 214, 31, 10, 202, 149, 220, 12, 131, 214, 73, 58, 210, 181, 140, 246, 187, 46, 72, 251, 158, 75, 117, 101, 226, 197, 64, 215, 146, 206, 113, 43, 212, 52, 217, 12, 184, 174, 37, 63, 63, 149, 132, 235, 74, 152, 31, 60, 2, 225, 59, 157, 78, 213, 116, 101, 130, 200, 109, 136, 126, 178, 109, 249, 128, 86, 38, 94, 40, 2, 106, 128, 11, 71, 8, 101, 205, 78, 106, 234, 160, 70, 97, 37, 233, 100, 136, 65, 179, 147, 90, 34, 131, 42, 110, 14, 142, 16, 203, 46, 55, 129, 37, 46, 220, 4, 150, 168, 224, 17, 164, 234, 61, 228, 249, 77, 188, 116, 34, 73, 204, 34, 214, 254, 251, 231, 214, 254, 99, 160, 177, 243, 143, 107, 188, 234, 241, 74, 78, 73, 212, 170, 118, 82, 0, 127, 199, 184, 221, 3, 3, 60, 162, 138, 219, 2, 20, 144, 147, 140, 36, 192, 93, 151, 74, 117, 22, 80, 247, 188, 0, 60, 177, 66, 107, 130, 227, 178, 155, 7, 16, 192, 141, 166, 100, 90, 191, 45, 34, 192, 187, 237, 228, 57, 201, 8, 3, 206, 75, 209, 250, 255, 22, 163, 150, 91, 181, 68, 170, 233, 55, 110, 198, 193, 162, 152, 101, 123, 22, 248, 92, 142, 233, 51, 160, 85, 237, 132, 219, 33, 101, 251, 237, 53, 122, 109, 207, 106, 1, 173, 109, 243, 27, 63, 208, 197, 222, 26, 28, 160, 105, 163, 138, 31, 90, 155, 134, 151, 132, 54, 39, 180, 11, 162, 43, 19, 171, 180, 93, 3, 222, 120, 63, 211, 50, 251, 220, 30, 104, 253, 182, 14, 52, 109, 223, 217, 113, 192, 218, 80, 52, 222, 79, 237, 49, 158, 246, 159, 149, 45, 209, 211, 220, 232, 103, 90, 160, 249, 115, 61, 182, 142, 82, 123, 252, 129, 115, 137, 30, 102, 151, 99, 137, 143, 230, 79, 181, 43, 39, 104, 177, 119, 28, 75, 140, 104, 188, 222, 58, 65, 170, 165, 183, 58, 150, 24, 161, 77, 186, 43, 67, 142, 37, 62, 28, 75, 84, 160, 109, 25, 85, 76, 177, 68, 135, 71, 208, 243, 251, 77, 213, 34, 254, 109, 13, 39, 212, 184, 34, 89, 226, 2, 79, 106, 170, 154, 58, 85, 40, 209, 34, 150, 24, 177, 54, 31, 249, 147, 148, 149, 248, 240, 136, 182, 117, 43, 145, 161, 46, 29, 127, 84, 116, 57, 198, 9, 165, 227, 86, 98, 195, 202, 55, 65, 209, 59, 179, 149, 8, 81, 141, 217, 74, 100, 240, 8, 132, 103, 173, 196, 133, 182, 93, 170, 37, 99, 156, 144, 246, 91, 43, 81, 226, 43, 250, 168, 53, 187, 18, 29, 238, 140, 118, 37, 46, 90, 221, 82, 7, 81, 56, 169, 83, 61, 119, 113, 179, 18, 27, 60, 242, 48, 251, 173, 43, 209, 161, 180, 211, 113, 164, 141, 43, 86, 166, 149, 8, 33, 73, 233, 24, 155, 76, 1, 8, 34, 16, 225, 153, 108, 133, 22, 248, 39, 107, 102, 208, 36, 146, 248, 240, 230, 110, 69, 147, 72, 162, 99, 87, 66, 147, 72, 226, 226, 93, 223, 4, 109, 84, 201, 72, 34, 68, 215, 146, 223, 155, 200, 240, 8, 132, 135, 157, 196, 133, 75, 152, 157, 68, 134, 166, 18, 126, 132, 178, 185, 73, 148, 208, 201, 174, 116, 170, 18, 7, 245, 92, 208, 55, 109, 18, 29, 169, 154, 54, 137, 12, 106, 187, 65, 77, 226, 226, 249, 109, 143, 49, 78, 200, 191, 211, 73, 168, 73, 156, 144, 96, 2, 8, 80, 107, 203, 36, 54, 214, 122, 14, 210, 182, 12, 147, 248, 240, 8, 114, 77, 100, 104, 125, 247, 116, 82, 133, 92, 19, 27, 82, 123, 156, 105, 226, 162, 249, 179, 181, 105, 131, 150, 93, 223, 116, 87, 66, 76, 19, 27, 184, 173, 64, 76, 37, 46, 34, 72, 64, 173, 75, 37, 50, 90, 85, 242, 66, 46, 153, 166, 126, 236, 232, 253, 69, 84, 98, 3, 119, 109, 165, 18, 27, 88, 106, 191, 35, 165, 18, 29, 186, 158, 119, 196, 143, 42, 14, 41, 149, 248, 224, 173, 78, 250, 100, 72, 169, 68, 136, 183, 46, 236, 53, 164, 109, 23, 82, 42, 17, 162, 181, 233, 251, 46, 244, 77, 39, 138, 24, 43, 164, 84, 34, 3, 73, 74, 183, 40, 5, 45, 246, 14, 122, 117, 79, 164, 84, 162, 3, 74, 37, 42, 232, 92, 175, 105, 137, 86, 170, 68, 136, 54, 217, 252, 222, 208, 252, 153, 252, 49, 11, 163, 202, 68, 235, 187, 84, 137, 150, 42, 102, 72, 39, 20, 191, 146, 197, 252, 205, 159, 218, 9, 249, 131, 174, 37, 83, 227, 253, 148, 248, 200, 79, 137, 10, 174, 253, 62, 149, 73, 251, 249, 206, 128, 4, 109, 242, 93, 177, 243, 202, 22, 248, 55, 101, 186, 84, 63, 39, 219, 174, 1, 149, 218, 206, 209, 39, 141, 44, 60, 209, 252, 217, 233, 212, 81, 218, 86, 246, 154, 42, 110, 142, 111, 202, 90, 179, 238, 137, 86, 166, 109, 120, 57, 144, 172, 164, 160, 138, 71, 28, 242, 149, 69, 120, 227, 253, 86, 247, 100, 219, 64, 165, 58, 173, 140, 165, 195, 184, 25, 228, 13, 125, 179, 171, 104, 219, 230, 45, 135, 36, 224, 10, 241, 205, 142, 45, 74, 203, 178, 61, 138, 194, 213, 210, 101, 144, 123, 174, 36, 241, 109, 155, 93, 80, 107, 78, 137, 16, 143, 160, 166, 237, 183, 199, 139, 249, 81, 171, 227, 165, 19, 85, 232, 249, 93, 187, 172, 3, 238, 154, 82, 98, 131, 47, 90, 189, 211, 33, 109, 242, 53, 45, 23, 98, 240, 78, 83, 74, 100, 104, 20, 86, 75, 39, 186, 208, 167, 236, 247, 37, 81, 194, 249, 116, 72, 255, 45, 246, 37, 177, 193, 151, 68, 5, 107, 45, 243, 44, 118, 168, 117, 45, 238, 111, 156, 190, 121, 73, 116, 176, 216, 17, 63, 218, 37, 209, 209, 170, 56, 169, 66, 187, 36, 62, 150, 92, 18, 21, 214, 74, 166, 245, 147, 130, 82, 123, 28, 37, 66, 232, 106, 90, 110, 63, 106, 118, 65, 137, 14, 136, 10, 120, 8, 205, 58, 232, 120, 22, 164, 180, 149, 194, 14, 169, 90, 7, 31, 34, 72, 80, 207, 5, 173, 131, 141, 71, 29, 116, 60, 21, 117, 80, 65, 45, 87, 212, 65, 134, 181, 255, 26, 13, 47, 103, 22, 187, 18, 226, 138, 58, 200, 200, 165, 233, 8, 21, 117, 144, 145, 84, 69, 168, 168, 131, 139, 92, 154, 70, 252, 168, 162, 14, 62, 150, 166, 81, 69, 29, 92, 84, 212, 193, 7, 173, 40, 196, 55, 109, 88, 9, 61, 9, 183, 58, 220, 110, 1, 228, 202, 90, 29, 108, 208, 86, 7, 21, 84, 3, 31, 148, 33, 183, 212, 193, 133, 115, 71, 219, 100, 172, 220, 185, 19, 146, 120, 101, 75, 29, 100, 144, 40, 111, 224, 181, 212, 65, 137, 214, 166, 225, 21, 225, 145, 181, 82, 177, 85, 7, 33, 158, 150, 17, 210, 170, 131, 140, 103, 146, 234, 224, 130, 99, 79, 185, 84, 7, 25, 78, 193, 35, 16, 24, 115, 55, 52, 3, 245, 76, 8, 31, 234, 96, 0, 34, 11, 35, 215, 181, 14, 240, 251, 58, 168, 149, 131, 16, 143, 74, 148, 131, 11, 190, 56, 168, 64, 66, 73, 7, 21, 180, 173, 183, 78, 210, 193, 198, 167, 131, 10, 86, 63, 79, 39, 251, 121, 58, 232, 120, 79, 7, 29, 19, 239, 169, 24, 226, 95, 236, 29, 196, 31, 65, 201, 110, 144, 180, 93, 72, 194, 232, 81, 188, 32, 223, 7, 207, 167, 195, 64, 169, 82, 186, 48, 69, 158, 14, 74, 52, 109, 219, 241, 116, 144, 225, 146, 45, 28, 223, 166, 237, 163, 241, 50, 248, 93, 56, 85, 168, 153, 65, 142, 167, 131, 144, 182, 139, 167, 131, 12, 173, 243, 209, 183, 114, 210, 80, 197, 105, 219, 107, 242, 249, 43, 168, 201, 71, 252, 200, 211, 193, 137, 10, 242, 116, 144, 194, 169, 42, 212, 40, 140, 60, 29, 132, 60, 171, 49, 242, 9, 59, 200, 211, 193, 198, 99, 225, 213, 52, 59, 52, 185, 24, 79, 7, 37, 220, 211, 193, 135, 75, 152, 29, 148, 218, 227, 15, 235, 45, 145, 167, 131, 12, 79, 7, 21, 124, 210, 197, 104, 163, 167, 49, 235, 116, 240, 129, 226, 211, 81, 157, 14, 46, 180, 145, 234, 116, 208, 33, 29, 108, 232, 116, 208, 33, 73, 233, 30, 231, 210, 193, 6, 47, 4, 118, 46, 29, 100, 64, 22, 52, 149, 240, 163, 214, 78, 93, 214, 165, 131, 12, 214, 165, 131, 10, 30, 81, 197, 13, 57, 93, 75, 126, 99, 95, 251, 15, 226, 93, 35, 15, 46, 161, 44, 155, 121, 192, 59, 23, 71, 211, 214, 121, 132, 16, 127, 203, 85, 224, 89, 58, 216, 104, 218, 170, 78, 199, 209, 179, 116, 176, 193, 35, 173, 140, 165, 131, 12, 143, 44, 150, 14, 50, 120, 107, 211, 111, 97, 233, 160, 195, 35, 72, 130, 131, 11, 18, 28, 12, 128, 171, 123, 26, 138, 42, 17, 28, 132, 68, 224, 8, 14, 42, 180, 58, 183, 21, 13, 46, 182, 162, 193, 134, 46, 79, 50, 228, 182, 162, 189, 6, 33, 13, 175, 133, 243, 203, 92, 127, 219, 57, 4, 183, 21, 155, 148, 253, 231, 138, 28, 34, 48, 12, 83, 34, 48, 255, 200, 173, 231, 175, 239, 242, 25, 218, 252, 222, 76, 188, 153, 248, 55, 102, 154, 137, 71, 240, 198, 105, 23, 48, 255, 17, 154, 9, 37, 157, 86, 172, 55, 214, 82, 199, 191, 237, 66, 238, 233, 238, 233, 175, 31, 205, 115, 220, 220, 212, 113, 91, 214, 202, 24, 226, 161, 42, 35, 13, 234, 60, 90, 159, 153, 129, 232, 90, 166, 194, 32, 191, 225, 192, 45, 155, 123, 91, 230, 238, 158, 208, 103, 106, 252, 160, 141, 151, 225, 208, 82, 151, 58, 115, 132, 210, 166, 165, 3, 81, 75, 151, 92, 28, 78, 73, 228, 214, 107, 240, 193, 173, 215, 160, 194, 187, 237, 164, 246, 53, 248, 224, 174, 175, 65, 72, 83, 9, 127, 131, 12, 206, 248, 138, 190, 68, 91, 214, 76, 252, 219, 46, 93, 207, 63, 52, 74, 58, 95, 75, 29, 127, 180, 215, 13, 15, 179, 207, 16, 109, 90, 68, 43, 69, 155, 147, 152, 245, 42, 9, 91, 150, 65, 195, 11, 61, 41, 27, 93, 201, 58, 37, 143, 196, 202, 35, 73, 43, 234, 152, 52, 117, 210, 39, 165, 121, 238, 233, 237, 77, 152, 112, 215, 229, 145, 136, 111, 235, 120, 164, 45, 211, 38, 217, 46, 91, 236, 23, 120, 231, 226, 160, 45, 115, 127, 28, 39, 244, 153, 26, 5, 131, 150, 186, 18, 90, 182, 127, 162, 113, 218, 149, 26, 15, 179, 16, 75, 151, 92, 30, 18, 254, 237, 117, 131, 13, 22, 165, 184, 212, 48, 242, 83, 229, 43, 67, 201, 117, 131, 20, 201, 117, 131, 10, 15, 195, 162, 112, 55, 184, 160, 79, 223, 4, 164, 180, 193, 155, 78, 228, 30, 119, 131, 14, 103, 144, 132, 36, 241, 106, 170, 221, 96, 67, 155, 252, 166, 169, 213, 161, 39, 63, 39, 140, 138, 157, 112, 167, 100, 16, 26, 156, 130, 214, 132, 214, 38, 31, 158, 60, 40, 117, 224, 65, 91, 70, 149, 106, 104, 26, 47, 247, 104, 183, 170, 82, 6, 53, 32, 105, 102, 144, 47, 230, 119, 221, 95, 230, 71, 107, 2, 3, 73, 122, 203, 161, 38, 31, 173, 9, 77, 254, 163, 245, 219, 174, 9, 223, 244, 245, 147, 171, 33, 23, 2, 188, 241, 46, 143, 129, 86, 102, 218, 34, 245, 78, 183, 128, 111, 91, 214, 180, 117, 46, 153, 251, 62, 32, 128, 2, 56, 120, 84, 210, 32, 21, 71, 126, 35, 15, 253, 84, 136, 125, 33, 220, 191, 83, 217, 165, 78, 131, 43, 132, 171, 165, 203, 72, 16, 64, 39, 251, 73, 55, 251, 189, 113, 3, 237, 1, 7, 245, 53, 65, 59, 39, 90, 157, 127, 14, 180, 213, 161, 60, 45, 17, 196, 154, 176, 120, 26, 94, 236, 88, 118, 49, 214, 132, 117, 144, 174, 125, 104, 253, 223, 229, 28, 41, 211, 136, 197, 156, 28, 151, 221, 224, 2, 143, 184, 186, 236, 6, 25, 201, 18, 212, 248, 150, 221, 224, 130, 227, 119, 149, 221, 32, 163, 105, 171, 171, 178, 27, 124, 88, 143, 209, 148, 221, 32, 195, 215, 229, 171, 58, 206, 207, 237, 36, 90, 93, 118, 114, 244, 228, 114, 159, 82, 59, 162, 194, 139, 75, 182, 46, 145, 187, 100, 46, 217, 99, 217, 181, 160, 146, 141, 195, 191, 49, 51, 193, 192, 5, 80, 113, 102, 160, 242, 218, 46, 7, 124, 129, 156, 100, 4, 53, 208, 186, 214, 57, 175, 212, 224, 233, 236, 151, 72, 87, 51, 161, 21, 170, 111, 130, 55, 232, 98, 111, 156, 144, 98, 110, 16, 162, 152, 27, 84, 88, 142, 28, 212, 33, 215, 149, 21, 141, 27, 124, 244, 91, 13, 42, 180, 215, 232, 91, 13, 46, 220, 169, 66, 144, 135, 217, 229, 171, 193, 69, 83, 9, 127, 3, 134, 209, 63, 142, 80, 95, 110, 14, 215, 182, 140, 42, 52, 161, 190, 220, 80, 203, 109, 20, 238, 5, 173, 252, 148, 205, 160, 229, 171, 65, 6, 154, 134, 87, 131, 11, 190, 80, 209, 230, 133, 182, 28, 121, 22, 134, 214, 138, 103, 157, 119, 120, 98, 133, 124, 161, 21, 187, 178, 105, 104, 105, 107, 239, 39, 86, 58, 48, 86, 30, 65, 43, 189, 87, 161, 149, 189, 10, 173, 84, 207, 37, 194, 194, 171, 193, 134, 227, 185, 28, 45, 188, 26, 7, 228, 17, 177, 86, 162, 133, 87, 131, 140, 133, 87, 131, 10, 254, 184, 209, 204, 114, 53, 200, 192, 114, 53, 168, 16, 33, 233, 4, 173, 6, 23, 107, 255, 105, 191, 175, 232, 87, 244, 83, 50, 253, 124, 121, 207, 82, 251, 65, 63, 159, 161, 36, 168, 8, 174, 146, 117, 142, 86, 131, 15, 136, 10, 47, 104, 53, 216, 160, 36, 180, 254, 103, 114, 180, 26, 132, 124, 190, 9, 104, 53, 184, 80, 17, 212, 227, 149, 190, 45, 59, 180, 26, 124, 80, 18, 158, 151, 123, 94, 206, 113, 173, 108, 55, 34, 144, 16, 225, 147, 161, 213, 224, 98, 87, 4, 151, 236, 83, 29, 180, 26, 132, 180, 174, 117, 13, 58, 224, 133, 65, 171, 65, 6, 37, 97, 53, 232, 80, 17, 250, 241, 67, 148, 4, 109, 156, 208, 106, 176, 161, 36, 184, 86, 18, 173, 6, 27, 171, 193, 0, 172, 126, 191, 13, 50, 52, 188, 126, 155, 77, 200, 1, 25, 152, 105, 251, 219, 224, 162, 17, 130, 130, 157, 54, 114, 224, 183, 233, 231, 158, 16, 55, 51, 161, 214, 190, 5, 178, 46, 145, 3, 25, 26, 133, 213, 111, 131, 11, 230, 229, 183, 213, 95, 171, 63, 165, 141, 146, 78, 2, 130, 116, 24, 222, 228, 163, 245, 157, 48, 0, 161, 44, 27, 51, 109, 17, 187, 134, 213, 15, 181, 109, 182, 25, 233, 51, 91, 160, 109, 23, 122, 137, 67, 42, 181, 35, 252, 151, 49, 78, 136, 146, 173, 222, 13, 109, 164, 116, 27, 164, 120, 223, 37, 73, 137, 126, 27, 116, 208, 229, 183, 65, 72, 5, 131, 243, 233, 208, 111, 131, 15, 46, 155, 194, 108, 131, 11, 143, 160, 79, 143, 217, 6, 27, 186, 210, 58, 179, 13, 50, 152, 109, 240, 209, 208, 120, 127, 91, 179, 232, 157, 157, 6, 29, 190, 237, 66, 144, 182, 146, 86, 167, 193, 133, 243, 47, 157, 6, 25, 92, 155, 116, 200, 105, 144, 241, 220, 32, 167, 65, 6, 7, 125, 19, 180, 160, 25, 125, 69, 255, 181, 193, 136, 215, 6, 27, 206, 175, 13, 46, 164, 100, 175, 13, 50, 168, 69, 186, 188, 127, 252, 248, 107, 131, 19, 254, 218, 160, 131, 131, 214, 101, 155, 60, 93, 254, 86, 191, 237, 183, 240, 166, 19, 49, 117, 30, 61, 227, 102, 208, 226, 133, 61, 4, 104, 171, 190, 145, 218, 209, 107, 131, 139, 215, 6, 35, 42, 203, 104, 59, 199, 55, 59, 118, 218, 168, 145, 64, 124, 105, 101, 157, 101, 59, 152, 105, 139, 94, 27, 132, 240, 231, 91, 93, 43, 123, 77, 81, 163, 48, 122, 109, 208, 0, 236, 180, 185, 49, 67, 175, 13, 46, 208, 6, 25, 191, 12, 105, 189, 109, 127, 91, 231, 211, 33, 213, 94, 126, 42, 164, 13, 54, 228, 167, 66, 238, 144, 199, 87, 60, 39, 77, 98, 173, 76, 232, 181, 193, 7, 215, 6, 29, 48, 204, 62, 107, 131, 11, 215, 148, 204, 43, 99, 109, 112, 98, 217, 197, 218, 32, 195, 79, 28, 170, 45, 69, 219, 161, 61, 60, 191, 16, 169, 157, 136, 181, 193, 133, 254, 46, 228, 150, 181, 65, 7, 243, 22, 214, 6, 25, 42, 30, 177, 54, 200, 144, 218, 227, 77, 27, 92, 52, 109, 240, 209, 30, 211, 180, 65, 134, 197, 236, 32, 105, 27, 244, 115, 125, 46, 215, 186, 150, 151, 230, 5, 60, 124, 229, 253, 121, 225, 150, 80, 205, 20, 247, 116, 207, 59, 96, 143, 52, 128, 17, 27, 97, 166, 13, 50, 180, 78, 182, 21, 75, 146, 54, 248, 88, 146, 61, 215, 70, 158, 26, 164, 112, 77, 13, 58, 90, 174, 251, 203, 6, 25, 218, 188, 108, 112, 33, 194, 4, 45, 64, 130, 67, 124, 229, 145, 63, 47, 236, 160, 85, 210, 76, 209, 180, 147, 86, 247, 164, 77, 63, 199, 224, 65, 187, 35, 255, 166, 141, 23, 2, 92, 29, 207, 229, 217, 143, 52, 53, 51, 7, 160, 240, 9, 92, 81, 1, 60, 119, 37, 3, 170, 184, 77, 236, 74, 232, 89, 252, 179, 65, 71, 131, 13, 201, 88, 54, 184, 224, 239, 83, 174, 108, 144, 161, 109, 151, 186, 117, 168, 65, 0, 65, 131, 13, 254, 144, 225, 104, 81, 131, 11, 13, 2, 0, 65, 158, 138, 138, 199, 224, 194, 90, 185, 84, 84, 60, 6, 25, 254, 150, 67, 15, 109, 91, 173, 172, 168, 120, 12, 58, 24, 37, 113, 80, 91, 254, 199, 224, 3, 25, 182, 31, 131, 10, 79, 133, 219, 37, 107, 117, 237, 49, 216, 224, 147, 116, 144, 83, 168, 246, 35, 165, 141, 86, 62, 80, 150, 13, 130, 178, 108, 11, 28, 243, 82, 109, 23, 132, 13, 202, 178, 173, 245, 24, 132, 188, 180, 104, 173, 199, 32, 195, 221, 51, 168, 224, 158, 193, 9, 247, 12, 42, 104, 75, 113, 6, 23, 152, 51, 8, 105, 170, 157, 156, 193, 69, 4, 103, 80, 129, 243, 233, 86, 106, 67, 112, 6, 31, 16, 156, 193, 70, 246, 87, 20, 130, 51, 200, 80, 95, 166, 191, 77, 65, 206, 32, 133, 99, 250, 200, 25, 92, 184, 51, 216, 96, 208, 225, 111, 185, 197, 163, 146, 198, 174, 87, 73, 24, 114, 6, 33, 90, 155, 86, 134, 156, 193, 134, 36, 165, 123, 141, 32, 103, 208, 1, 145, 253, 140, 212, 30, 79, 153, 28, 69, 232, 90, 6, 61, 14, 57, 131, 16, 175, 88, 139, 59, 57, 82, 77, 77, 84, 211, 5, 180, 254, 39, 67, 223, 184, 25, 132, 60, 34, 48, 110, 6, 23, 24, 55, 131, 10, 207, 226, 219, 12, 50, 56, 174, 205, 36, 114, 248, 102, 167, 218, 12, 50, 180, 25, 116, 164, 150, 45, 105, 166, 60, 164, 246, 120, 3, 117, 131, 234, 124, 141, 178, 108, 6, 29, 30, 129, 208, 12, 62, 82, 54, 131, 10, 13, 254, 200, 49, 184, 208, 140, 84, 75, 228, 24, 108, 184, 254, 58, 132, 175, 77, 166, 17, 170, 61, 102, 112, 65, 169, 234, 164, 52, 51, 248, 224, 17, 102, 236, 67, 43, 183, 245, 147, 33, 201, 74, 72, 86, 215, 146, 106, 29, 249, 169, 84, 113, 67, 249, 169, 88, 51, 131, 13, 107, 255, 61, 90, 235, 127, 58, 244, 44, 200, 193, 147, 146, 37, 131, 90, 253, 30, 28, 150, 45, 207, 27, 240, 236, 175, 232, 4, 202, 79, 21, 177, 137, 221, 19, 177, 102, 6, 31, 60, 192, 13, 249, 43, 160, 153, 193, 71, 243, 111, 99, 246, 240, 77, 155, 68, 13, 173, 147, 69, 75, 166, 218, 227, 110, 180, 153, 129, 56, 41, 181, 153, 193, 133, 83, 85, 136, 193, 243, 173, 168, 153, 193, 8, 126, 94, 184, 209, 55, 102, 48, 226, 87, 242, 141, 25, 92, 160, 111, 204, 32, 196, 23, 51, 8, 161, 43, 95, 178, 152, 65, 198, 195, 108, 163, 85, 45, 102, 240, 225, 178, 31, 249, 75, 220, 118, 253, 91, 224, 141, 247, 29, 51, 112, 143, 187, 65, 254, 18, 51, 248, 128, 208, 24, 92, 40, 203, 134, 26, 131, 139, 202, 91, 12, 82, 84, 222, 98, 80, 65, 215, 146, 191, 77, 105, 144, 112, 199, 223, 98, 208, 193, 213, 190, 197, 32, 131, 82, 247, 188, 227, 157, 102, 151, 99, 7, 213, 114, 33, 8, 136, 171, 123, 30, 81, 120, 49, 15, 138, 182, 11, 162, 240, 98, 144, 241, 188, 24, 84, 248, 149, 44, 230, 71, 110, 23, 131, 144, 231, 87, 146, 118, 49, 200, 104, 101, 152, 231, 136, 160, 182, 155, 10, 47, 21, 93, 12, 66, 186, 117, 146, 139, 193, 69, 126, 42, 84, 209, 111, 157, 160, 137, 166, 244, 251, 253, 115, 49, 184, 240, 207, 197, 224, 67, 157, 148, 201, 145, 139, 65, 135, 207, 197, 160, 130, 55, 185, 24, 92, 112, 79, 8, 27, 214, 90, 9, 131, 11, 251, 208, 83, 81, 177, 12, 58, 68, 60, 204, 246, 251, 202, 50, 216, 136, 128, 36, 116, 45, 249, 40, 63, 21, 82, 90, 89, 6, 33, 158, 255, 101, 112, 225, 105, 117, 124, 25, 92, 188, 247, 50, 40, 193, 154, 41, 12, 95, 204, 223, 160, 45, 83, 218, 142, 111, 91, 6, 25, 17, 60, 130, 14, 74, 219, 50, 184, 208, 218, 150, 65, 238, 61, 34, 252, 174, 106, 203, 32, 67, 132, 103, 110, 73, 51, 5, 181, 206, 231, 129, 243, 75, 209, 183, 114, 226, 112, 207, 117, 45, 185, 233, 11, 184, 178, 108, 232, 93, 255, 153, 27, 158, 122, 241, 204, 141, 32, 141, 132, 209, 171, 208, 55, 237, 135, 198, 30, 65, 17, 79, 82, 208, 195, 148, 177, 131, 114, 146, 17, 135, 86, 143, 168, 168, 114, 120, 131, 235, 178, 165, 11, 84, 91, 6, 31, 170, 45, 131, 10, 206, 80, 234, 164, 199, 143, 94, 189, 1, 127, 137, 25, 8, 253, 92, 47, 173, 76, 20, 30, 193, 154, 25, 180, 178, 45, 131, 142, 200, 194, 14, 198, 10, 173, 3, 117, 104, 253, 181, 12, 66, 214, 90, 6, 173, 181, 204, 106, 187, 100, 66, 77, 219, 181, 12, 229, 83, 106, 63, 120, 68, 43, 214, 25, 175, 78, 209, 157, 104, 59, 164, 77, 178, 117, 64, 221, 243, 90, 177, 142, 148, 157, 174, 101, 176, 0, 171, 31, 114, 120, 152, 101, 217, 148, 78, 90, 189, 129, 174, 101, 112, 129, 247, 93, 12, 213, 30, 59, 30, 129, 208, 150, 211, 99, 245, 115, 62, 29, 226, 71, 219, 15, 66, 221, 243, 19, 159, 175, 21, 219, 120, 134, 147, 222, 209, 144, 135, 71, 22, 79, 103, 219, 5, 249, 54, 94, 111, 250, 14, 146, 102, 166, 249, 179, 109, 69, 42, 228, 239, 91, 121, 240, 244, 55, 133, 240, 111, 186, 150, 193, 6, 93, 203, 160, 130, 107, 191, 102, 25, 92, 188, 174, 102, 25, 100, 152, 192, 164, 2, 170, 184, 85, 192, 91, 151, 101, 208, 193, 61, 169, 228, 133, 26, 6, 29, 16, 141, 58, 198, 48, 200, 160, 159, 139, 97, 144, 97, 93, 54, 180, 12, 131, 140, 167, 95, 155, 194, 65, 127, 21, 55, 9, 73, 98, 230, 112, 141, 61, 242, 192, 7, 199, 15, 219, 217, 52, 101, 112, 241, 252, 115, 114, 228, 30, 82, 134, 148, 42, 131, 17, 74, 149, 65, 133, 116, 146, 50, 184, 48, 129, 43, 66, 9, 151, 48, 59, 200, 23, 180, 58, 159, 202, 96, 67, 175, 98, 80, 65, 49, 24, 0, 109, 188, 18, 131, 12, 191, 48, 168, 192, 33, 200, 35, 11, 131, 13, 30, 89, 24, 84, 88, 24, 108, 180, 100, 11, 131, 143, 133, 193, 0, 232, 147, 12, 58, 232, 147, 12, 42, 120, 227, 180, 147, 100, 176, 193, 132, 5, 245, 78, 183, 116, 173, 236, 116, 139, 82, 154, 182, 173, 147, 210, 52, 73, 113, 93, 203, 122, 83, 71, 15, 179, 207, 114, 218, 232, 97, 246, 97, 246, 41, 17, 101, 75, 157, 71, 241, 194, 154, 153, 214, 149, 176, 187, 54, 179, 254, 48, 251, 176, 86, 50, 253, 21, 253, 119, 93, 43, 153, 19, 224, 93, 35, 212, 129, 78, 72, 210, 174, 244, 204, 203, 51, 47, 12, 86, 97, 169, 253, 254, 249, 200, 37, 91, 249, 38, 168, 68, 186, 50, 233, 232, 125, 151, 123, 117, 164, 244, 61, 25, 202, 35, 109, 77, 189, 23, 104, 197, 50, 83, 6, 113, 199, 188, 222, 147, 153, 120, 152, 93, 75, 190, 47, 224, 164, 143, 164, 109, 101, 175, 249, 58, 44, 188, 154, 6, 51, 203, 248, 202, 55, 65, 31, 12, 179, 234, 225, 193, 196, 25, 41, 130, 132, 212, 233, 33, 73, 234, 36, 213, 118, 105, 188, 39, 131, 14, 199, 211, 97, 157, 12, 50, 52, 117, 50, 184, 208, 56, 237, 123, 126, 75, 6, 31, 239, 250, 142, 134, 87, 195, 115, 210, 50, 161, 39, 181, 100, 16, 242, 168, 175, 100, 144, 97, 41, 147, 43, 25, 92, 180, 74, 146, 193, 133, 38, 159, 177, 40, 165, 21, 73, 50, 232, 224, 15, 193, 177, 122, 27, 244, 52, 127, 74, 6, 33, 13, 105, 123, 73, 6, 25, 92, 31, 69, 5, 230, 219, 182, 243, 175, 40, 58, 148, 66, 184, 173, 248, 138, 62, 3, 146, 148, 239, 239, 24, 226, 186, 150, 105, 112, 199, 199, 194, 171, 249, 138, 226, 162, 249, 87, 185, 250, 67, 43, 163, 185, 27, 34, 194, 2, 25, 86, 78, 20, 53, 222, 135, 198, 239, 109, 41, 205, 17, 141, 119, 245, 147, 112, 215, 213, 94, 55, 112, 91, 209, 160, 180, 159, 239, 15, 179, 203, 221, 225, 161, 165, 46, 230, 165, 245, 31, 55, 242, 149, 251, 157, 174, 249, 129, 179, 236, 116, 136, 1, 141, 215, 93, 29, 173, 9, 254, 176, 5, 77, 219, 166, 225, 229, 223, 150, 157, 106, 138, 222, 119, 49, 120, 74, 164, 241, 126, 114, 132, 65, 235, 175, 101, 220, 66, 184, 255, 6, 36, 73, 157, 228, 252, 74, 117, 144, 187, 246, 242, 240, 206, 229, 193, 241, 92, 140, 166, 157, 168, 210, 127, 221, 224, 252, 75, 137, 5, 20, 184, 88, 57, 81, 212, 174, 162, 216, 120, 152, 101, 168, 251, 247, 196, 19, 226, 111, 112, 93, 203, 32, 132, 97, 88, 146, 114, 65, 43, 183, 162, 56, 225, 250, 169, 220, 131, 72, 148, 163, 214, 73, 171, 63, 146, 226, 220, 161, 177, 71, 30, 118, 37, 70, 191, 181, 52, 38, 139, 87, 119, 199, 174, 166, 173, 75, 196, 174, 162, 8, 161, 116, 129, 71, 32, 240, 74, 180, 234, 171, 115, 15, 226, 157, 102, 155, 242, 228, 114, 17, 218, 204, 30, 159, 16, 54, 58, 245, 121, 168, 90, 11, 193, 7, 108, 52, 179, 21, 197, 5, 143, 32, 102, 43, 138, 11, 95, 215, 70, 43, 138, 26, 175, 131, 99, 173, 116, 124, 1, 105, 101, 152, 183, 160, 164, 21, 197, 7, 66, 146, 81, 20, 21, 30, 149, 112, 5, 220, 68, 209, 97, 121, 237, 56, 106, 170, 221, 180, 78, 20, 31, 52, 245, 227, 71, 107, 211, 247, 93, 15, 239, 52, 185, 218, 69, 4, 126, 182, 142, 163, 215, 166, 243, 35, 150, 231, 203, 115, 16, 255, 124, 8, 199, 188, 36, 154, 92, 200, 49, 47, 254, 164, 206, 219, 34, 199, 76, 161, 191, 203, 241, 43, 105, 56, 96, 195, 210, 116, 92, 54, 210, 137, 226, 67, 39, 138, 10, 114, 162, 216, 64, 19, 69, 199, 218, 255, 109, 207, 225, 188, 98, 195, 25, 94, 215, 74, 10, 242, 200, 218, 127, 15, 201, 245, 187, 254, 183, 199, 41, 73, 236, 146, 200, 35, 14, 186, 24, 38, 41, 139, 19, 63, 183, 139, 96, 79, 91, 157, 87, 124, 168, 252, 218, 127, 168, 89, 135, 56, 175, 232, 224, 188, 98, 99, 217, 133, 156, 87, 92, 52, 240, 228, 26, 53, 246, 8, 114, 94, 113, 194, 179, 65, 206, 43, 66, 56, 233, 21, 21, 154, 124, 69, 133, 124, 69, 5, 173, 146, 149, 20, 164, 138, 248, 145, 190, 149, 19, 101, 217, 124, 31, 168, 120, 4, 169, 181, 111, 89, 224, 164, 252, 79, 180, 246, 31, 3, 139, 80, 98, 97, 80, 131, 43, 58, 152, 237, 187, 34, 131, 175, 220, 111, 234, 174, 232, 120, 93, 76, 234, 66, 219, 174, 8, 105, 157, 104, 187, 226, 194, 21, 27, 79, 235, 155, 224, 138, 139, 133, 113, 56, 72, 182, 237, 220, 185, 34, 195, 162, 176, 115, 197, 5, 195, 108, 115, 69, 6, 87, 148, 96, 174, 216, 96, 174, 168, 64, 85, 128, 225, 164, 79, 202, 132, 175, 253, 215, 192, 193, 63, 95, 29, 39, 103, 239, 129, 39, 86, 72, 215, 107, 109, 78, 222, 170, 218, 67, 74, 181, 161, 111, 172, 208, 99, 180, 216, 19, 225, 94, 225, 85, 20, 137, 135, 217, 215, 55, 81, 234, 175, 61, 78, 219, 158, 63, 42, 65, 223, 236, 168, 0, 137, 149, 79, 84, 44, 135, 88, 241, 211, 217, 203, 46, 212, 180, 125, 215, 119, 64, 153, 76, 239, 250, 18, 244, 151, 78, 22, 48, 144, 36, 117, 210, 90, 234, 252, 155, 189, 117, 97, 202, 80, 179, 15, 192, 35, 157, 141, 253, 53, 242, 72, 203, 228, 11, 120, 164, 210, 11, 244, 42, 215, 245, 58, 162, 189, 111, 66, 131, 39, 87, 147, 77, 58, 170, 60, 229, 160, 242, 148, 182, 78, 246, 179, 185, 132, 217, 121, 160, 111, 162, 82, 219, 121, 43, 163, 237, 10, 80, 177, 108, 223, 113, 235, 164, 160, 103, 53, 174, 188, 166, 138, 155, 210, 138, 253, 109, 233, 237, 33, 110, 254, 218, 73, 29, 113, 115, 224, 142, 121, 33, 110, 218, 118, 181, 69, 220, 30, 168, 116, 211, 28, 120, 86, 99, 196, 13, 165, 147, 152, 165, 147, 152, 193, 239, 122, 32, 128, 32, 81, 197, 35, 12, 82, 99, 143, 52, 109, 93, 35, 174, 17, 9, 9, 44, 35, 190, 60, 231, 183, 97, 32, 61, 250, 182, 203, 129, 79, 6, 18, 184, 250, 2, 117, 82, 54, 141, 86, 248, 85, 185, 39, 117, 173, 255, 186, 180, 92, 34, 42, 203, 240, 191, 212, 30, 211, 185, 94, 211, 18, 45, 203, 182, 134, 137, 138, 98, 13, 15, 16, 64, 21, 183, 119, 141, 48, 96, 0, 207, 93, 137, 186, 245, 159, 165, 154, 110, 51, 79, 39, 99, 207, 151, 92, 191, 13, 106, 253, 244, 234, 208, 148, 206, 17, 87, 184, 226, 152, 87, 211, 184, 223, 29, 56, 191, 148, 4, 124, 74, 237, 6, 42, 30, 65, 11, 48, 88, 166, 190, 128, 115, 217, 224, 83, 106, 11, 128, 1, 179, 43, 241, 196, 87, 180, 81, 120, 100, 97, 36, 154, 70, 35, 22, 32, 0, 245, 92, 208, 210, 150, 222, 68, 15, 60, 17, 66, 180, 87, 0, 93, 102, 149, 182, 119, 128, 182, 72, 221, 243, 12, 116, 170, 150, 239, 11, 216, 59, 200, 241, 93, 203, 115, 15, 218, 174, 136, 119, 125, 6, 94, 75, 134, 212, 129, 149, 173, 245, 43, 233, 236, 184, 29, 74, 150, 116, 0, 11, 84, 203, 94, 36, 154, 221, 53, 165, 68, 137, 149, 43, 46, 80, 199, 201, 21, 25, 30, 64, 149, 252, 246, 248, 0, 210, 246, 43, 67, 174, 40, 128, 103, 201, 181, 146, 130, 34, 154, 54, 170, 56, 185, 98, 35, 159, 76, 174, 200, 160, 138, 211, 182, 231, 224, 40, 42, 250, 185, 32, 139, 189, 243, 248, 228, 6, 169, 107, 114, 187, 51, 33, 124, 112, 210, 39, 91, 15, 85, 185, 50, 185, 34, 35, 130, 4, 228, 204, 147, 2, 137, 96, 2, 228, 220, 158, 183, 70, 48, 65, 83, 199, 18, 175, 77, 87, 4, 19, 36, 231, 116, 69, 48, 129, 187, 101, 12, 34, 152, 128, 117, 78, 176, 206, 8, 18, 80, 229, 181, 93, 16, 17, 76, 128, 148, 47, 170, 205, 72, 68, 48, 1, 235, 164, 136, 96, 2, 212, 150, 210, 169, 34, 34, 152, 128, 117, 162, 5, 106, 237, 91, 92, 113, 225, 190, 120, 97, 143, 131, 173, 227, 104, 2, 87, 100, 188, 58, 154, 128, 98, 2, 87, 124, 76, 224, 104, 2, 87, 92, 160, 9, 92, 17, 130, 38, 112, 197, 6, 182, 142, 35, 9, 92, 145, 225, 107, 89, 182, 72, 2, 87, 124, 240, 21, 69, 18, 184, 4, 87, 100, 120, 58, 39, 200, 21, 23, 58, 217, 95, 182, 237, 16, 191, 179, 117, 188, 181, 162, 11, 185, 226, 131, 227, 218, 12, 114, 69, 198, 179, 180, 194, 11, 82, 236, 188, 50, 87, 124, 224, 179, 209, 110, 154, 68, 174, 40, 225, 221, 138, 10, 46, 73, 249, 254, 144, 164, 124, 151, 200, 213, 58, 225, 6, 62, 105, 4, 33, 142, 87, 183, 34, 67, 183, 162, 2, 151, 12, 233, 202, 201, 190, 9, 138, 18, 141, 155, 116, 167, 184, 240, 136, 179, 226, 66, 171, 36, 173, 107, 169, 60, 27, 43, 18, 160, 177, 71, 16, 191, 131, 247, 195, 4, 16, 160, 6, 202, 158, 138, 166, 200, 192, 76, 219, 73, 83, 92, 60, 204, 78, 154, 78, 154, 226, 130, 105, 156, 38, 77, 113, 161, 118, 229, 162, 105, 219, 63, 105, 138, 141, 73, 83, 116, 108, 66, 147, 166, 200, 240, 48, 203, 94, 83, 92, 176, 215, 20, 21, 144, 241, 100, 119, 34, 68, 155, 223, 155, 226, 162, 25, 30, 129, 160, 189, 111, 66, 83, 116, 232, 211, 55, 161, 41, 46, 92, 178, 166, 184, 160, 188, 249, 215, 119, 130, 52, 181, 116, 120, 33, 64, 248, 218, 127, 15, 100, 112, 126, 41, 200, 85, 211, 70, 45, 87, 53, 197, 134, 111, 170, 154, 34, 3, 195, 72, 53, 197, 134, 254, 79, 164, 154, 162, 67, 43, 78, 77, 247, 185, 209, 54, 161, 174, 45, 93, 70, 34, 26, 133, 21, 106, 218, 42, 78, 77, 177, 33, 53, 197, 134, 90, 32, 3, 115, 45, 162, 87, 161, 198, 243, 142, 41, 46, 104, 115, 66, 144, 111, 117, 79, 10, 59, 166, 184, 208, 138, 245, 116, 28, 83, 108, 52, 109, 153, 58, 255, 208, 58, 105, 117, 135, 136, 198, 251, 204, 20, 23, 239, 187, 144, 63, 180, 49, 99, 217, 149, 24, 42, 218, 104, 59, 168, 231, 210, 216, 8, 51, 230, 240, 8, 99, 35, 204, 20, 33, 30, 134, 234, 164, 232, 59, 106, 253, 214, 247, 95, 166, 184, 240, 203, 20, 27, 158, 78, 247, 101, 138, 140, 165, 254, 184, 51, 161, 92, 11, 83, 116, 208, 197, 14, 107, 166, 72, 18, 179, 8, 151, 76, 146, 74, 241, 126, 158, 206, 235, 59, 122, 215, 247, 76, 218, 11, 50, 130, 154, 137, 55, 232, 122, 222, 87, 63, 228, 64, 83, 63, 246, 198, 109, 61, 2, 181, 254, 227, 254, 199, 253, 32, 63, 21, 154, 64, 2, 16, 36, 166, 155, 201, 158, 248, 109, 111, 2, 106, 165, 176, 107, 117, 142, 29, 228, 73, 149, 146, 117, 186, 126, 31, 105, 147, 14, 130, 157, 177, 114, 160, 148, 101, 99, 160, 233, 242, 36, 243, 214, 138, 85, 201, 171, 65, 227, 253, 148, 72, 37, 60, 105, 187, 190, 45, 211, 150, 162, 59, 65, 109, 181, 27, 224, 71, 140, 182, 243, 218, 56, 233, 31, 222, 228, 98, 208, 4, 203, 138, 186, 182, 109, 154, 54, 120, 227, 245, 85, 175, 14, 238, 16, 249, 169, 156, 227, 73, 141, 35, 24, 187, 167, 86, 101, 217, 144, 218, 149, 19, 102, 218, 183, 93, 200, 87, 194, 217, 58, 238, 240, 219, 222, 4, 180, 43, 61, 173, 237, 208, 174, 228, 128, 123, 122, 103, 135, 118, 37, 231, 211, 81, 236, 242, 87, 119, 182, 142, 163, 93, 73, 155, 236, 101, 104, 33, 118, 165, 2, 80, 120, 49, 146, 102, 10, 146, 224, 15, 212, 218, 183, 60, 188, 32, 26, 208, 6, 169, 226, 137, 72, 66, 171, 214, 62, 7, 252, 1, 180, 12, 154, 116, 232, 113, 144, 214, 61, 87, 106, 32, 128, 135, 180, 158, 11, 5, 255, 139, 104, 118, 129, 75, 36, 158, 180, 69, 175, 146, 148, 189, 160, 214, 133, 41, 42, 64, 2, 204, 63, 136, 75, 47, 65, 145, 108, 39, 144, 71, 28, 154, 241, 33, 215, 159, 165, 200, 192, 150, 162, 196, 187, 62, 98, 75, 25, 60, 59, 136, 45, 197, 5, 91, 138, 142, 180, 207, 208, 138, 117, 183, 107, 41, 54, 60, 34, 89, 138, 11, 44, 19, 98, 150, 226, 66, 181, 255, 161, 244, 247, 165, 222, 132, 158, 206, 2, 236, 155, 40, 69, 197, 122, 3, 7, 127, 203, 65, 92, 157, 244, 201, 30, 28, 184, 231, 74, 8, 27, 90, 91, 91, 231, 232, 91, 54, 186, 20, 31, 40, 19, 250, 249, 142, 40, 172, 218, 82, 216, 91, 254, 142, 208, 138, 237, 124, 110, 19, 85, 15, 75, 83, 74, 228, 13, 90, 238, 162, 170, 49, 99, 156, 208, 3, 39, 189, 50, 14, 17, 235, 209, 186, 22, 3, 175, 41, 67, 11, 26, 247, 39, 93, 138, 12, 199, 158, 122, 168, 226, 6, 193, 92, 34, 108, 80, 225, 133, 37, 18, 197, 134, 86, 149, 236, 248, 182, 11, 121, 68, 145, 81, 209, 70, 27, 169, 122, 43, 181, 69, 30, 81, 140, 240, 136, 162, 130, 103, 133, 84, 190, 171, 165, 17, 70, 181, 157, 172, 226, 132, 4, 10, 64, 0, 129, 91, 69, 136, 86, 39, 125, 82, 80, 211, 40, 106, 26, 69, 198, 55, 164, 253, 124, 119, 93, 79, 53, 138, 144, 166, 173, 243, 233, 26, 127, 103, 131, 36, 49, 107, 254, 124, 110, 135, 166, 209, 166, 81, 124, 208, 102, 60, 54, 161, 166, 81, 100, 104, 187, 160, 166, 81, 92, 124, 227, 102, 20, 25, 154, 63, 41, 195, 40, 50, 26, 94, 72, 21, 25, 222, 123, 25, 164, 138, 140, 214, 253, 215, 118, 136, 31, 57, 64, 136, 55, 222, 95, 165, 200, 104, 218, 42, 197, 199, 251, 46, 244, 164, 166, 41, 35, 42, 17, 63, 114, 109, 148, 98, 131, 86, 39, 181, 151, 11, 105, 163, 20, 27, 116, 210, 47, 69, 80, 138, 12, 157, 244, 75, 138, 12, 174, 75, 146, 148, 157, 164, 200, 96, 6, 41, 46, 218, 226, 17, 148, 146, 34, 131, 105, 139, 226, 99, 177, 69, 209, 177, 216, 162, 168, 240, 84, 164, 226, 67, 21, 123, 60, 245, 29, 146, 148, 239, 46, 217, 35, 30, 79, 117, 142, 214, 199, 83, 177, 193, 121, 181, 148, 150, 235, 249, 158, 138, 14, 238, 9, 121, 211, 214, 83, 241, 241, 77, 27, 167, 162, 195, 191, 212, 169, 200, 208, 78, 74, 197, 5, 119, 220, 14, 57, 41, 21, 29, 234, 220, 168, 240, 178, 152, 31, 226, 157, 29, 137, 149, 137, 23, 90, 20, 55, 80, 247, 148, 42, 148, 150, 101, 123, 20, 58, 232, 239, 202, 246, 40, 100, 180, 50, 182, 40, 39, 10, 27, 109, 149, 74, 218, 174, 7, 71, 30, 121, 127, 10, 29, 188, 209, 120, 63, 251, 41, 100, 180, 74, 146, 58, 105, 1, 15, 179, 18, 34, 52, 90, 25, 168, 162, 203, 61, 133, 20, 238, 41, 84, 32, 73, 79, 161, 130, 186, 231, 21, 46, 32, 127, 133, 13, 175, 174, 80, 65, 33, 67, 27, 87, 56, 110, 133, 12, 143, 64, 192, 134, 187, 174, 103, 182, 21, 54, 144, 174, 181, 148, 108, 133, 14, 38, 142, 40, 217, 10, 27, 180, 105, 217, 10, 25, 90, 37, 41, 251, 81, 147, 173, 16, 210, 240, 98, 120, 228, 193, 35, 16, 90, 29, 200, 89, 3, 182, 139, 189, 131, 190, 217, 85, 148, 194, 35, 16, 76, 182, 194, 6, 37, 129, 83, 182, 194, 5, 83, 78, 161, 194, 51, 235, 120, 195, 63, 223, 145, 74, 94, 207, 220, 72, 85, 118, 211, 40, 172, 208, 225, 201, 238, 244, 223, 5, 233, 90, 30, 43, 124, 232, 254, 243, 239, 114, 254, 172, 240, 241, 219, 60, 43, 132, 40, 147, 254, 120, 80, 45, 93, 69, 27, 118, 37, 228, 64, 6, 159, 128, 158, 21, 50, 232, 90, 242, 31, 99, 139, 28, 183, 132, 227, 118, 254, 157, 174, 209, 216, 35, 172, 144, 241, 172, 80, 129, 50, 78, 75, 41, 104, 201, 197, 188, 48, 43, 140, 104, 253, 77, 10, 99, 165, 82, 155, 177, 66, 198, 195, 108, 63, 199, 88, 97, 131, 219, 50, 86, 200, 208, 140, 157, 166, 138, 50, 86, 8, 81, 247, 60, 99, 133, 14, 18, 207, 127, 160, 131, 4, 140, 21, 42, 68, 192, 88, 161, 130, 175, 126, 136, 177, 66, 134, 54, 201, 88, 33, 228, 209, 90, 177, 43, 183, 213, 17, 99, 133, 14, 218, 114, 185, 198, 178, 139, 177, 194, 7, 247, 5, 99, 133, 13, 201, 249, 31, 68, 107, 118, 37, 98, 172, 176, 161, 254, 150, 21, 50, 172, 203, 134, 21, 50, 248, 218, 127, 14, 109, 78, 168, 34, 177, 194, 70, 69, 98, 133, 10, 93, 73, 172, 176, 161, 146, 88, 161, 66, 107, 214, 21, 181, 102, 253, 37, 86, 232, 208, 120, 63, 27, 190, 41, 123, 137, 21, 62, 112, 117, 207, 39, 86, 200, 144, 52, 51, 232, 233, 108, 118, 76, 31, 105, 219, 254, 196, 10, 27, 36, 254, 196, 10, 25, 118, 37, 244, 48, 251, 240, 8, 4, 39, 117, 170, 39, 86, 8, 121, 199, 137, 21, 50, 168, 226, 6, 83, 197, 12, 178, 150, 145, 80, 103, 149, 36, 86, 232, 160, 144, 241, 149, 71, 222, 20, 46, 94, 37, 137, 29, 121, 83, 232, 112, 210, 43, 163, 237, 144, 55, 133, 20, 221, 58, 97, 228, 77, 33, 3, 213, 84, 146, 114, 65, 251, 235, 49, 213, 20, 50, 20, 83, 168, 96, 178, 20, 42, 104, 109, 205, 58, 98, 43, 81, 248, 152, 68, 20, 42, 72, 237, 113, 165, 77, 235, 100, 21, 50, 214, 37, 170, 108, 127, 50, 180, 10, 39, 124, 109, 50, 69, 186, 150, 68, 7, 249, 186, 32, 143, 64, 120, 88, 151, 72, 53, 39, 95, 133, 17, 155, 78, 66, 207, 247, 42, 116, 60, 15, 52, 35, 131, 31, 245, 42, 108, 232, 85, 248, 224, 71, 159, 75, 211, 86, 161, 132, 71, 32, 112, 107, 91, 133, 141, 119, 109, 86, 97, 67, 106, 143, 89, 245, 26, 203, 190, 46, 134, 89, 133, 139, 150, 108, 45, 117, 144, 46, 195, 172, 66, 135, 181, 36, 195, 172, 194, 134, 197, 222, 137, 192, 48, 171, 176, 225, 164, 79, 135, 24, 102, 21, 66, 48, 204, 42, 84, 104, 169, 236, 241, 163, 86, 161, 99, 213, 42, 71, 195, 43, 87, 225, 67, 211, 246, 87, 41, 250, 164, 189, 10, 61, 240, 8, 98, 217, 77, 174, 66, 135, 63, 150, 182, 150, 78, 66, 40, 225, 146, 33, 7, 119, 228, 42, 108, 172, 194, 0, 176, 236, 70, 225, 66, 50, 10, 21, 232, 86, 84, 225, 2, 50, 60, 169, 115, 136, 71, 144, 166, 157, 168, 66, 137, 70, 97, 69, 97, 103, 194, 211, 254, 130, 181, 246, 77, 64, 202, 180, 255, 191, 101, 131, 38, 170, 16, 66, 157, 148, 201, 35, 90, 58, 122, 124, 107, 154, 168, 194, 133, 190, 149, 19, 85, 184, 88, 235, 53, 52, 81, 133, 12, 183, 104, 162, 10, 25, 42, 252, 170, 112, 129, 98, 2, 87, 164, 147, 109, 112, 210, 227, 159, 248, 245, 240, 205, 110, 65, 90, 118, 61, 154, 182, 173, 85, 242, 13, 165, 107, 229, 123, 91, 136, 231, 26, 135, 174, 101, 30, 20, 94, 76, 235, 132, 27, 36, 125, 85, 232, 176, 54, 95, 21, 58, 88, 242, 85, 225, 66, 191, 171, 114, 229, 198, 7, 30, 129, 224, 170, 144, 65, 21, 54, 86, 190, 9, 170, 144, 225, 155, 29, 185, 115, 167, 10, 29, 141, 247, 65, 209, 157, 188, 239, 66, 58, 217, 207, 54, 0, 110, 135, 40, 148, 126, 38, 109, 167, 10, 29, 170, 253, 15, 142, 203, 110, 246, 181, 196, 131, 16, 202, 169, 114, 170, 144, 225, 84, 97, 163, 105, 139, 158, 95, 111, 170, 80, 226, 97, 86, 21, 55, 85, 216, 208, 135, 95, 182, 75, 21, 58, 120, 67, 63, 27, 93, 170, 144, 161, 159, 235, 33, 197, 174, 132, 150, 42, 92, 44, 85, 168, 96, 225, 213, 168, 66, 134, 230, 207, 214, 166, 141, 42, 124, 60, 70, 21, 42, 56, 163, 234, 115, 49, 170, 208, 241, 48, 140, 42, 92, 104, 20, 86, 74, 187, 85, 155, 193, 143, 90, 25, 85, 8, 241, 77, 155, 68, 173, 254, 212, 190, 183, 216, 181, 125, 129, 39, 41, 250, 217, 60, 168, 69, 40, 161, 77, 43, 107, 56, 158, 234, 211, 246, 71, 124, 179, 183, 250, 179, 178, 37, 82, 199, 201, 39, 252, 81, 9, 82, 150, 77, 27, 226, 143, 74, 144, 75, 214, 224, 146, 249, 46, 62, 109, 191, 35, 137, 9, 92, 145, 106, 51, 170, 233, 87, 30, 173, 170, 25, 61, 45, 81, 107, 0, 177, 242, 57, 214, 4, 101, 48, 204, 42, 228, 84, 21, 54, 220, 86, 56, 184, 173, 104, 175, 162, 129, 136, 80, 177, 68, 116, 190, 131, 42, 108, 108, 63, 10, 134, 217, 127, 168, 226, 164, 10, 7, 224, 17, 8, 138, 142, 213, 64, 144, 36, 85, 184, 120, 167, 217, 133, 32, 60, 2, 97, 37, 219, 164, 10, 29, 254, 168, 4, 61, 168, 82, 133, 139, 134, 23, 195, 31, 175, 183, 36, 131, 28, 154, 183, 168, 194, 5, 132, 72, 237, 241, 84, 133, 11, 151, 170, 80, 65, 210, 118, 169, 84, 133, 140, 111, 170, 218, 34, 85, 216, 104, 222, 162, 80, 65, 105, 167, 227, 17, 141, 107, 88, 19, 252, 97, 72, 23, 133, 16, 190, 40, 108, 40, 173, 120, 82, 33, 67, 250, 7, 225, 145, 39, 21, 46, 248, 218, 127, 74, 251, 33, 103, 137, 63, 21, 58, 224, 17, 253, 84, 200, 224, 17, 8, 250, 169, 28, 202, 246, 27, 20, 110, 12, 127, 82, 237, 98, 71, 189, 211, 121, 99, 34, 148, 182, 190, 167, 62, 212, 181, 173, 147, 32, 74, 125, 39, 218, 104, 87, 54, 77, 23, 138, 180, 175, 204, 249, 237, 7, 253, 84, 216, 176, 253, 242, 83, 225, 34, 2, 95, 208, 39, 93, 234, 11, 90, 85, 179, 54, 133, 251, 129, 123, 220, 13, 133, 91, 53, 16, 129, 47, 200, 1, 157, 236, 3, 173, 42, 213, 81, 90, 89, 230, 85, 196, 171, 8, 22, 240, 5, 61, 240, 198, 255, 143, 65, 4, 18, 190, 160, 215, 6, 33, 2, 95, 16, 3, 107, 45, 195, 255, 18, 53, 120, 109, 16, 28, 92, 178, 252, 84, 200, 240, 180, 253, 202, 80, 195, 202, 35, 8, 35, 124, 245, 107, 104, 243, 187, 99, 93, 162, 252, 84, 248, 176, 175, 129, 240, 169, 112, 241, 60, 21, 42, 120, 196, 241, 84, 200, 240, 48, 235, 120, 42, 92, 104, 197, 182, 58, 158, 10, 27, 239, 137, 28, 79, 133, 140, 78, 133, 13, 111, 90, 210, 82, 33, 163, 181, 105, 169, 144, 161, 173, 190, 227, 77, 39, 186, 208, 203, 86, 150, 10, 39, 60, 178, 144, 160, 16, 67, 187, 73, 133, 11, 46, 25, 106, 82, 225, 34, 130, 9, 20, 42, 88, 110, 220, 60, 65, 18, 20, 58, 28, 67, 51, 28, 148, 237, 187, 116, 210, 62, 146, 208, 149, 201, 145, 4, 133, 140, 71, 37, 45, 221, 245, 77, 112, 52, 218, 72, 130, 194, 134, 134, 62, 125, 19, 84, 251, 85, 190, 9, 72, 130, 194, 71, 227, 230, 89, 236, 144, 4, 133, 14, 231, 211, 125, 46, 118, 18, 148, 163, 237, 82, 81, 7, 73, 80, 216, 248, 100, 13, 77, 205, 78, 122, 101, 144, 4, 133, 12, 245, 84, 36, 65, 225, 98, 226, 206, 247, 201, 246, 114, 169, 66, 18, 20, 62, 250, 241, 55, 135, 55, 222, 79, 26, 225, 118, 72, 127, 157, 29, 115, 208, 188, 24, 73, 80, 216, 160, 154, 157, 132, 36, 40, 100, 248, 86, 18, 73, 80, 184, 208, 181, 36, 170, 72, 248, 80, 145, 240, 129, 186, 76, 206, 255, 84, 154, 124, 136, 36, 229, 242, 126, 73, 219, 215, 68, 243, 195, 146, 239, 14, 124, 127, 189, 6, 78, 226, 6, 250, 165, 243, 218, 100, 17, 43, 19, 47, 7, 222, 53, 242, 236, 184, 203, 230, 72, 155, 100, 203, 192, 105, 55, 74, 37, 222, 147, 65, 107, 147, 137, 208, 181, 140, 74, 94, 141, 66, 225, 224, 16, 90, 121, 252, 170, 151, 168, 1, 23, 186, 210, 147, 112, 1, 210, 200, 65, 125, 41, 9, 23, 218, 46, 200, 45, 74, 73, 216, 200, 78, 72, 43, 182, 161, 233, 228, 155, 78, 32, 154, 90, 190, 183, 69, 140, 223, 95, 194, 5, 30, 65, 20, 128, 64, 2, 9, 34, 232, 164, 95, 194, 6, 165, 75, 181, 116, 218, 67, 207, 154, 64, 191, 13, 122, 9, 143, 64, 104, 125, 10, 143, 64, 120, 120, 106, 218, 253, 18, 58, 124, 235, 36, 190, 14, 226, 155, 23, 236, 146, 72, 21, 55, 100, 168, 226, 134, 10, 146, 196, 13, 21, 212, 73, 153, 184, 225, 130, 27, 54, 184, 33, 67, 61, 19, 226, 134, 11, 213, 126, 214, 144, 193, 35, 16, 252, 81, 73, 67, 134, 250, 54, 84, 72, 198, 182, 225, 2, 58, 150, 54, 219, 112, 225, 233, 71, 154, 182, 33, 99, 217, 134, 10, 154, 74, 248, 17, 4, 131, 69, 41, 173, 43, 223, 247, 78, 40, 156, 244, 75, 241, 215, 224, 254, 29, 180, 191, 158, 0, 14, 208, 239, 201, 175, 110, 251, 29, 85, 154, 8, 187, 36, 237, 242, 215, 165, 18, 159, 88, 107, 223, 132, 111, 219, 234, 214, 53, 188, 241, 186, 47, 107, 117, 185, 124, 82, 166, 213, 53, 94, 70, 20, 118, 235, 80, 171, 106, 102, 251, 232, 23, 72, 156, 1, 209, 253, 95, 139, 59, 57, 106, 19, 13, 91, 231, 184, 19, 170, 52, 13, 35, 60, 242, 78, 179, 203, 105, 214, 65, 149, 166, 225, 3, 163, 28, 106, 0, 105, 20, 86, 223, 30, 75, 232, 74, 216, 209, 188, 24, 162, 121, 113, 131, 187, 117, 26, 168, 210, 52, 124, 248, 91, 174, 210, 52, 116, 208, 138, 117, 254, 151, 168, 210, 52, 132, 52, 13, 27, 149, 110, 26, 54, 144, 112, 55, 13, 23, 62, 165, 118, 211, 112, 209, 52, 124, 52, 13, 31, 18, 52, 13, 29, 173, 20, 221, 9, 242, 8, 163, 28, 138, 208, 180, 125, 220, 80, 132, 166, 161, 195, 130, 92, 175, 201, 86, 18, 79, 22, 225, 186, 18, 126, 180, 190, 46, 199, 184, 1, 69, 104, 26, 58, 188, 105, 208, 133, 140, 166, 225, 35, 157, 244, 46, 147, 54, 106, 26, 66, 36, 105, 29, 106, 26, 66, 184, 36, 49, 67, 77, 67, 134, 54, 201, 158, 138, 92, 168, 105, 24, 209, 52, 164, 104, 26, 62, 188, 174, 245, 22, 212, 52, 212, 52, 108, 64, 137, 134, 215, 130, 148, 169, 243, 40, 59, 251, 43, 218, 144, 193, 155, 54, 14, 173, 207, 164, 243, 75, 129, 240, 181, 142, 129, 126, 46, 111, 217, 14, 174, 76, 157, 127, 184, 100, 250, 235, 218, 47, 169, 79, 184, 254, 227, 150, 208, 181, 100, 229, 41, 237, 164, 8, 192, 93, 23, 82, 223, 18, 185, 210, 138, 101, 251, 142, 23, 104, 219, 197, 48, 92, 209, 246, 240, 111, 204, 56, 92, 87, 194, 16, 231, 95, 99, 245, 67, 250, 111, 177, 47, 137, 190, 162, 13, 35, 190, 162, 13, 21, 252, 145, 186, 231, 41, 218, 208, 145, 253, 21, 93, 236, 29, 244, 160, 37, 163, 104, 67, 134, 213, 15, 233, 115, 95, 138, 71, 144, 106, 203, 32, 138, 54, 68, 209, 134, 12, 119, 109, 165, 18, 73, 154, 41, 175, 13, 31, 82, 191, 54, 92, 144, 120, 178, 215, 134, 11, 6, 218, 168, 165, 32, 103, 15, 236, 74, 232, 97, 118, 189, 54, 124, 188, 54, 84, 192, 154, 213, 61, 223, 192, 35, 109, 2, 16, 44, 242, 136, 46, 246, 119, 109, 232, 240, 60, 40, 125, 215, 134, 20, 141, 223, 219, 82, 32, 173, 255, 248, 209, 116, 146, 141, 222, 181, 161, 227, 59, 21, 98, 90, 27, 54, 18, 43, 214, 22, 177, 120, 65, 13, 68, 34, 96, 109, 8, 97, 109, 248, 96, 109, 216, 64, 135, 46, 165, 218, 144, 97, 229, 155, 160, 159, 218, 176, 49, 241, 132, 62, 181, 33, 227, 209, 213, 169, 13, 23, 105, 21, 111, 171, 99, 240, 174, 157, 218, 176, 161, 177, 71, 84, 67, 6, 215, 73, 249, 102, 135, 44, 240, 56, 46, 187, 97, 198, 14, 146, 120, 178, 59, 85, 195, 133, 75, 13, 21, 40, 203, 150, 26, 50, 112, 179, 147, 108, 200, 160, 191, 11, 81, 104, 63, 224, 194, 23, 171, 95, 123, 14, 7, 213, 187, 232, 91, 11, 106, 150, 112, 210, 43, 131, 16, 199, 179, 161, 130, 115, 167, 100, 104, 93, 54, 124, 168, 181, 111, 65, 235, 178, 237, 59, 90, 91, 91, 231, 13, 142, 221, 39, 83, 203, 45, 27, 50, 44, 246, 14, 195, 191, 233, 68, 189, 121, 113, 114, 104, 227, 149, 252, 45, 156, 212, 116, 225, 150, 13, 27, 223, 234, 158, 220, 178, 161, 99, 121, 190, 60, 135, 184, 101, 75, 109, 224, 158, 16, 183, 108, 200, 224, 150, 13, 21, 90, 54, 84, 208, 204, 178, 225, 2, 194, 8, 164, 148, 101, 67, 137, 181, 18, 41, 203, 134, 13, 42, 25, 201, 134, 11, 174, 109, 151, 74, 109, 212, 240, 193, 178, 27, 212, 144, 161, 33, 0, 42, 24, 6, 32, 2, 195, 154, 224, 15, 195, 133, 135, 217, 138, 254, 99, 200, 96, 235, 56, 90, 240, 128, 3, 111, 218, 190, 235, 63, 96, 235, 120, 107, 139, 8, 240, 24, 70, 60, 134, 16, 239, 143, 161, 130, 71, 36, 52, 56, 158, 78, 63, 214, 143, 161, 163, 85, 151, 0, 212, 173, 251, 100, 13, 39, 125, 50, 151, 140, 161, 109, 151, 55, 45, 215, 2, 77, 91, 137, 71, 82, 197, 201, 155, 66, 239, 153, 26, 212, 115, 217, 126, 136, 31, 181, 82, 9, 209, 74, 229, 126, 167, 67, 251, 235, 49, 116, 72, 112, 212, 250, 235, 49, 108, 56, 110, 135, 36, 143, 33, 3, 237, 99, 232, 240, 12, 27, 20, 103, 168, 96, 77, 112, 103, 184, 192, 239, 158, 78, 237, 12, 27, 45, 1, 67, 127, 23, 196, 35, 72, 146, 210, 53, 206, 208, 241, 174, 141, 156, 225, 194, 25, 54, 148, 45, 107, 134, 12, 218, 156, 16, 107, 134, 140, 109, 134, 10, 36, 43, 41, 200, 169, 66, 205, 240, 241, 63, 129, 225, 195, 255, 4, 134, 10, 19, 24, 50, 188, 57, 134, 10, 142, 161, 35, 173, 231, 226, 24, 46, 224, 194, 121, 43, 204, 144, 225, 31, 51, 84, 208, 166, 165, 147, 144, 250, 99, 134, 144, 111, 203, 14, 125, 123, 204, 240, 177, 15, 53, 222, 103, 134, 13, 183, 142, 183, 58, 207, 12, 29, 239, 204, 80, 193, 35, 16, 124, 187, 153, 97, 131, 177, 114, 92, 51, 123, 180, 108, 154, 25, 50, 248, 174, 108, 102, 184, 80, 17, 144, 54, 126, 110, 204, 176, 193, 147, 75, 21, 114, 204, 11, 161, 131, 8, 19, 164, 159, 109, 155, 116, 20, 77, 227, 6, 173, 88, 117, 254, 228, 197, 56, 232, 235, 82, 133, 30, 212, 153, 225, 145, 237, 247, 208, 230, 132, 22, 64, 203, 162, 86, 63, 212, 26, 59, 208, 120, 209, 55, 221, 149, 208, 131, 101, 225, 120, 170, 6, 55, 141, 25, 66, 30, 109, 204, 112, 97, 177, 124, 16, 167, 108, 140, 7, 245, 78, 39, 177, 109, 217, 195, 35, 2, 96, 224, 79, 42, 68, 225, 174, 109, 253, 45, 232, 225, 155, 50, 102, 200, 208, 186, 94, 210, 197, 12, 27, 139, 25, 62, 180, 199, 12, 122, 110, 12, 20, 75, 228, 158, 132, 121, 81, 68, 48, 232, 202, 228, 157, 235, 41, 102, 8, 65, 15, 179, 138, 25, 62, 116, 197, 182, 110, 240, 82, 197, 12, 25, 22, 171, 32, 135, 46, 165, 152, 33, 131, 63, 104, 169, 43, 41, 102, 200, 88, 148, 130, 82, 49, 67, 6, 238, 223, 35, 146, 196, 12, 25, 158, 214, 197, 164, 41, 82, 170, 159, 170, 173, 122, 119, 184, 54, 67, 162, 162, 77, 226, 18, 74, 164, 177, 128, 66, 130, 35, 167, 60, 144, 36, 49, 67, 137, 230, 6, 34, 148, 177, 43, 69, 146, 210, 53, 26, 220, 233, 251, 195, 73, 159, 148, 119, 154, 109, 16, 173, 223, 236, 38, 40, 188, 173, 164, 105, 132, 65, 58, 137, 25, 46, 240, 181, 255, 84, 251, 81, 101, 97, 54, 81, 89, 152, 161, 163, 178, 48, 67, 133, 134, 192, 223, 67, 218, 9, 197, 218, 133, 25, 54, 188, 99, 3, 45, 138, 49, 100, 40, 198, 208, 241, 172, 197, 80, 161, 109, 37, 25, 122, 178, 59, 209, 98, 8, 233, 85, 142, 189, 132, 33, 195, 49, 125, 9, 67, 6, 9, 67, 71, 132, 69, 83, 231, 31, 18, 232, 208, 168, 139, 48, 132, 56, 124, 69, 95, 215, 146, 159, 210, 249, 99, 229, 38, 246, 79, 169, 77, 201, 70, 139, 69, 24, 196, 98, 21, 244, 208, 185, 76, 178, 65, 180, 73, 182, 220, 13, 93, 191, 175, 235, 121, 127, 136, 80, 169, 206, 131, 111, 204, 32, 149, 234, 168, 84, 135, 66, 165, 58, 238, 113, 55, 142, 86, 181, 147, 85, 16, 109, 78, 236, 45, 78, 187, 26, 26, 255, 191, 199, 163, 120, 105, 52, 94, 213, 156, 82, 162, 197, 34, 12, 29, 22, 139, 48, 84, 112, 126, 41, 149, 101, 184, 224, 175, 44, 195, 5, 136, 165, 45, 93, 101, 25, 50, 148, 85, 150, 225, 194, 86, 150, 161, 99, 157, 91, 247, 117, 95, 134, 15, 143, 32, 163, 161, 180, 98, 61, 194, 241, 183, 156, 244, 202, 56, 32, 8, 247, 116, 90, 177, 140, 161, 244, 125, 153, 47, 196, 251, 178, 109, 203, 88, 227, 181, 121, 152, 109, 203, 144, 97, 251, 53, 147, 8, 109, 126, 72, 175, 197, 182, 101, 232, 128, 155, 150, 218, 50, 100, 248, 166, 170, 45, 106, 203, 208, 193, 22, 109, 25, 66, 156, 217, 50, 92, 104, 12, 74, 203, 150, 33, 163, 149, 45, 83, 182, 12, 27, 203, 46, 101, 203, 112, 225, 108, 25, 115, 40, 91, 134, 15, 101, 203, 80, 97, 215, 90, 134, 143, 182, 75, 54, 106, 93, 107, 25, 66, 112, 241, 40, 181, 12, 23, 148, 237, 55, 180, 98, 87, 254, 186, 76, 232, 25, 118, 87, 141, 147, 58, 196, 73, 239, 112, 117, 207, 83, 44, 207, 183, 31, 66, 107, 255, 173, 149, 104, 129, 214, 101, 144, 1, 148, 101, 67, 173, 57, 61, 208, 116, 129, 54, 106, 101, 175, 33, 85, 156, 84, 65, 224, 4, 120, 152, 117, 207, 165, 84, 210, 30, 3, 93, 191, 223, 64, 83, 58, 215, 37, 87, 227, 253, 108, 251, 174, 10, 85, 60, 194, 64, 1, 156, 79, 198, 244, 87, 226, 9, 104, 8, 160, 107, 201, 119, 192, 105, 30, 183, 243, 42, 97, 26, 4, 12, 96, 33, 73, 219, 197, 255, 18, 45, 128, 49, 77, 131, 214, 255, 100, 223, 184, 5, 208, 128, 164, 147, 117, 178, 7, 254, 16, 190, 233, 68, 85, 23, 187, 18, 99, 117, 66, 15, 15, 111, 58, 27, 173, 159, 180, 155, 147, 58, 119, 192, 157, 150, 97, 195, 118, 90, 134, 11, 156, 150, 33, 196, 245, 51, 237, 226, 133, 61, 17, 16, 202, 246, 219, 107, 104, 238, 63, 128, 0, 38, 158, 10, 183, 67, 189, 64, 155, 29, 143, 74, 208, 131, 58, 41, 211, 67, 2, 6, 104, 109, 192, 253, 202, 144, 226, 53, 101, 190, 175, 12, 27, 248, 224, 188, 50, 231, 149, 33, 195, 193, 151, 247, 205, 250, 202, 48, 98, 66, 215, 239, 107, 147, 108, 35, 26, 111, 131, 124, 101, 248, 112, 126, 153, 175, 124, 101, 232, 64, 10, 110, 101, 184, 160, 218, 143, 114, 211, 246, 167, 163, 88, 118, 33, 93, 146, 86, 134, 14, 39, 159, 109, 101, 184, 248, 102, 143, 192, 160, 111, 229, 196, 85, 251, 31, 46, 25, 130, 112, 70, 219, 225, 141, 61, 178, 64, 211, 128, 248, 3, 215, 237, 108, 188, 159, 86, 194, 93, 89, 54, 228, 158, 43, 69, 52, 109, 157, 127, 90, 34, 7, 109, 90, 25, 46, 80, 88, 25, 42, 100, 5, 171, 166, 12, 23, 218, 252, 254, 180, 59, 180, 54, 233, 208, 211, 206, 160, 167, 27, 105, 153, 237, 212, 30, 79, 136, 54, 126, 96, 132, 71, 152, 50, 92, 208, 138, 101, 202, 144, 129, 31, 185, 100, 136, 145, 51, 76, 25, 22, 192, 25, 166, 140, 41, 195, 69, 131, 51, 136, 41, 67, 6, 198, 92, 129, 216, 99, 111, 149, 50, 108, 120, 90, 223, 4, 71, 171, 123, 254, 129, 144, 111, 169, 12, 23, 154, 98, 216, 224, 138, 97, 163, 41, 134, 13, 62, 165, 54, 90, 197, 176, 177, 15, 161, 85, 12, 31, 18, 63, 5, 63, 115, 69, 30, 169, 40, 70, 81, 241, 8, 170, 40, 86, 81, 236, 65, 69, 49, 231, 147, 61, 68, 232, 90, 242, 25, 211, 160, 181, 255, 24, 211, 56, 32, 198, 237, 0, 169, 150, 72, 181, 101, 24, 240, 198, 203, 224, 83, 238, 63, 9, 119, 92, 118, 147, 157, 14, 105, 133, 234, 155, 224, 14, 40, 242, 83, 249, 46, 164, 84, 162, 247, 84, 12, 27, 164, 253, 100, 136, 145, 4, 138, 225, 163, 162, 14, 146, 64, 49, 92, 232, 90, 6, 73, 160, 24, 50, 92, 145, 4, 138, 33, 3, 243, 164, 160, 149, 216, 123, 37, 25, 66, 168, 69, 91, 86, 73, 134, 12, 30, 113, 62, 25, 164, 146, 145, 213, 64, 112, 62, 25, 46, 30, 20, 205, 159, 207, 249, 100, 248, 192, 61, 33, 173, 216, 125, 104, 223, 196, 62, 111, 156, 214, 65, 127, 23, 197, 55, 102, 26, 167, 69, 15, 120, 227, 180, 168, 53, 235, 170, 22, 44, 74, 65, 222, 192, 155, 23, 167, 135, 92, 165, 12, 162, 117, 225, 84, 169, 206, 164, 214, 82, 208, 234, 39, 145, 171, 148, 57, 62, 145, 241, 116, 99, 79, 134, 36, 158, 12, 27, 43, 29, 239, 100, 184, 120, 22, 30, 127, 203, 161, 86, 212, 186, 64, 169, 82, 73, 39, 67, 6, 93, 175, 31, 236, 74, 8, 226, 219, 174, 4, 169, 120, 4, 241, 63, 52, 144, 180, 93, 13, 232, 151, 130, 97, 164, 107, 201, 119, 192, 37, 109, 25, 240, 167, 34, 151, 131, 138, 126, 74, 244, 185, 61, 51, 67, 241, 219, 255, 137, 126, 155, 157, 212, 18, 73, 252, 62, 38, 28, 194, 35, 26, 133, 149, 164, 147, 33, 195, 35, 16, 36, 157, 12, 23, 139, 202, 237, 100, 149, 166, 173, 147, 58, 25, 50, 112, 126, 153, 183, 58, 151, 12, 31, 171, 65, 21, 94, 26, 191, 190, 147, 206, 181, 108, 29, 181, 67, 100, 97, 228, 146, 225, 226, 151, 237, 66, 46, 153, 75, 134, 142, 182, 146, 108, 201, 180, 201, 150, 12, 31, 206, 51, 99, 201, 112, 193, 157, 146, 37, 195, 197, 174, 100, 168, 160, 76, 58, 114, 137, 6, 119, 220, 14, 162, 87, 33, 149, 36, 147, 36, 67, 7, 71, 146, 161, 194, 239, 114, 142, 13, 143, 160, 246, 154, 181, 201, 208, 1, 145, 48, 65, 235, 18, 57, 182, 78, 90, 155, 12, 33, 220, 115, 236, 80, 90, 102, 91, 147, 12, 29, 182, 31, 122, 109, 77, 50, 116, 236, 74, 219, 36, 75, 219, 36, 195, 198, 51, 38, 25, 46, 32, 231, 148, 12, 27, 124, 245, 67, 146, 148, 14, 66, 179, 173, 147, 146, 77, 224, 73, 96, 232, 152, 192, 147, 192, 240, 209, 250, 109, 23, 122, 18, 24, 58, 38, 192, 252, 171, 88, 200, 144, 172, 98, 161, 66, 197, 194, 70, 165, 61, 11, 21, 210, 126, 190, 35, 157, 35, 167, 44, 92, 232, 111, 83, 180, 145, 83, 22, 62, 42, 170, 218, 34, 167, 80, 22, 66, 156, 178, 80, 65, 227, 202, 91, 184, 144, 201, 223, 194, 133, 110, 111, 161, 130, 4, 19, 151, 36, 246, 10, 176, 183, 240, 225, 159, 239, 168, 2, 236, 45, 140, 168, 0, 123, 11, 29, 149, 95, 168, 224, 155, 95, 168, 224, 146, 85, 96, 161, 79, 223, 132, 70, 175, 23, 66, 94, 47, 108, 188, 211, 236, 162, 240, 66, 134, 103, 114, 128, 64, 199, 162, 40, 188, 112, 225, 241, 66, 7, 52, 241, 41, 181, 33, 206, 139, 116, 255, 121, 161, 195, 117, 185, 243, 194, 6, 199, 11, 21, 56, 206, 193, 33, 190, 45, 59, 214, 6, 169, 123, 62, 63, 213, 106, 154, 23, 65, 15, 22, 197, 77, 99, 182, 64, 75, 124, 179, 115, 79, 135, 24, 120, 230, 5, 53, 72, 82, 46, 142, 121, 33, 3, 23, 40, 203, 133, 142, 230, 112, 164, 105, 188, 144, 33, 121, 215, 166, 241, 66, 135, 127, 220, 120, 33, 164, 105, 188, 80, 161, 162, 139, 23, 46, 120, 100, 37, 188, 144, 97, 37, 188, 80, 129, 1, 82, 218, 188, 56, 33, 7, 150, 78, 116, 53, 188, 144, 241, 52, 13, 47, 92, 104, 26, 94, 248, 192, 154, 25, 198, 52, 188, 26, 94, 184, 120, 94, 217, 240, 194, 133, 71, 34, 104, 120, 33, 195, 130, 134, 151, 68, 195, 11, 29, 13, 47, 84, 224, 220, 115, 238, 213, 219, 115, 126, 41, 19, 182, 189, 213, 55, 97, 219, 155, 176, 237, 53, 76, 216, 246, 156, 95, 74, 227, 109, 15, 226, 89, 26, 111, 123, 141, 183, 189, 135, 239, 124, 103, 219, 175, 108, 251, 29, 216, 246, 59, 247, 184, 109, 46, 199, 79, 193, 239, 192, 207, 239, 224, 202, 246, 215, 63, 183, 243, 203, 55, 59, 99, 87, 73, 54, 215, 138, 245, 87, 87, 95, 142, 165, 175, 231, 239, 218, 234, 116, 194, 172, 55, 29, 228, 59, 223, 85, 186, 166, 42, 157, 74, 231, 120, 150, 86, 213, 156, 26, 63, 203, 47, 227, 95, 198, 20, 110, 14, 199, 220, 180, 98, 153, 41, 115, 120, 150, 74, 178, 74, 50, 135, 75, 6, 225, 143, 74, 92, 178, 247, 94, 166, 149, 194, 43, 66, 61, 83, 43, 133, 151, 231, 122, 84, 242, 120, 150, 71, 37, 234, 153, 150, 92, 84, 2, 209, 222, 195, 90, 175, 173, 109, 16, 39, 125, 178, 166, 233, 242, 8, 253, 109, 203, 248, 82, 36, 86, 190, 9, 207, 59, 166, 238, 160, 159, 202, 221, 215, 37, 83, 9, 79, 218, 66, 124, 235, 164, 173, 131, 191, 74, 117, 30, 109, 61, 29, 79, 199, 209, 244, 63, 23, 227, 240, 158, 75, 181, 101, 84, 162, 218, 50, 14, 204, 67, 39, 234, 42, 218, 104, 55, 56, 191, 20, 87, 77, 157, 95, 202, 146, 154, 122, 191, 69, 213, 195, 211, 253, 18, 167, 7, 87, 207, 180, 148, 101, 130, 0, 161, 218, 46, 16, 62, 33, 56, 191, 20, 231, 151, 210, 246, 233, 116, 56, 56, 159, 142, 255, 53, 237, 106, 240, 71, 37, 108, 29, 87, 109, 151, 87, 103, 86, 237, 53, 240, 86, 181, 216, 209, 201, 126, 54, 109, 136, 39, 187, 83, 61, 117, 105, 235, 231, 98, 215, 250, 109, 181, 23, 60, 217, 157, 175, 77, 167, 147, 58, 157, 180, 216, 59, 175, 222, 170, 218, 99, 199, 184, 25, 56, 41, 19, 133, 36, 229, 178, 86, 38, 213, 214, 245, 173, 156, 72, 76, 216, 246, 92, 41, 156, 244, 201, 86, 190, 9, 234, 19, 175, 77, 243, 131, 122, 46, 21, 85, 109, 85, 91, 70, 61, 23, 136, 9, 39, 165, 62, 142, 211, 147, 221, 89, 1, 8, 17, 15, 181, 174, 168, 225, 120, 42, 94, 200, 208, 146, 196, 75, 146, 120, 33, 67, 146, 120, 161, 194, 63, 154, 182, 21, 27, 161, 77, 54, 51, 143, 141, 48, 83, 164, 139, 82, 32, 150, 251, 67, 35, 113, 104, 101, 226, 118, 79, 106, 88, 153, 120, 33, 196, 35, 12, 238, 9, 130, 183, 122, 4, 66, 163, 181, 181, 181, 215, 13, 206, 160, 86, 199, 83, 37, 47, 92, 248, 131, 174, 117, 120, 64, 92, 226, 249, 16, 205, 50, 17, 20, 13, 147, 144, 74, 94, 200, 88, 20, 91, 232, 240, 166, 173, 106, 187, 32, 54, 89, 11, 27, 84, 242, 210, 214, 201, 46, 116, 80, 252, 239, 194, 134, 86, 73, 90, 167, 191, 11, 29, 173, 191, 11, 31, 187, 144, 177, 80, 129, 126, 42, 247, 90, 91, 85, 211, 70, 223, 116, 173, 47, 248, 231, 218, 162, 71, 47, 60, 204, 54, 117, 34, 16, 222, 119, 225, 194, 125, 23, 66, 48, 253, 69, 239, 106, 223, 132, 93, 248, 96, 166, 45, 98, 205, 204, 231, 114, 168, 242, 218, 46, 156, 80, 218, 228, 59, 250, 246, 48, 43, 105, 187, 208, 129, 36, 109, 23, 70, 248, 251, 190, 166, 237, 66, 137, 138, 5, 73, 106, 47, 205, 159, 116, 130, 58, 181, 237, 66, 10, 109, 219, 118, 53, 246, 22, 39, 8, 109, 187, 208, 179, 32, 109, 187, 16, 210, 186, 104, 148, 116, 254, 248, 69, 191, 108, 23, 50, 214, 46, 108, 168, 125, 15, 173, 93, 200, 216, 215, 160, 181, 11, 23, 18, 110, 29, 111, 180, 54, 13, 47, 164, 254, 216, 81, 127, 236, 56, 158, 214, 181, 178, 129, 180, 70, 68, 168, 240, 210, 120, 24, 122, 167, 217, 133, 16, 238, 61, 179, 11, 25, 24, 134, 159, 217, 133, 11, 221, 133, 10, 24, 168, 55, 77, 187, 240, 33, 66, 195, 35, 139, 85, 150, 93, 200, 112, 249, 203, 46, 100, 112, 9, 246, 86, 177, 47, 187, 176, 49, 193, 45, 187, 26, 120, 4, 97, 68, 3, 115, 109, 217, 133, 144, 101, 23, 54, 212, 113, 114, 180, 50, 109, 69, 23, 54, 180, 46, 116, 84, 116, 161, 130, 54, 209, 133, 10, 232, 87, 41, 122, 208, 86, 223, 241, 246, 116, 54, 70, 115, 111, 209, 40, 172, 36, 220, 225, 157, 37, 170, 142, 118, 112, 217, 20, 212, 120, 223, 113, 4, 83, 214, 168, 44, 243, 240, 153, 218, 130, 164, 138, 19, 122, 44, 157, 232, 194, 133, 5, 12, 36, 216, 215, 212, 49, 68, 23, 62, 220, 117, 161, 66, 182, 214, 133, 11, 237, 165, 147, 180, 157, 46, 116, 168, 116, 232, 25, 93, 200, 144, 168, 46, 84, 104, 125, 127, 43, 181, 74, 58, 217, 130, 111, 249, 143, 65, 104, 125, 114, 169, 237, 6, 194, 3, 172, 77, 4, 37, 91, 33, 132, 168, 212, 133, 10, 30, 113, 169, 22, 50, 184, 84, 43, 45, 116, 88, 207, 181, 37, 38, 156, 22, 58, 212, 166, 133, 10, 174, 21, 235, 13, 119, 109, 30, 129, 176, 88, 57, 153, 52, 125, 86, 104, 193, 4, 117, 70, 69, 46, 116, 60, 21, 185, 80, 161, 129, 198, 140, 73, 148, 163, 200, 2, 207, 146, 116, 42, 116, 160, 21, 219, 246, 115, 33, 163, 245, 115, 225, 66, 123, 205, 208, 182, 11, 98, 173, 76, 232, 61, 23, 58, 112, 104, 242, 151, 231, 8, 29, 120, 211, 114, 225, 130, 51, 140, 134, 23, 58, 30, 9, 66, 30, 9, 6, 96, 35, 204, 184, 159, 4, 25, 173, 235, 73, 112, 65, 159, 4, 21, 184, 190, 182, 214, 229, 73, 48, 162, 242, 18, 108, 168, 125, 46, 193, 5, 119, 9, 42, 104, 171, 239, 94, 75, 144, 145, 147, 198, 18, 92, 104, 217, 88, 130, 11, 239, 219, 188, 88, 130, 12, 207, 149, 44, 65, 134, 207, 118, 240, 230, 132, 34, 36, 75, 176, 241, 112, 138, 238, 196, 73, 153, 16, 196, 67, 53, 245, 118, 232, 63, 238, 134, 54, 45, 123, 2, 67, 243, 156, 170, 237, 214, 9, 163, 100, 9, 66, 50, 249, 107, 80, 34, 139, 198, 30, 241, 8, 242, 125, 180, 9, 64, 176, 76, 123, 98, 120, 115, 250, 214, 201, 107, 179, 170, 77, 168, 51, 75, 240, 241, 40, 126, 20, 51, 22, 36, 75, 208, 33, 89, 130, 10, 156, 234, 114, 196, 18, 100, 40, 85, 170, 142, 116, 49, 204, 115, 28, 57, 255, 154, 4, 41, 42, 220, 36, 168, 224, 186, 77, 130, 20, 255, 88, 146, 184, 73, 144, 145, 141, 151, 4, 23, 250, 233, 146, 224, 130, 182, 101, 152, 68, 106, 73, 208, 145, 218, 227, 136, 146, 75, 130, 13, 134, 145, 106, 43, 65, 107, 173, 4, 27, 201, 184, 29, 9, 50, 32, 109, 178, 249, 93, 31, 83, 134, 38, 143, 74, 176, 97, 242, 168, 4, 21, 188, 55, 221, 147, 110, 209, 220, 189, 143, 74, 176, 225, 182, 155, 71, 37, 184, 240, 8, 82, 197, 233, 81, 9, 58, 36, 201, 43, 61, 42, 65, 8, 196, 184, 25, 213, 201, 203, 163, 18, 84, 128, 78, 250, 37, 69, 234, 185, 60, 42, 65, 7, 138, 74, 80, 129, 115, 235, 210, 42, 65, 70, 47, 163, 18, 167, 42, 209, 201, 174, 68, 78, 85, 130, 16, 168, 169, 74, 240, 49, 129, 4, 17, 26, 146, 76, 73, 37, 200, 128, 14, 111, 78, 18, 92, 112, 141, 91, 36, 184, 80, 209, 79, 9, 46, 56, 56, 47, 173, 19, 69, 186, 188, 9, 157, 141, 157, 219, 122, 227, 182, 143, 5, 233, 165, 83, 108, 39, 147, 190, 192, 189, 181, 184, 127, 219, 155, 240, 104, 154, 3, 233, 36, 102, 143, 134, 141, 208, 181, 76, 3, 143, 68, 88, 96, 98, 210, 148, 129, 15, 224, 193, 174, 134, 50, 238, 5, 155, 78, 114, 48, 240, 48, 11, 209, 188, 116, 201, 5, 37, 235, 148, 160, 3, 166, 218, 41, 65, 6, 93, 207, 93, 74, 112, 209, 250, 190, 202, 214, 82, 151, 18, 108, 240, 72, 74, 152, 148, 188, 5, 73, 144, 81, 137, 32, 67, 151, 99, 235, 250, 148, 8, 58, 152, 58, 196, 143, 36, 148, 8, 58, 94, 253, 181, 65, 202, 164, 55, 168, 103, 66, 75, 46, 42, 105, 240, 120, 150, 115, 137, 30, 24, 102, 27, 191, 16, 191, 232, 233, 126, 9, 189, 191, 8, 54, 244, 139, 224, 194, 195, 109, 133, 71, 112, 161, 105, 235, 168, 226, 17, 108, 248, 156, 120, 4, 23, 38, 30, 65, 5, 219, 207, 35, 184, 80, 241, 30, 65, 5, 151, 172, 161, 218, 223, 224, 17, 124, 44, 86, 225, 247, 8, 46, 60, 130, 16, 159, 239, 17, 92, 112, 143, 32, 164, 155, 85, 211, 201, 2, 19, 186, 150, 28, 192, 122, 253, 192, 55, 59, 114, 199, 237, 148, 190, 107, 139, 144, 208, 143, 136, 104, 32, 177, 64, 63, 23, 251, 234, 187, 71, 208, 241, 219, 30, 114, 143, 32, 196, 67, 89, 38, 228, 30, 65, 7, 247, 8, 42, 80, 154, 158, 210, 70, 17, 173, 89, 79, 111, 143, 96, 163, 129, 185, 198, 96, 206, 35, 248, 96, 148, 243, 8, 46, 56, 159, 206, 35, 139, 82, 126, 23, 74, 174, 55, 157, 182, 227, 225, 188, 122, 167, 115, 141, 61, 130, 11, 138, 89, 219, 133, 190, 237, 114, 248, 182, 75, 219, 54, 212, 74, 219, 216, 35, 200, 224, 112, 210, 167, 99, 152, 85, 144, 180, 88, 62, 141, 197, 124, 85, 34, 48, 30, 156, 227, 34, 76, 60, 69, 96, 60, 204, 126, 179, 67, 88, 44, 31, 244, 48, 233, 154, 182, 165, 125, 95, 85, 168, 129, 135, 87, 73, 98, 138, 119, 219, 201, 159, 223, 213, 249, 4, 195, 107, 101, 131, 5, 173, 146, 100, 24, 102, 25, 109, 85, 207, 239, 218, 101, 255, 129, 118, 58, 198, 105, 189, 8, 181, 201, 117, 99, 111, 203, 16, 255, 215, 5, 53, 157, 168, 3, 78, 250, 116, 16, 18, 79, 230, 17, 148, 182, 225, 134, 133, 26, 87, 116, 49, 165, 15, 205, 42, 65, 238, 41, 6, 186, 210, 147, 42, 143, 169, 66, 18, 173, 12, 243, 216, 107, 143, 94, 151, 168, 177, 71, 112, 98, 226, 9, 69, 64, 141, 61, 130, 10, 202, 216, 35, 184, 16, 129, 161, 45, 243, 8, 46, 124, 219, 229, 17, 100, 144, 36, 75, 237, 143, 252, 87, 103, 136, 36, 89, 74, 135, 118, 61, 130, 143, 93, 143, 160, 194, 183, 117, 60, 130, 12, 174, 142, 167, 227, 17, 100, 168, 237, 198, 35, 200, 224, 158, 241, 8, 46, 104, 106, 102, 60, 130, 139, 228, 234, 17, 92, 112, 234, 17, 84, 104, 234, 17, 84, 128, 176, 5, 125, 147, 207, 118, 72, 221, 211, 128, 63, 162, 162, 141, 182, 122, 167, 91, 186, 228, 242, 88, 151, 168, 145, 88, 121, 4, 23, 242, 83, 161, 166, 18, 234, 201, 46, 85, 30, 193, 136, 92, 165, 108, 37, 75, 65, 175, 174, 237, 22, 36, 86, 30, 65, 158, 60, 130, 14, 229, 146, 71, 112, 225, 153, 117, 92, 21, 39, 143, 224, 227, 85, 117, 58, 201, 35, 216, 104, 139, 71, 80, 97, 23, 143, 160, 66, 75, 143, 160, 194, 98, 149, 8, 30, 65, 136, 195, 98, 249, 32, 143, 224, 226, 97, 22, 162, 46, 147, 43, 68, 4, 8, 36, 144, 48, 129, 4, 17, 210, 129, 32, 157, 197, 39, 93, 30, 193, 134, 71, 144, 225, 30, 65, 136, 71, 112, 194, 35, 232, 144, 64, 49, 228, 17, 100, 64, 79, 103, 47, 187, 144, 71, 112, 34, 21, 71, 144, 71, 112, 225, 204, 249, 109, 110, 86, 34, 156, 136, 32, 132, 167, 109, 254, 108, 187, 48, 78, 200, 35, 8, 17, 193, 6, 200, 35, 248, 136, 96, 99, 101, 91, 214, 250, 252, 16, 190, 217, 121, 203, 254, 6, 77, 91, 79, 213, 149, 48, 39, 8, 13, 175, 157, 9, 130, 78, 214, 95, 255, 194, 237, 33, 7, 26, 175, 147, 218, 115, 251, 22, 232, 82, 237, 45, 104, 223, 190, 198, 90, 203, 124, 69, 95, 219, 46, 73, 167, 131, 96, 187, 252, 105, 125, 19, 88, 118, 58, 200, 82, 117, 40, 234, 143, 89, 132, 126, 118, 179, 236, 157, 102, 213, 65, 78, 250, 137, 165, 233, 146, 53, 176, 102, 230, 193, 178, 211, 57, 40, 237, 86, 70, 213, 131, 47, 249, 168, 105, 187, 22, 119, 114, 1, 32, 3, 219, 126, 52, 33, 130, 139, 182, 11, 106, 217, 223, 168, 139, 32, 196, 35, 168, 81, 23, 193, 197, 230, 115, 4, 23, 212, 57, 130, 10, 217, 28, 65, 5, 118, 28, 90, 142, 32, 196, 114, 4, 31, 203, 17, 84, 240, 171, 56, 130, 11, 20, 128, 64, 2, 9, 34, 168, 85, 28, 97, 231, 150, 68, 240, 241, 237, 117, 131, 126, 35, 216, 104, 156, 161, 95, 150, 78, 219, 53, 104, 118, 200, 222, 8, 62, 28, 219, 8, 42, 44, 86, 209, 38, 130, 12, 171, 162, 17, 84, 80, 139, 208, 209, 42, 105, 126, 184, 147, 62, 41, 77, 155, 108, 245, 39, 73, 204, 16, 255, 75, 228, 17, 139, 229, 227, 158, 144, 196, 111, 98, 169, 223, 76, 40, 252, 155, 54, 165, 235, 121, 237, 124, 71, 90, 102, 147, 58, 103, 208, 224, 250, 136, 194, 171, 193, 98, 239, 160, 86, 182, 15, 113, 247, 184, 27, 137, 214, 214, 94, 63, 208, 201, 98, 215, 118, 208, 220, 173, 238, 83, 186, 134, 251, 119, 112, 222, 74, 34, 73, 98, 150, 171, 148, 57, 233, 147, 181, 126, 183, 23, 153, 248, 109, 47, 18, 65, 61, 19, 106, 235, 173, 223, 236, 244, 61, 157, 6, 36, 137, 153, 46, 118, 180, 54, 25, 165, 73, 93, 101, 98, 1, 85, 220, 22, 52, 213, 175, 172, 59, 208, 84, 191, 31, 11, 160, 169, 62, 179, 12, 122, 128, 41, 107, 220, 59, 105, 12, 32, 140, 213, 68, 31, 36, 137, 25, 210, 79, 229, 208, 224, 218, 168, 92, 144, 54, 217, 58, 161, 104, 150, 105, 252, 216, 149, 252, 165, 222, 212, 54, 157, 228, 208, 10, 67, 251, 173, 149, 232, 93, 35, 248, 120, 215, 8, 42, 52, 78, 251, 77, 85, 4, 27, 220, 36, 82, 182, 63, 65, 161, 109, 157, 148, 204, 65, 243, 103, 242, 199, 44, 188, 224, 155, 29, 27, 76, 50, 130, 143, 8, 138, 226, 239, 72, 234, 124, 129, 42, 110, 174, 107, 233, 100, 15, 173, 20, 238, 134, 193, 39, 117, 21, 7, 134, 89, 165, 205, 169, 146, 145, 68, 16, 109, 203, 60, 35, 184, 112, 156, 240, 8, 218, 149, 185, 50, 130, 14, 149, 100, 4, 21, 214, 102, 4, 31, 173, 141, 102, 4, 27, 36, 169, 206, 37, 41, 35, 216, 120, 118, 146, 148, 17, 92, 188, 39, 255, 86, 108, 131, 67, 51, 210, 135, 88, 107, 193, 255, 139, 18, 191, 232, 112, 166, 191, 184, 208, 12, 42, 201, 71, 191, 184, 104, 197, 134, 174, 37, 37, 170, 14, 61, 250, 69, 134, 247, 92, 232, 23, 23, 139, 139, 247, 102, 252, 98, 163, 109, 182, 66, 191, 200, 248, 92, 108, 252, 34, 99, 173, 68, 191, 200, 176, 250, 101, 219, 165, 249, 43, 250, 190, 232, 208, 170, 22, 59, 174, 237, 252, 2, 14, 161, 77, 43, 115, 152, 144, 48, 59, 17, 203, 174, 5, 236, 245, 123, 91, 200, 227, 185, 175, 47, 50, 254, 241, 147, 11, 169, 227, 103, 95, 116, 240, 197, 198, 111, 227, 64, 225, 164, 87, 6, 34, 173, 227, 154, 25, 251, 98, 4, 4, 17, 152, 96, 2, 236, 139, 16, 254, 45, 217, 23, 27, 36, 52, 156, 10, 4, 1, 162, 128, 132, 9, 16, 251, 34, 36, 2, 130, 0, 77, 48, 1, 4, 18, 16, 251, 162, 68, 218, 214, 134, 47, 50, 60, 162, 107, 23, 102, 221, 234, 139, 11, 95, 108, 60, 47, 190, 184, 160, 107, 25, 95, 95, 92, 68, 240, 69, 5, 110, 43, 156, 65, 53, 83, 144, 47, 70, 52, 248, 116, 22, 175, 238, 146, 73, 82, 41, 200, 215, 249, 198, 204, 65, 83, 203, 247, 22, 49, 177, 240, 106, 26, 208, 226, 195, 210, 234, 158, 163, 213, 175, 97, 251, 57, 247, 144, 47, 54, 44, 82, 56, 159, 14, 165, 246, 26, 28, 24, 70, 142, 253, 138, 126, 62, 195, 226, 133, 61, 159, 14, 53, 19, 71, 190, 248, 104, 114, 49, 200, 57, 232, 85, 203, 147, 180, 92, 203, 115, 67, 170, 37, 74, 237, 111, 56, 254, 12, 77, 91, 231, 149, 16, 179, 30, 94, 59, 169, 55, 154, 182, 173, 189, 166, 240, 90, 137, 158, 126, 237, 37, 125, 157, 79, 135, 32, 114, 189, 7, 165, 173, 239, 219, 224, 42, 218, 52, 180, 145, 175, 179, 8, 105, 120, 190, 213, 61, 124, 209, 161, 107, 73, 167, 217, 33, 111, 155, 11, 162, 106, 221, 65, 81, 18, 106, 139, 156, 79, 167, 34, 11, 35, 95, 100, 80, 201, 46, 180, 232, 192, 92, 67, 190, 203, 173, 21, 72, 39, 11, 241, 217, 104, 67, 190, 248, 176, 178, 95, 68, 54, 228, 139, 12, 106, 87, 78, 30, 8, 93, 79, 233, 218, 133, 25, 242, 197, 198, 90, 114, 113, 194, 37, 67, 190, 200, 64, 225, 165, 56, 33, 95, 132, 104, 188, 136, 32, 95, 116, 68, 22, 142, 32, 95, 108, 104, 92, 4, 249, 34, 131, 51, 110, 225, 22, 249, 226, 130, 78, 246, 83, 182, 190, 195, 179, 22, 52, 104, 147, 108, 155, 151, 171, 232, 34, 95, 132, 44, 246, 14, 242, 197, 197, 163, 146, 103, 7, 249, 98, 35, 29, 84, 69, 29, 228, 139, 15, 139, 139, 213, 207, 241, 52, 255, 58, 59, 237, 136, 231, 123, 213, 47, 179, 13, 242, 69, 6, 117, 244, 15, 144, 198, 160, 166, 13, 239, 167, 246, 30, 223, 150, 29, 82, 197, 9, 57, 175, 150, 178, 214, 107, 12, 242, 197, 133, 167, 27, 239, 103, 197, 174, 108, 13, 152, 171, 55, 52, 157, 40, 242, 197, 133, 106, 166, 60, 42, 65, 19, 64, 16, 129, 8, 30, 209, 220, 237, 139, 16, 207, 59, 166, 140, 181, 201, 84, 146, 88, 33, 135, 244, 50, 40, 109, 203, 32, 95, 116, 52, 43, 180, 40, 225, 248, 221, 23, 27, 220, 115, 49, 58, 215, 75, 189, 173, 54, 33, 95, 92, 232, 90, 114, 173, 76, 200, 23, 31, 109, 127, 237, 91, 144, 47, 70, 248, 34, 133, 234, 93, 244, 61, 36, 45, 215, 130, 124, 145, 209, 217, 28, 190, 109, 179, 17, 76, 160, 158, 11, 242, 197, 70, 99, 80, 106, 143, 63, 28, 223, 39, 187, 23, 25, 173, 20, 111, 40, 253, 100, 219, 18, 249, 226, 99, 101, 196, 202, 180, 175, 75, 58, 110, 37, 242, 197, 7, 95, 12, 128, 107, 247, 98, 196, 162, 163, 113, 47, 42, 76, 48, 113, 139, 14, 148, 108, 198, 226, 30, 205, 75, 66, 77, 170, 134, 229, 22, 29, 190, 246, 159, 227, 155, 238, 130, 240, 181, 255, 24, 183, 248, 208, 74, 229, 4, 110, 113, 49, 129, 91, 84, 208, 110, 177, 81, 209, 70, 27, 185, 69, 134, 91, 116, 112, 139, 1, 96, 235, 200, 121, 113, 145, 182, 241, 226, 66, 171, 218, 229, 141, 23, 31, 90, 215, 226, 142, 64, 104, 149, 112, 47, 188, 200, 192, 155, 182, 255, 234, 16, 216, 91, 231, 18, 2, 47, 74, 184, 186, 231, 31, 254, 136, 23, 31, 26, 60, 204, 122, 235, 36, 183, 115, 210, 22, 27, 206, 191, 100, 244, 251, 190, 45, 66, 60, 2, 129, 251, 219, 34, 131, 165, 182, 197, 199, 63, 215, 22, 45, 125, 180, 190, 245, 202, 126, 203, 65, 60, 144, 80, 234, 235, 219, 162, 130, 78, 82, 41, 14, 6, 90, 125, 193, 107, 59, 151, 172, 241, 188, 28, 53, 172, 108, 12, 77, 201, 60, 252, 99, 245, 142, 222, 105, 130, 216, 135, 90, 191, 161, 93, 12, 150, 126, 91, 92, 104, 109, 244, 219, 226, 66, 130, 4, 223, 22, 23, 220, 19, 132, 111, 17, 136, 113, 51, 232, 83, 50, 251, 157, 104, 173, 6, 214, 229, 123, 91, 92, 208, 252, 160, 218, 74, 48, 226, 157, 102, 189, 45, 46, 220, 19, 58, 34, 52, 208, 3, 231, 211, 77, 188, 99, 186, 28, 227, 196, 255, 18, 53, 208, 218, 251, 38, 180, 69, 134, 54, 39, 228, 32, 241, 100, 141, 207, 231, 218, 34, 100, 129, 187, 3, 31, 30, 73, 91, 84, 144, 180, 197, 135, 203, 126, 79, 172, 144, 164, 45, 66, 42, 188, 32, 73, 91, 92, 72, 90, 227, 133, 188, 170, 131, 17, 200, 216, 182, 168, 192, 25, 191, 173, 78, 91, 92, 48, 211, 22, 31, 141, 23, 29, 76, 91, 108, 124, 211, 38, 17, 58, 120, 147, 107, 50, 161, 180, 211, 241, 207, 86, 143, 243, 224, 217, 95, 81, 6, 238, 185, 18, 197, 167, 99, 236, 160, 138, 219, 4, 77, 112, 91, 180, 54, 10, 163, 86, 166, 45, 62, 190, 181, 45, 46, 84, 84, 91, 84, 88, 249, 212, 78, 86, 181, 69, 71, 197, 193, 48, 114, 173, 32, 165, 21, 85, 109, 209, 129, 23, 139, 12, 207, 154, 180, 250, 194, 104, 129, 254, 46, 58, 214, 122, 14, 170, 232, 164, 113, 66, 216, 160, 213, 249, 116, 11, 90, 213, 98, 166, 45, 58, 160, 182, 232, 72, 206, 22, 21, 126, 213, 75, 157, 112, 59, 182, 56, 225, 174, 235, 41, 118, 200, 87, 54, 81, 241, 136, 243, 168, 45, 69, 3, 227, 135, 227, 218, 12, 68, 81, 18, 114, 32, 131, 46, 247, 254, 193, 23, 243, 79, 84, 33, 9, 93, 141, 231, 119, 45, 78, 232, 231, 42, 101, 108, 177, 225, 108, 177, 209, 202, 22, 29, 30, 65, 12, 179, 10, 53, 108, 241, 161, 203, 177, 117, 228, 146, 45, 62, 92, 178, 69, 5, 143, 180, 166, 236, 111, 80, 170, 146, 151, 55, 88, 214, 192, 205, 196, 81, 91, 246, 45, 223, 132, 166, 185, 136, 166, 185, 125, 199, 168, 45, 131, 104, 212, 69, 42, 152, 161, 182, 108, 87, 66, 144, 182, 140, 65, 161, 238, 121, 182, 94, 177, 238, 208, 127, 93, 233, 42, 150, 109, 219, 7, 242, 149, 57, 32, 180, 223, 187, 76, 72, 155, 100, 139, 13, 75, 243, 175, 69, 6, 119, 112, 134, 209, 176, 76, 23, 64, 207, 130, 34, 180, 185, 53, 139, 12, 20, 173, 21, 235, 205, 44, 58, 116, 43, 179, 184, 48, 105, 138, 152, 69, 134, 166, 142, 185, 233, 34, 35, 2, 9, 36, 160, 170, 139, 139, 138, 90, 84, 224, 106, 81, 129, 71, 144, 46, 181, 184, 88, 57, 121, 84, 130, 22, 181, 232, 88, 212, 162, 2, 79, 139, 14, 79, 139, 10, 244, 119, 33, 199, 164, 113, 90, 92, 144, 164, 117, 154, 22, 23, 16, 165, 105, 209, 225, 50, 33, 77, 139, 11, 143, 64, 88, 153, 22, 23, 173, 104, 101, 90, 108, 104, 102, 203, 226, 2, 245, 120, 37, 196, 150, 69, 9, 95, 204, 223, 114, 89, 108, 180, 92, 22, 21, 28, 84, 113, 107, 80, 177, 137, 23, 131, 6, 94, 218, 135, 251, 119, 84, 83, 73, 162, 112, 70, 194, 73, 13, 154, 43, 218, 38, 0, 193, 226, 0, 28, 211, 111, 56, 36, 2, 106, 19, 128, 96, 145, 161, 77, 0, 130, 69, 5, 101, 217, 208, 39, 69, 83, 199, 61, 14, 50, 60, 223, 234, 8, 240, 174, 111, 130, 163, 85, 210, 118, 61, 212, 46, 90, 221, 227, 32, 164, 105, 243, 56, 184, 240, 72, 252, 57, 184, 208, 218, 158, 131, 11, 86, 63, 136, 191, 229, 30, 156, 33, 173, 88, 173, 88, 127, 68, 129, 180, 98, 35, 180, 98, 149, 237, 59, 124, 101, 107, 214, 27, 86, 78, 90, 191, 57, 168, 69, 45, 217, 115, 144, 209, 118, 65, 220, 60, 7, 25, 207, 206, 23, 146, 148, 203, 127, 221, 58, 14, 105, 170, 238, 13, 174, 235, 117, 219, 236, 69, 89, 243, 156, 67, 63, 151, 183, 236, 103, 224, 19, 142, 34, 158, 151, 231, 224, 194, 55, 109, 210, 29, 194, 221, 191, 131, 11, 186, 17, 34, 72, 168, 226, 132, 30, 141, 194, 234, 159, 227, 252, 19, 79, 133, 123, 193, 59, 59, 143, 32, 135, 166, 45, 55, 255, 88, 210, 118, 65, 52, 109, 25, 167, 182, 16, 119, 63, 89, 77, 170, 26, 214, 202, 228, 105, 191, 37, 83, 71, 234, 164, 76, 20, 105, 61, 23, 135, 43, 114, 74, 132, 243, 175, 241, 253, 239, 224, 195, 253, 59, 168, 240, 216, 249, 165, 160, 8, 15, 7, 183, 108, 223, 118, 49, 84, 113, 170, 0, 132, 90, 20, 65, 4, 2, 163, 92, 132, 135, 231, 164, 101, 138, 224, 202, 178, 161, 38, 31, 233, 100, 223, 0, 238, 86, 226, 2, 152, 232, 199, 4, 144, 248, 42, 213, 233, 52, 224, 106, 121, 210, 236, 160, 13, 95, 209, 71, 252, 42, 73, 198, 40, 135, 248, 189, 209, 228, 51, 92, 215, 243, 159, 116, 169, 63, 24, 136, 136, 240, 48, 75, 209, 186, 204, 182, 101, 239, 26, 65, 173, 46, 147, 55, 180, 50, 204, 54, 95, 224, 146, 33, 166, 75, 33, 140, 149, 132, 235, 191, 101, 251, 63, 209, 98, 239, 224, 195, 98, 239, 160, 194, 228, 45, 119, 112, 33, 221, 65, 199, 114, 7, 27, 223, 24, 109, 7, 33, 19, 156, 131, 10, 156, 115, 80, 129, 147, 56, 73, 74, 231, 32, 163, 117, 81, 216, 65, 6, 143, 32, 127, 84, 242, 236, 160, 195, 159, 29, 71, 207, 14, 54, 114, 61, 118, 80, 66, 215, 190, 179, 131, 139, 199, 49, 59, 184, 160, 180, 178, 12, 122, 248, 130, 174, 37, 213, 59, 146, 48, 59, 200, 224, 198, 14, 42, 120, 4, 181, 54, 42, 151, 71, 27, 59, 232, 0, 209, 171, 148, 177, 131, 139, 10, 218, 199, 64, 27, 181, 189, 40, 99, 7, 29, 206, 167, 67, 202, 216, 193, 134, 99, 143, 154, 145, 50, 118, 212, 98, 7, 25, 206, 13, 189, 47, 59, 216, 192, 35, 16, 90, 54, 236, 32, 67, 162, 236, 160, 2, 4, 233, 120, 74, 230, 32, 163, 89, 28, 108, 120, 4, 130, 47, 7, 25, 26, 123, 196, 193, 133, 165, 32, 9, 92, 248, 42, 237, 117, 112, 209, 186, 233, 36, 183, 14, 66, 60, 191, 106, 23, 59, 242, 72, 4, 2, 3, 107, 194, 132, 54, 39, 228, 170, 153, 66, 225, 138, 222, 105, 118, 65, 84, 203, 229, 52, 235, 32, 67, 223, 196, 193, 129, 132, 127, 167, 147, 156, 75, 29, 27, 124, 210, 165, 142, 12, 170, 173, 106, 169, 35, 131, 23, 33, 126, 189, 100, 26, 117, 132, 248, 199, 18, 85, 199, 133, 219, 138, 5, 73, 84, 29, 27, 74, 213, 209, 161, 84, 29, 31, 13, 190, 26, 253, 146, 58, 52, 59, 66, 64, 32, 153, 64, 130, 8, 46, 169, 99, 195, 89, 118, 186, 6, 127, 167, 89, 111, 139, 240, 193, 129, 187, 46, 150, 234, 40, 225, 148, 163, 2, 245, 92, 144, 68, 57, 50, 90, 43, 214, 61, 57, 58, 60, 206, 240, 72, 195, 61, 157, 28, 33, 144, 180, 77, 178, 135, 243, 106, 41, 168, 115, 105, 80, 170, 84, 27, 98, 22, 45, 64, 209, 157, 32, 254, 182, 14, 154, 119, 146, 142, 46, 232, 161, 105, 139, 12, 13, 21, 69, 248, 128, 187, 133, 227, 151, 184, 42, 244, 236, 184, 196, 90, 143, 65, 135, 227, 228, 232, 112, 93, 184, 238, 111, 218, 167, 240, 181, 255, 16, 210, 200, 72, 142, 143, 214, 79, 142, 144, 165, 173, 165, 147, 80, 114, 116, 60, 204, 58, 66, 22, 199, 0, 120, 211, 74, 58, 46, 84, 210, 81, 193, 99, 162, 10, 233, 36, 29, 25, 58, 73, 71, 5, 164, 233, 165, 35, 131, 111, 187, 26, 159, 60, 29, 33, 238, 233, 168, 208, 234, 92, 58, 50, 56, 233, 211, 61, 238, 9, 2, 100, 98, 177, 119, 26, 48, 162, 177, 71, 216, 241, 35, 109, 233, 216, 208, 170, 90, 58, 50, 120, 235, 50, 235, 158, 95, 128, 194, 142, 163, 167, 243, 125, 106, 233, 232, 192, 210, 89, 58, 50, 60, 204, 46, 150, 142, 11, 150, 142, 143, 247, 85, 200, 35, 16, 120, 33, 232, 90, 6, 130, 53, 35, 9, 179, 131, 28, 36, 190, 10, 249, 218, 116, 92, 88, 57, 81, 212, 142, 134, 248, 2, 157, 44, 246, 8, 21, 109, 180, 43, 218, 104, 79, 168, 247, 67, 91, 142, 124, 46, 166, 1, 81, 38, 29, 31, 173, 78, 106, 47, 215, 67, 101, 25, 180, 168, 69, 17, 64, 128, 182, 147, 73, 199, 8, 85, 233, 168, 32, 81, 142, 210, 37, 56, 50, 40, 109, 205, 186, 4, 71, 70, 235, 164, 37, 56, 50, 72, 112, 132, 120, 120, 57, 85, 72, 130, 99, 35, 130, 227, 35, 226, 219, 46, 255, 135, 243, 75, 65, 46, 217, 251, 75, 167, 226, 64, 122, 69, 30, 169, 52, 50, 60, 82, 105, 84, 112, 9, 253, 93, 168, 210, 184, 168, 52, 6, 128, 210, 24, 0, 87, 247, 124, 123, 141, 140, 246, 26, 27, 77, 155, 246, 26, 25, 92, 219, 107, 92, 104, 175, 189, 198, 7, 18, 168, 189, 70, 200, 107, 100, 52, 78, 168, 189, 198, 69, 106, 143, 39, 106, 175, 177, 225, 158, 214, 55, 50, 172, 111, 116, 184, 137, 55, 42, 232, 90, 242, 17, 68, 127, 159, 55, 50, 184, 55, 42, 112, 224, 234, 158, 111, 208, 181, 36, 133, 23, 211, 8, 153, 192, 188, 241, 49, 129, 121, 163, 130, 171, 40, 82, 204, 152, 58, 148, 158, 222, 232, 208, 245, 186, 113, 193, 147, 107, 116, 240, 8, 132, 165, 19, 110, 100, 184, 91, 212, 205, 208, 90, 177, 173, 225, 164, 13, 1, 81, 197, 205, 161, 255, 184, 241, 193, 143, 84, 123, 220, 200, 80, 199, 141, 13, 206, 167, 123, 230, 70, 198, 51, 55, 58, 92, 194, 220, 184, 224, 107, 255, 73, 232, 155, 60, 223, 137, 131, 135, 217, 213, 188, 8, 175, 238, 169, 147, 86, 159, 112, 79, 174, 138, 27, 242, 6, 92, 21, 55, 87, 197, 173, 177, 71, 36, 156, 79, 183, 128, 86, 172, 235, 90, 70, 173, 125, 139, 171, 127, 4, 197, 179, 26, 35, 119, 143, 184, 215, 82, 87, 90, 160, 21, 235, 72, 151, 106, 239, 193, 210, 37, 151, 9, 254, 199, 64, 107, 197, 179, 178, 37, 50, 24, 64, 231, 178, 22, 235, 226, 133, 101, 226, 198, 135, 79, 234, 14, 92, 63, 211, 42, 109, 23, 161, 147, 197, 62, 241, 232, 249, 91, 182, 101, 173, 175, 74, 194, 93, 251, 45, 220, 248, 128, 176, 161, 59, 185, 113, 129, 169, 214, 168, 240, 206, 14, 106, 141, 14, 11, 175, 165, 53, 54, 52, 195, 26, 21, 18, 107, 124, 240, 163, 181, 158, 67, 137, 53, 78, 160, 196, 26, 35, 18, 107, 132, 96, 141, 142, 196, 26, 33, 110, 53, 42, 104, 203, 80, 67, 4, 38, 128, 64, 49, 117, 219, 216, 80, 233, 40, 220, 26, 239, 52, 219, 248, 96, 204, 118, 170, 211, 8, 73, 117, 26, 21, 154, 23, 167, 165, 105, 100, 84, 212, 137, 176, 52, 141, 139, 138, 54, 218, 104, 105, 26, 27, 21, 117, 208, 210, 52, 46, 150, 166, 81, 65, 82, 76, 163, 66, 132, 8, 80, 96, 130, 196, 52, 46, 38, 16, 193, 4, 17, 36, 166, 113, 241, 235, 59, 129, 48, 144, 52, 83, 180, 145, 65, 146, 152, 57, 180, 151, 162, 141, 12, 205, 15, 109, 52, 209, 70, 198, 195, 172, 63, 237, 68, 79, 191, 54, 46, 104, 239, 179, 125, 109, 92, 80, 184, 157, 215, 198, 197, 162, 36, 109, 157, 215, 198, 6, 132, 127, 75, 247, 124, 39, 115, 137, 182, 159, 11, 226, 240, 21, 253, 70, 5, 173, 236, 69, 188, 185, 91, 29, 252, 225, 97, 246, 93, 27, 23, 170, 50, 37, 131, 222, 181, 241, 241, 174, 141, 10, 147, 141, 80, 201, 46, 136, 55, 118, 174, 141, 13, 254, 205, 174, 162, 16, 86, 63, 137, 213, 207, 213, 115, 87, 34, 127, 9, 230, 45, 252, 220, 78, 89, 54, 231, 33, 38, 139, 31, 24, 183, 235, 90, 6, 210, 171, 82, 83, 213, 212, 169, 106, 160, 40, 233, 209, 220, 74, 132, 144, 132, 13, 7, 165, 147, 126, 87, 74, 51, 232, 170, 168, 208, 138, 109, 104, 239, 130, 138, 170, 182, 13, 99, 101, 227, 125, 199, 21, 112, 82, 166, 246, 32, 84, 251, 117, 178, 216, 145, 246, 42, 93, 235, 148, 101, 163, 80, 150, 45, 153, 74, 118, 53, 195, 189, 234, 193, 157, 146, 65, 88, 240, 14, 111, 126, 215, 212, 18, 97, 196, 211, 175, 157, 239, 15, 47, 185, 161, 201, 87, 4, 121, 215, 199, 205, 48, 20, 37, 173, 149, 104, 130, 54, 46, 152, 111, 187, 92, 190, 217, 105, 163, 163, 97, 173, 116, 60, 160, 107, 25, 212, 246, 1, 105, 202, 229, 208, 3, 23, 13, 169, 78, 27, 29, 212, 74, 176, 161, 191, 77, 105, 157, 240, 195, 215, 202, 132, 88, 54, 109, 92, 224, 154, 210, 121, 174, 236, 116, 234, 168, 105, 187, 54, 251, 31, 60, 48, 94, 144, 78, 144, 97, 162, 106, 98, 245, 67, 109, 155, 109, 70, 250, 204, 158, 153, 54, 58, 52, 78, 91, 89, 166, 141, 141, 84, 202, 180, 145, 161, 178, 253, 201, 150, 244, 5, 137, 95, 63, 151, 35, 73, 39, 123, 156, 212, 86, 170, 180, 85, 237, 107, 188, 211, 69, 56, 159, 236, 209, 30, 107, 205, 174, 68, 234, 214, 53, 109, 149, 74, 135, 214, 210, 244, 64, 211, 184, 223, 31, 232, 122, 205, 64, 223, 202, 137, 239, 66, 128, 43, 245, 71, 0, 87, 237, 25, 192, 39, 84, 91, 164, 107, 201, 31, 128, 164, 237, 74, 128, 54, 201, 22, 253, 75, 223, 172, 0, 239, 92, 139, 21, 226, 134, 190, 237, 106, 96, 177, 119, 24, 211, 56, 36, 92, 159, 219, 51, 51, 16, 46, 105, 187, 22, 108, 132, 153, 66, 42, 18, 171, 135, 75, 82, 123, 105, 64, 7, 46, 153, 54, 58, 112, 179, 178, 2, 161, 3, 226, 113, 9, 179, 243, 120, 10, 240, 228, 82, 165, 149, 92, 218, 8, 81, 182, 169, 101, 91, 246, 150, 132, 126, 42, 108, 88, 57, 105, 253, 182, 218, 184, 224, 12, 244, 223, 178, 205, 13, 60, 72, 58, 25, 132, 146, 237, 168, 72, 172, 30, 222, 180, 85, 169, 142, 186, 199, 209, 70, 7, 140, 151, 115, 168, 8, 173, 255, 153, 220, 65, 69, 208, 182, 235, 161, 34, 52, 119, 43, 90, 141, 54, 66, 86, 163, 141, 10, 30, 105, 180, 241, 209, 84, 194, 255, 244, 4, 54, 208, 230, 132, 32, 207, 185, 202, 130, 101, 167, 171, 120, 147, 139, 129, 0, 225, 159, 106, 63, 114, 149, 135, 175, 63, 43, 91, 162, 247, 68, 174, 210, 180, 97, 180, 122, 167, 171, 104, 163, 141, 144, 5, 19, 205, 15, 215, 253, 86, 197, 105, 219, 67, 14, 168, 54, 58, 214, 254, 107, 248, 125, 206, 144, 224, 200, 241, 93, 203, 115, 11, 158, 70, 27, 29, 108, 131, 154, 54, 143, 74, 80, 163, 141, 11, 248, 98, 126, 70, 27, 25, 143, 202, 91, 140, 54, 50, 84, 120, 169, 52, 252, 81, 73, 163, 240, 3, 195, 175, 13, 4, 6, 73, 23, 163, 141, 16, 79, 218, 197, 14, 53, 62, 36, 163, 141, 10, 171, 80, 3, 163, 141, 142, 117, 217, 16, 163, 141, 12, 70, 27, 21, 104, 122, 233, 149, 167, 218, 235, 111, 234, 45, 151, 203, 38, 221, 181, 109, 147, 158, 77, 186, 163, 242, 212, 122, 236, 81, 121, 202, 185, 93, 12, 170, 184, 43, 83, 231, 23, 52, 188, 22, 112, 208, 252, 219, 152, 33, 73, 98, 133, 38, 42, 139, 57, 57, 26, 167, 84, 136, 46, 13, 148, 58, 233, 115, 89, 224, 252, 147, 88, 151, 168, 242, 41, 81, 163, 242, 148, 54, 46, 52, 123, 67, 52, 84, 86, 110, 218, 229, 216, 250, 131, 181, 50, 33, 138, 166, 255, 185, 24, 135, 180, 50, 33, 247, 132, 15, 157, 239, 74, 27, 23, 187, 18, 106, 36, 86, 218, 184, 32, 73, 188, 148, 54, 46, 36, 137, 153, 36, 241, 98, 166, 173, 195, 215, 161, 223, 223, 74, 200, 119, 149, 54, 46, 40, 125, 84, 105, 227, 226, 83, 106, 163, 10, 47, 74, 27, 33, 254, 218, 73, 29, 125, 74, 165, 141, 14, 20, 221, 201, 251, 174, 110, 132, 112, 210, 39, 229, 33, 181, 199, 17, 3, 132, 17, 169, 61, 142, 22, 37, 59, 105, 35, 164, 105, 218, 200, 96, 45, 39, 109, 100, 232, 101, 39, 105, 227, 66, 87, 74, 116, 72, 152, 160, 199, 139, 54, 46, 220, 115, 209, 70, 134, 214, 73, 106, 35, 195, 171, 58, 142, 24, 255, 243, 130, 176, 129, 243, 233, 86, 106, 227, 3, 91, 11, 77, 219, 214, 73, 65, 191, 18, 200, 175, 100, 127, 31, 210, 182, 75, 219, 46, 213, 118, 45, 100, 225, 213, 160, 94, 165, 82, 27, 33, 46, 187, 129, 31, 45, 74, 73, 237, 127, 96, 249, 56, 60, 26, 137, 91, 141, 149, 90, 154, 42, 58, 105, 138, 84, 106, 67, 72, 218, 115, 212, 73, 153, 28, 238, 161, 212, 75, 151, 92, 214, 74, 164, 20, 92, 246, 123, 229, 169, 201, 126, 182, 93, 141, 251, 217, 211, 178, 75, 226, 170, 154, 86, 52, 232, 242, 254, 241, 227, 252, 82, 156, 95, 138, 55, 117, 52, 97, 231, 247, 189, 19, 138, 238, 100, 223, 99, 180, 245, 243, 93, 253, 69, 44, 74, 153, 240, 23, 161, 254, 40, 212, 223, 254, 122, 175, 141, 90, 10, 90, 224, 160, 58, 117, 81, 109, 230, 32, 9, 183, 191, 152, 127, 241, 227, 97, 246, 61, 249, 159, 182, 223, 128, 237, 71, 176, 85, 166, 206, 68, 69, 223, 245, 39, 26, 59, 78, 151, 122, 147, 255, 208, 228, 47, 249, 159, 223, 30, 95, 251, 79, 155, 19, 162, 232, 78, 208, 90, 82, 221, 82, 220, 82, 118, 37, 52, 241, 230, 132, 154, 137, 55, 19, 111, 188, 175, 218, 215, 232, 122, 222, 117, 61, 207, 251, 227, 182, 253, 18, 102, 7, 105, 147, 205, 19, 170, 184, 45, 229, 5, 65, 60, 146, 180, 239, 21, 75, 65, 78, 63, 237, 231, 123, 231, 123, 91, 231, 218, 118, 73, 58, 157, 71, 84, 83, 8, 2, 105, 20, 86, 170, 118, 57, 211, 10, 8, 211, 229, 152, 42, 78, 57, 105, 153, 144, 246, 251, 108, 205, 122, 46, 170, 214, 27, 154, 25, 162, 176, 227, 20, 218, 233, 56, 3, 10, 171, 116, 24, 43, 244, 190, 171, 61, 158, 12, 124, 210, 165, 238, 168, 115, 105, 240, 247, 92, 72, 210, 118, 33, 199, 211, 97, 172, 254, 113, 55, 212, 91, 39, 20, 43, 117, 178, 111, 165, 98, 198, 224, 129, 89, 164, 180, 247, 77, 208, 70, 107, 49, 179, 6, 79, 46, 109, 70, 59, 155, 169, 232, 98, 180, 223, 147, 95, 162, 242, 148, 246, 218, 212, 56, 105, 107, 127, 182, 123, 220, 13, 69, 79, 208, 213, 52, 252, 200, 113, 171, 179, 99, 229, 55, 63, 120, 4, 194, 179, 158, 151, 131, 72, 218, 46, 164, 54, 151, 139, 216, 181, 218, 164, 115, 247, 77, 219, 86, 213, 236, 208, 212, 161, 160, 103, 53, 110, 93, 216, 155, 80, 197, 238, 136, 155, 47, 249, 13, 22, 165, 60, 59, 142, 40, 186, 19, 6, 172, 106, 39, 252, 73, 39, 15, 212, 190, 215, 120, 155, 182, 238, 121, 7, 158, 212, 180, 211, 181, 149, 164, 236, 47, 64, 3, 173, 110, 41, 110, 41, 205, 196, 189, 153, 56, 243, 242, 52, 191, 3, 157, 139, 106, 143, 37, 92, 182, 5, 90, 255, 243, 129, 118, 58, 190, 228, 163, 197, 223, 148, 53, 90, 0, 167, 232, 78, 82, 59, 145, 50, 233, 223, 249, 78, 161, 147, 93, 236, 29, 7, 142, 167, 210, 86, 154, 173, 255, 44, 205, 4, 53, 51, 120, 77, 25, 114, 207, 49, 163, 156, 75, 167, 77, 58, 94, 168, 233, 54, 55, 80, 204, 86, 42, 102, 18, 95, 209, 71, 186, 96, 65, 219, 116, 210, 163, 18, 138, 238, 4, 105, 39, 37, 145, 2, 84, 146, 148, 68, 78, 85, 210, 252, 153, 86, 181, 109, 205, 139, 54, 114, 46, 219, 34, 231, 18, 181, 93, 128, 49, 87, 48, 230, 10, 212, 210, 33, 109, 146, 49, 224, 184, 147, 203, 165, 232, 78, 22, 123, 39, 229, 162, 84, 25, 148, 246, 93, 58, 13, 124, 58, 9, 41, 125, 102, 27, 244, 218, 60, 160, 105, 39, 173, 142, 120, 177, 54, 238, 120, 46, 102, 91, 41, 186, 235, 18, 57, 233, 149, 249, 138, 54, 164, 124, 97, 36, 36, 109, 23, 90, 155, 140, 146, 61, 105, 250, 60, 193, 76, 91, 164, 105, 39, 234, 224, 83, 53, 240, 8, 226, 119, 79, 127, 202, 87, 197, 201, 250, 0, 205, 50, 109, 34, 109, 123, 140, 113, 98, 64, 49, 106, 169, 43, 45, 240, 43, 65, 223, 233, 164, 212, 178, 151, 9, 199, 115, 57, 127, 230, 229, 89, 140, 43, 71, 15, 47, 206, 191, 68, 206, 249, 139, 40, 85, 199, 1, 179, 191, 94, 196, 132, 39, 204, 170, 118, 18, 177, 82, 49, 219, 202, 178, 166, 140, 43, 26, 228, 42, 101, 253, 60, 149, 53, 168, 98, 3, 216, 231, 73, 169, 196, 147, 173, 230, 201, 229, 144, 238, 63, 47, 222, 207, 138, 93, 153, 120, 53, 126, 93, 42, 113, 6, 75, 243, 114, 36, 193, 4, 53, 86, 42, 81, 187, 35, 93, 75, 170, 100, 3, 168, 100, 199, 195, 172, 164, 237, 90, 119, 187, 150, 34, 215, 182, 203, 117, 165, 39, 41, 179, 139, 129, 215, 197, 164, 54, 14, 79, 69, 46, 136, 156, 52, 150, 120, 196, 61, 194, 154, 153, 198, 30, 65, 141, 61, 194, 141, 61, 194, 58, 146, 168, 249, 87, 194, 236, 32, 165, 223, 30, 51, 228, 187, 64, 233, 103, 210, 118, 170, 144, 239, 50, 214, 183, 149, 48, 59, 136, 1, 198, 169, 245, 219, 62, 215, 154, 137, 75, 152, 29, 180, 64, 147, 173, 80, 182, 92, 213, 94, 101, 155, 135, 196, 155, 182, 206, 192, 181, 73, 86, 225, 229, 157, 102, 87, 235, 90, 217, 180, 54, 201, 214, 113, 39, 164, 77, 50, 8, 109, 146, 65, 152, 237, 165, 118, 213, 115, 65, 141, 211, 62, 124, 69, 219, 4, 32, 88, 9, 179, 131, 26, 222, 147, 31, 61, 59, 235, 18, 61, 59, 18, 102, 167, 213, 85, 51, 5, 61, 56, 205, 58, 175, 108, 169, 3, 97, 233, 176, 87, 219, 13, 63, 185, 144, 218, 110, 36, 76, 144, 54, 3, 215, 166, 121, 206, 218, 64, 68, 144, 77, 54, 140, 167, 162, 226, 49, 77, 181, 147, 163, 181, 94, 4, 99, 133, 24, 119, 133, 106, 51, 16, 150, 205, 154, 153, 198, 200, 95, 98, 7, 73, 226, 133, 252, 37, 94, 220, 46, 9, 157, 48, 67, 110, 151, 218, 110, 80, 133, 151, 138, 46, 137, 95, 9, 106, 114, 253, 50, 141, 125, 234, 185, 104, 47, 227, 236, 116, 45, 227, 160, 107, 25, 231, 83, 25, 125, 19, 58, 25, 122, 79, 70, 226, 93, 98, 105, 101, 93, 211, 166, 147, 39, 87, 235, 132, 39, 158, 78, 213, 30, 47, 168, 185, 91, 155, 230, 17, 196, 143, 30, 79, 133, 112, 220, 9, 61, 158, 218, 64, 27, 87, 56, 110, 181, 150, 108, 154, 108, 215, 109, 254, 148, 12, 98, 204, 152, 73, 18, 43, 199, 3, 13, 92, 221, 243, 142, 219, 41, 160, 91, 231, 251, 148, 168, 105, 147, 88, 53, 109, 18, 67, 156, 244, 184, 193, 187, 126, 83, 12, 180, 113, 5, 133, 4, 139, 189, 131, 84, 83, 13, 84, 83, 206, 36, 2, 17, 128, 0, 77, 246, 65, 83, 46, 231, 203, 236, 68, 41, 158, 5, 202, 246, 245, 83, 233, 167, 250, 84, 249, 169, 22, 80, 219, 13, 202, 79, 21, 1, 117, 46, 13, 124, 149, 191, 102, 239, 55, 241, 4, 49, 241, 212, 224, 170, 51, 161, 95, 165, 205, 104, 35, 253, 212, 134, 112, 239, 219, 107, 110, 188, 141, 182, 3, 77, 46, 6, 61, 253, 237, 49, 133, 27, 154, 104, 20, 86, 223, 158, 51, 243, 9, 103, 230, 252, 232, 113, 156, 26, 168, 90, 255, 199, 146, 180, 43, 53, 70, 139, 57, 249, 55, 245, 198, 9, 173, 132, 33, 175, 41, 251, 138, 126, 171, 240, 178, 152, 31, 125, 227, 244, 208, 244, 155, 55, 94, 111, 202, 86, 161, 214, 182, 249, 141, 211, 2, 172, 151, 105, 19, 251, 175, 76, 123, 20, 173, 206, 142, 121, 35, 7, 235, 49, 205, 139, 155, 221, 229, 90, 17, 84, 113, 82, 30, 129, 240, 73, 25, 70, 145, 170, 245, 111, 186, 171, 129, 107, 219, 133, 28, 203, 149, 58, 23, 212, 180, 213, 90, 7, 17, 144, 71, 190, 211, 113, 187, 24, 164, 250, 225, 89, 218, 118, 41, 219, 71, 13, 28, 94, 83, 134, 90, 155, 126, 75, 115, 132, 1, 124, 69, 27, 210, 181, 228, 127, 235, 202, 87, 165, 184, 55, 78, 219, 180, 108, 253, 84, 205, 170, 228, 213, 158, 54, 51, 186, 72, 52, 109, 215, 243, 142, 38, 128, 64, 61, 23, 85, 156, 58, 151, 6, 173, 180, 170, 181, 111, 97, 160, 243, 115, 2, 73, 237, 252, 138, 62, 210, 138, 245, 6, 15, 82, 123, 252, 241, 253, 255, 150, 215, 148, 161, 220, 94, 144, 219, 74, 123, 41, 218, 17, 206, 73, 120, 227, 133, 208, 79, 182, 20, 206, 51, 51, 71, 146, 182, 75, 0, 223, 186, 30, 19, 13, 180, 173, 44, 67, 173, 170, 41, 242, 198, 74, 61, 160, 41, 45, 240, 64, 0, 65, 162, 227, 83, 106, 59, 41, 181, 177, 17, 65, 27, 21, 232, 90, 82, 27, 33, 141, 14, 143, 32, 70, 53, 50, 104, 197, 54, 110, 153, 16, 163, 26, 33, 109, 153, 212, 200, 248, 85, 154, 26, 25, 222, 119, 165, 198, 135, 212, 216, 80, 109, 213, 70, 202, 246, 81, 106, 116, 240, 37, 31, 165, 198, 197, 63, 86, 183, 20, 71, 169, 241, 225, 78, 223, 81, 106, 100, 164, 198, 6, 210, 138, 117, 109, 148, 26, 37, 26, 47, 74, 141, 13, 169, 241, 145, 26, 31, 94, 83, 134, 82, 227, 66, 251, 189, 107, 131, 82, 163, 131, 53, 51, 40, 117, 106, 74, 182, 66, 169, 177, 209, 44, 211, 32, 212, 93, 174, 197, 170, 50, 121, 167, 106, 186, 50, 161, 212, 248, 208, 79, 182, 45, 81, 106, 116, 164, 198, 0, 56, 254, 150, 198, 5, 74, 54, 58, 30, 197, 11, 162, 100, 35, 195, 35, 168, 233, 36, 27, 25, 173, 248, 208, 181, 108, 69, 23, 131, 90, 23, 232, 103, 35, 68, 210, 9, 250, 108, 92, 164, 227, 217, 184, 176, 52, 29, 151, 141, 11, 39, 61, 126, 199, 55, 187, 227, 207, 61, 180, 105, 101, 207, 114, 46, 187, 105, 217, 8, 129, 84, 212, 89, 107, 25, 198, 142, 180, 159, 140, 253, 43, 160, 207, 111, 66, 5, 30, 92, 53, 83, 32, 26, 60, 210, 96, 250, 251, 128, 48, 86, 45, 27, 25, 92, 69, 85, 203, 198, 133, 106, 217, 232, 200, 198, 135, 166, 151, 238, 248, 212, 94, 68, 37, 106, 72, 197, 178, 113, 33, 213, 194, 178, 145, 193, 35, 175, 177, 116, 35, 132, 171, 228, 94, 155, 141, 17, 21, 76, 54, 42, 44, 38, 27, 21, 148, 147, 124, 49, 59, 196, 100, 35, 131, 201, 70, 5, 188, 42, 27, 33, 204, 147, 130, 218, 46, 217, 232, 136, 208, 24, 128, 198, 30, 65, 141, 14, 200, 144, 175, 76, 117, 45, 169, 32, 244, 249, 77, 104, 175, 129, 223, 4, 132, 188, 9, 216, 240, 200, 226, 183, 189, 9, 184, 144, 191, 84, 77, 240, 90, 16, 197, 90, 251, 38, 224, 194, 227, 245, 66, 146, 180, 111, 2, 54, 36, 105, 223, 33, 241, 124, 238, 180, 12, 233, 123, 208, 230, 119, 117, 82, 186, 190, 9, 232, 240, 180, 190, 9, 16, 198, 10, 81, 88, 165, 227, 168, 245, 77, 192, 7, 157, 158, 111, 2, 50, 184, 79, 64, 5, 15, 179, 62, 1, 33, 250, 38, 16, 28, 15, 61, 1, 25, 60, 50, 97, 2, 42, 180, 46, 11, 175, 9, 184, 240, 133, 35, 19, 112, 33, 50, 1, 3, 192, 139, 38, 160, 194, 162, 9, 168, 96, 2, 2, 224, 211, 235, 111, 88, 75, 29, 71, 141, 157, 127, 28, 66, 124, 85, 28, 42, 248, 218, 127, 19, 247, 207, 33, 195, 35, 168, 213, 241, 231, 176, 209, 150, 211, 239, 130, 242, 83, 57, 254, 28, 66, 120, 4, 130, 227, 207, 225, 194, 31, 61, 204, 246, 115, 232, 104, 176, 216, 59, 136, 113, 51, 72, 2, 25, 239, 218, 207, 33, 67, 191, 70, 218, 207, 97, 195, 249, 149, 250, 142, 178, 191, 162, 15, 104, 115, 66, 14, 216, 72, 247, 28, 42, 168, 226, 244, 180, 231, 144, 65, 97, 213, 150, 242, 208, 181, 164, 227, 207, 161, 181, 94, 99, 233, 68, 87, 43, 163, 202, 241, 153, 208, 90, 207, 33, 35, 37, 207, 161, 130, 100, 37, 197, 109, 191, 163, 230, 185, 205, 5, 225, 80, 201, 207, 104, 149, 180, 93, 168, 121, 14, 29, 254, 104, 238, 214, 166, 77, 243, 28, 66, 188, 255, 19, 53, 207, 97, 163, 121, 14, 21, 120, 4, 97, 99, 121, 109, 121, 14, 33, 239, 250, 72, 169, 227, 228, 237, 53, 224, 182, 145, 118, 45, 207, 161, 195, 195, 180, 33, 168, 246, 187, 195, 135, 75, 214, 208, 149, 137, 23, 66, 84, 251, 145, 187, 195, 197, 251, 46, 228, 14, 23, 221, 14, 21, 104, 239, 155, 224, 104, 218, 66, 76, 154, 67, 67, 219, 116, 210, 227, 233, 215, 134, 224, 217, 241, 166, 218, 201, 21, 128, 34, 16, 64, 37, 185, 24, 8, 116, 192, 27, 13, 220, 23, 167, 5, 60, 194, 188, 133, 159, 159, 219, 161, 131, 162, 59, 129, 240, 93, 13, 28, 44, 85, 28, 225, 146, 61, 42, 89, 175, 255, 185, 182, 79, 243, 251, 58, 19, 217, 44, 104, 246, 126, 201, 113, 43, 6, 174, 90, 50, 70, 177, 228, 90, 156, 80, 115, 247, 50, 117, 9, 199, 237, 156, 179, 227, 118, 184, 104, 87, 209, 6, 111, 126, 36, 34, 16, 62, 160, 166, 45, 133, 126, 54, 233, 184, 29, 130, 64, 135, 234, 172, 96, 248, 187, 103, 185, 68, 239, 222, 49, 110, 135, 12, 15, 179, 107, 101, 66, 15, 179, 14, 79, 75, 244, 48, 235, 44, 120, 145, 234, 92, 148, 36, 229, 2, 1, 194, 3, 8, 142, 167, 3, 65, 125, 159, 150, 16, 212, 23, 241, 79, 252, 99, 101, 251, 235, 95, 125, 229, 190, 196, 211, 255, 244, 107, 47, 240, 85, 218, 79, 223, 132, 6, 157, 172, 247, 75, 218, 200, 29, 183, 107, 254, 151, 180, 162, 104, 241, 130, 135, 89, 85, 220, 36, 222, 105, 118, 49, 109, 157, 148, 10, 81, 72, 125, 89, 219, 116, 28, 92, 146, 114, 137, 88, 43, 147, 68, 171, 36, 181, 151, 7, 253, 92, 104, 173, 68, 13, 112, 225, 159, 239, 40, 53, 200, 159, 58, 175, 140, 219, 225, 4, 227, 118, 248, 104, 26, 225, 118, 200, 160, 44, 27, 250, 164, 17, 110, 247, 208, 185, 32, 6, 22, 164, 233, 41, 110, 135, 15, 14, 26, 67, 120, 211, 137, 36, 105, 191, 162, 141, 194, 223, 183, 226, 48, 129, 43, 122, 224, 162, 225, 133, 18, 183, 67, 198, 243, 194, 237, 144, 97, 53, 16, 116, 225, 118, 200, 208, 207, 201, 194, 35, 159, 82, 59, 39, 25, 65, 105, 31, 24, 43, 148, 246, 145, 76, 157, 228, 72, 130, 249, 182, 67, 136, 71, 244, 233, 155, 240, 252, 54, 111, 59, 124, 136, 48, 56, 133, 174, 37, 27, 190, 206, 163, 111, 219, 140, 79, 169, 221, 180, 133, 55, 78, 235, 168, 232, 98, 148, 109, 59, 108, 112, 167, 100, 16, 86, 78, 180, 98, 221, 177, 43, 61, 36, 105, 223, 4, 103, 232, 81, 182, 223, 78, 67, 115, 183, 230, 167, 122, 84, 120, 121, 30, 30, 72, 165, 33, 17, 161, 191, 116, 226, 12, 188, 98, 91, 54, 205, 3, 200, 73, 70, 154, 29, 49, 80, 81, 151, 20, 223, 118, 185, 62, 168, 78, 213, 242, 29, 53, 203, 52, 118, 32, 73, 234, 36, 215, 127, 22, 212, 186, 255, 218, 14, 29, 190, 169, 107, 59, 92, 168, 226, 166, 237, 208, 1, 169, 166, 78, 219, 33, 68, 37, 47, 109, 135, 12, 22, 29, 152, 67, 74, 27, 33, 218, 174, 29, 50, 124, 106, 155, 180, 29, 50, 156, 38, 109, 135, 14, 10, 33, 220, 227, 110, 80, 203, 254, 6, 95, 209, 111, 14, 13, 159, 82, 219, 33, 131, 227, 207, 33, 109, 135, 12, 143, 52, 109, 42, 239, 28, 54, 158, 206, 94, 118, 245, 59, 135, 20, 12, 183, 115, 184, 224, 75, 21, 179, 93, 28, 116, 45, 195, 178, 155, 92, 229, 64, 99, 95, 245, 92, 4, 192, 96, 165, 39, 234, 1, 124, 229, 1, 109, 78, 232, 65, 155, 86, 38, 129, 98, 143, 6, 141, 61, 2, 81, 109, 25, 39, 189, 50, 13, 14, 218, 16, 111, 188, 159, 116, 66, 63, 215, 226, 7, 95, 251, 111, 193, 154, 224, 139, 82, 144, 42, 110, 12, 48, 64, 173, 239, 82, 53, 224, 146, 45, 176, 40, 39, 61, 118, 184, 208, 148, 253, 236, 112, 33, 73, 233, 158, 29, 46, 116, 217, 78, 46, 233, 100, 239, 172, 153, 225, 109, 201, 212, 218, 183, 188, 179, 91, 236, 157, 5, 139, 189, 131, 26, 118, 60, 130, 26, 118, 28, 169, 255, 44, 218, 141, 118, 243, 238, 184, 236, 6, 82, 81, 213, 182, 98, 173, 165, 76, 180, 101, 147, 149, 19, 138, 213, 175, 146, 223, 30, 7, 110, 38, 77, 219, 111, 246, 135, 239, 100, 222, 57, 65, 186, 28, 219, 103, 79, 87, 38, 125, 98, 125, 251, 131, 244, 148, 54, 211, 230, 175, 184, 7, 73, 219, 133, 158, 150, 200, 61, 87, 66, 172, 158, 186, 123, 26, 76, 154, 162, 87, 215, 174, 44, 163, 237, 26, 104, 202, 229, 24, 72, 82, 123, 65, 218, 164, 83, 45, 157, 111, 118, 90, 39, 188, 0, 131, 231, 55, 165, 227, 6, 86, 191, 5, 170, 56, 109, 123, 222, 180, 101, 251, 5, 96, 224, 201, 229, 124, 21, 210, 138, 109, 15, 164, 90, 251, 169, 61, 78, 177, 50, 241, 26, 128, 11, 128, 101, 167, 91, 224, 160, 49, 131, 116, 189, 78, 167, 105, 188, 190, 169, 90, 7, 149, 156, 188, 38, 150, 92, 30, 113, 52, 147, 182, 221, 236, 22, 120, 245, 180, 202, 178, 153, 71, 37, 200, 61, 45, 131, 197, 222, 201, 165, 233, 138, 58, 15, 222, 234, 150, 58, 217, 48, 104, 102, 246, 33, 166, 239, 143, 163, 111, 14, 180, 117, 126, 41, 20, 186, 150, 245, 157, 32, 127, 137, 153, 202, 50, 200, 155, 183, 84, 116, 57, 3, 93, 175, 145, 106, 250, 21, 135, 73, 211, 199, 83, 39, 28, 33, 93, 203, 99, 2, 40, 245, 215, 158, 170, 231, 29, 211, 207, 180, 203, 61, 181, 128, 3, 213, 153, 124, 213, 62, 200, 85, 202, 16, 227, 247, 71, 193, 238, 9, 65, 190, 162, 205, 61, 33, 247, 180, 160, 117, 210, 24, 180, 101, 16, 75, 211, 186, 92, 63, 151, 41, 233, 162, 205, 128, 98, 182, 192, 66, 89, 30, 145, 142, 91, 137, 42, 234, 52, 120, 178, 27, 212, 188, 56, 237, 74, 15, 7, 76, 23, 137, 103, 238, 247, 87, 119, 135, 103, 57, 215, 144, 90, 78, 84, 162, 5, 220, 211, 59, 175, 124, 103, 135, 15, 77, 219, 198, 251, 235, 236, 212, 217, 97, 195, 217, 161, 130, 214, 214, 50, 61, 252, 155, 29, 46, 180, 170, 182, 204, 55, 59, 116, 232, 155, 160, 149, 223, 172, 12, 114, 232, 160, 212, 31, 250, 102, 135, 141, 86, 127, 19, 237, 84, 16, 131, 135, 167, 95, 219, 129, 162, 105, 171, 248, 129, 174, 180, 238, 216, 33, 163, 117, 153, 85, 204, 144, 86, 172, 163, 74, 50, 212, 234, 28, 59, 116, 160, 206, 14, 237, 51, 115, 236, 176, 161, 236, 212, 241, 63, 139, 29, 50, 96, 235, 248, 179, 216, 33, 195, 181, 237, 250, 101, 8, 39, 154, 182, 206, 237, 74, 8, 33, 148, 58, 190, 139, 29, 50, 116, 45, 131, 142, 86, 138, 238, 4, 49, 220, 184, 89, 8, 135, 111, 203, 14, 27, 116, 45, 195, 14, 25, 34, 17, 216, 185, 230, 80, 162, 237, 130, 16, 178, 236, 170, 224, 6, 121, 120, 164, 105, 14, 23, 154, 195, 0, 84, 152, 67, 5, 191, 141, 153, 63, 142, 34, 48, 101, 17, 152, 67, 7, 253, 124, 238, 134, 23, 138, 192, 28, 54, 68, 96, 14, 29, 141, 43, 137, 34, 48, 135, 12, 108, 52, 188, 28, 205, 221, 138, 16, 199, 203, 161, 194, 251, 46, 135, 11, 173, 21, 93, 14, 25, 42, 204, 104, 47, 35, 161, 205, 15, 236, 45, 227, 118, 18, 154, 64, 7, 99, 238, 39, 151, 67, 70, 179, 247, 45, 151, 67, 8, 109, 187, 158, 197, 14, 241, 163, 206, 150, 203, 161, 3, 181, 185, 92, 83, 46, 135, 13, 143, 172, 196, 225, 2, 51, 109, 27, 137, 195, 133, 123, 168, 145, 56, 100, 104, 36, 14, 27, 205, 58, 152, 198, 9, 53, 18, 135, 12, 9, 120, 146, 56, 92, 240, 8, 4, 16, 120, 146, 56, 100, 48, 237, 202, 58, 100, 240, 8, 132, 93, 56, 191, 204, 25, 102, 21, 90, 90, 89, 135, 142, 108, 155, 124, 29, 46, 92, 63, 123, 29, 46, 250, 233, 191, 186, 117, 216, 224, 69, 234, 214, 225, 226, 189, 173, 195, 5, 87, 239, 20, 251, 235, 177, 8, 247, 239, 52, 82, 229, 226, 244, 248, 102, 247, 41, 251, 125, 73, 196, 109, 29, 54, 224, 182, 14, 21, 28, 116, 37, 109, 29, 50, 228, 182, 117, 184, 208, 180, 117, 168, 224, 17, 102, 43, 186, 14, 25, 218, 164, 63, 181, 14, 25, 170, 253, 106, 29, 46, 214, 90, 70, 251, 125, 90, 199, 56, 173, 195, 6, 167, 117, 232, 120, 22, 36, 73, 235, 176, 33, 211, 58, 84, 112, 28, 58, 90, 255, 83, 33, 231, 56, 148, 104, 118, 156, 179, 227, 208, 65, 27, 59, 14, 23, 42, 219, 148, 29, 135, 139, 95, 251, 22, 109, 135, 36, 60, 194, 248, 91, 58, 14, 27, 238, 233, 26, 135, 12, 174, 113, 216, 136, 176, 38, 56, 106, 28, 46, 22, 167, 198, 161, 3, 53, 14, 33, 26, 135, 14, 212, 56, 108, 160, 198, 97, 99, 2, 223, 22, 53, 14, 23, 141, 195, 134, 195, 134, 123, 104, 28, 82, 52, 14, 3, 80, 161, 14, 21, 72, 90, 54, 196, 243, 219, 233, 254, 233, 231, 98, 84, 33, 137, 180, 142, 147, 111, 4, 130, 178, 71, 225, 134, 52, 181, 100, 205, 76, 171, 195, 135, 206, 37, 66, 181, 116, 84, 155, 65, 159, 20, 194, 37, 204, 78, 5, 92, 210, 201, 16, 211, 234, 208, 241, 164, 86, 135, 11, 30, 113, 234, 112, 65, 253, 177, 243, 77, 29, 54, 90, 91, 83, 135, 12, 170, 169, 67, 5, 166, 14, 21, 120, 164, 81, 135, 11, 106, 81, 171, 58, 92, 168, 58, 124, 48, 202, 97, 227, 125, 21, 114, 120, 132, 81, 14, 23, 222, 147, 81, 14, 25, 150, 93, 136, 81, 14, 23, 159, 28, 58, 24, 43, 20, 225, 118, 149, 197, 225, 227, 27, 34, 48, 74, 178, 56, 100, 144, 40, 71, 239, 218, 104, 165, 123, 210, 61, 233, 112, 225, 47, 29, 66, 86, 78, 156, 119, 38, 130, 243, 233, 112, 193, 35, 16, 22, 94, 13, 226, 167, 208, 212, 143, 189, 194, 237, 168, 172, 115, 67, 59, 207, 200, 254, 138, 42, 203, 246, 21, 69, 11, 212, 51, 53, 156, 79, 135, 14, 231, 211, 161, 130, 147, 62, 29, 54, 168, 102, 202, 67, 143, 19, 114, 79, 135, 19, 173, 255, 75, 121, 136, 166, 18, 254, 167, 209, 207, 126, 23, 64, 132, 149, 137, 151, 131, 243, 47, 93, 170, 245, 148, 72, 167, 46, 200, 253, 59, 20, 17, 104, 16, 1, 2, 6, 206, 191, 228, 5, 17, 32, 36, 204, 139, 166, 100, 34, 24, 191, 191, 132, 240, 65, 61, 211, 202, 228, 43, 147, 167, 195, 135, 71, 30, 93, 140, 109, 99, 109, 63, 198, 178, 171, 37, 139, 249, 81, 183, 254, 39, 67, 61, 97, 241, 232, 98, 52, 246, 136, 59, 191, 20, 36, 65, 58, 146, 32, 66, 181, 31, 69, 16, 64, 211, 182, 1, 9, 24, 58, 245, 249, 109, 79, 187, 249, 211, 126, 62, 197, 171, 167, 110, 125, 151, 42, 145, 51, 168, 129, 55, 205, 161, 40, 238, 233, 148, 101, 67, 141, 61, 194, 64, 89, 54, 148, 182, 149, 189, 230, 140, 17, 209, 246, 115, 61, 42, 105, 52, 246, 200, 183, 6, 196, 45, 117, 22, 94, 142, 213, 15, 45, 207, 89, 253, 16, 59, 237, 5, 202, 178, 161, 181, 30, 243, 224, 224, 248, 174, 166, 169, 67, 219, 100, 172, 24, 102, 29, 219, 15, 229, 167, 114, 72, 187, 152, 198, 205, 235, 241, 21, 85, 156, 22, 171, 64, 76, 124, 99, 134, 45, 18, 205, 206, 63, 8, 54, 248, 194, 215, 213, 121, 124, 83, 135, 95, 228, 82, 61, 19, 98, 30, 113, 64, 160, 196, 42, 168, 119, 186, 116, 233, 176, 241, 154, 150, 14, 23, 88, 146, 14, 21, 254, 39, 48, 196, 78, 163, 249, 19, 29, 84, 211, 86, 155, 116, 216, 224, 208, 241, 78, 179, 141, 84, 58, 108, 168, 116, 168, 64, 61, 130, 86, 63, 8, 15, 179, 13, 156, 207, 8, 199, 211, 65, 16, 92, 120, 4, 105, 74, 135, 139, 148, 14, 33, 41, 29, 62, 104, 37, 33, 38, 54, 161, 7, 2, 8, 210, 33, 99, 173, 100, 90, 63, 41, 200, 225, 163, 153, 65, 191, 73, 65, 14, 29, 79, 63, 114, 184, 192, 154, 25, 124, 244, 3, 57, 116, 40, 99, 127, 109, 228, 112, 225, 112, 225, 112, 161, 110, 29, 114, 200, 224, 146, 33, 231, 112, 225, 169, 200, 133, 28, 50, 252, 34, 135, 28, 66, 158, 181, 178, 45, 131, 28, 54, 152, 89, 6, 57, 100, 120, 218, 225, 194, 117, 91, 29, 57, 41, 21, 57, 108, 104, 101, 84, 33, 135, 11, 228, 150, 166, 150, 9, 185, 212, 30, 79, 228, 176, 225, 105, 137, 28, 46, 32, 68, 235, 132, 81, 33, 181, 199, 209, 115, 255, 24, 33, 90, 159, 92, 255, 24, 25, 223, 84, 253, 99, 92, 188, 63, 70, 5, 39, 61, 70, 133, 101, 151, 123, 70, 134, 138, 51, 62, 156, 79, 231, 140, 12, 46, 155, 51, 46, 48, 46, 212, 25, 27, 207, 90, 150, 12, 114, 198, 134, 51, 6, 96, 101, 219, 102, 155, 145, 81, 209, 70, 27, 53, 205, 216, 88, 217, 86, 53, 227, 194, 83, 219, 29, 183, 91, 128, 148, 182, 170, 102, 164, 200, 86, 150, 9, 253, 46, 205, 216, 96, 81, 186, 82, 54, 35, 35, 155, 81, 129, 191, 99, 84, 240, 8, 90, 9, 65, 134, 2, 48, 71, 70, 235, 59, 198, 133, 199, 157, 99, 92, 104, 221, 126, 237, 136, 213, 207, 35, 16, 212, 61, 255, 104, 218, 166, 236, 151, 240, 35, 36, 225, 127, 32, 225, 119, 119, 141, 107, 234, 24, 23, 106, 213, 54, 117, 140, 12, 58, 217, 166, 142, 209, 193, 31, 73, 120, 104, 39, 165, 185, 129, 166, 141, 42, 78, 104, 1, 87, 247, 252, 154, 192, 143, 214, 101, 63, 191, 253, 146, 58, 240, 100, 234, 36, 7, 141, 119, 57, 150, 254, 176, 192, 131, 214, 212, 202, 9, 53, 216, 149, 144, 54, 173, 76, 155, 86, 214, 208, 216, 35, 14, 72, 154, 41, 202, 178, 153, 8, 134, 89, 72, 235, 191, 58, 98, 128, 15, 77, 29, 163, 68, 83, 199, 168, 176, 210, 49, 66, 84, 251, 209, 110, 242, 68, 204, 216, 176, 175, 169, 55, 198, 5, 55, 70, 5, 223, 30, 179, 198, 184, 88, 141, 209, 241, 172, 198, 168, 160, 108, 191, 237, 210, 198, 184, 80, 182, 143, 180, 49, 50, 180, 49, 163, 163, 49, 50, 52, 53, 70, 133, 166, 239, 187, 208, 107, 67, 141, 177, 161, 49, 58, 84, 155, 65, 146, 212, 133, 126, 43, 138, 26, 99, 132, 71, 32, 252, 50, 198, 197, 243, 142, 169, 195, 241, 84, 188, 16, 132, 83, 85, 232, 151, 49, 54, 152, 109, 26, 198, 200, 160, 255, 186, 148, 49, 50, 42, 188, 184, 100, 104, 49, 62, 44, 198, 0, 36, 181, 140, 15, 39, 189, 50, 15, 115, 24, 27, 12, 180, 57, 161, 180, 189, 36, 131, 246, 45, 80, 42, 145, 166, 101, 24, 70, 136, 214, 87, 198, 138, 145, 241, 180, 190, 9, 143, 79, 197, 8, 113, 212, 120, 23, 248, 149, 240, 39, 198, 197, 202, 79, 140, 11, 204, 174, 196, 184, 144, 24, 29, 204, 91, 24, 21, 188, 49, 8, 29, 148, 23, 70, 133, 137, 39, 196, 143, 220, 225, 201, 238, 108, 230, 109, 52, 52, 10, 123, 58, 222, 172, 26, 133, 95, 155, 1, 48, 110, 70, 162, 129, 66, 128, 240, 235, 11, 209, 10, 213, 102, 218, 123, 120, 152, 85, 237, 247, 166, 19, 241, 83, 48, 172, 21, 235, 254, 168, 196, 193, 37, 67, 207, 79, 56, 158, 78, 4, 131, 6, 165, 15, 143, 123, 32, 132, 59, 110, 135, 34, 11, 99, 67, 61, 19, 138, 44, 140, 12, 8, 22, 70, 5, 90, 177, 205, 17, 30, 206, 191, 100, 92, 144, 172, 164, 32, 79, 198, 136, 214, 137, 39, 35, 196, 147, 177, 193, 147, 209, 209, 120, 37, 200, 147, 209, 193, 147, 81, 193, 164, 233, 100, 92, 72, 79, 67, 5, 149, 134, 1, 88, 151, 78, 105, 200, 208, 20, 109, 250, 53, 104, 104, 19, 128, 96, 209, 87, 94, 195, 198, 87, 94, 67, 133, 149, 173, 236, 53, 92, 112, 47, 236, 53, 100, 80, 202, 104, 11, 226, 111, 8, 113, 10, 183, 243, 143, 181, 94, 67, 71, 74, 94, 195, 134, 229, 53, 84, 208, 36, 197, 27, 46, 120, 67, 134, 243, 134, 10, 180, 115, 37, 85, 222, 176, 209, 19, 26, 42, 112, 215, 176, 209, 176, 129, 11, 39, 173, 67, 65, 204, 173, 149, 168, 189, 126, 180, 215, 238, 124, 186, 134, 243, 233, 190, 45, 82, 237, 71, 43, 153, 107, 8, 193, 92, 195, 135, 183, 42, 115, 13, 39, 188, 241, 254, 75, 205, 12, 98, 174, 225, 2, 166, 49, 163, 109, 195, 11, 237, 106, 112, 253, 84, 238, 161, 8, 230, 26, 54, 126, 213, 75, 196, 28, 115, 13, 23, 204, 53, 84, 224, 26, 6, 160, 245, 115, 33, 213, 18, 81, 184, 97, 3, 58, 158, 231, 134, 10, 238, 243, 125, 159, 27, 54, 120, 33, 72, 82, 58, 125, 110, 248, 64, 134, 71, 32, 56, 213, 229, 220, 208, 225, 139, 110, 184, 39, 8, 75, 213, 161, 52, 147, 228, 14, 207, 232, 66, 15, 141, 196, 97, 195, 195, 236, 59, 110, 184, 208, 38, 253, 161, 119, 220, 208, 49, 65, 4, 199, 220, 112, 225, 209, 24, 228, 116, 37, 204, 13, 23, 206, 184, 161, 2, 227, 198, 184, 33, 3, 55, 100, 124, 107, 15, 141, 89, 163, 112, 147, 172, 165, 20, 138, 229, 253, 131, 197, 236, 144, 123, 166, 180, 211, 241, 111, 118, 234, 14, 212, 118, 163, 154, 186, 3, 13, 124, 179, 99, 160, 117, 109, 50, 39, 165, 238, 82, 197, 13, 31, 44, 74, 65, 30, 129, 200, 69, 55, 242, 219, 44, 40, 188, 24, 8, 77, 191, 162, 16, 156, 170, 132, 185, 194, 109, 5, 99, 177, 124, 244, 119, 161, 197, 42, 13, 21, 95, 149, 197, 236, 144, 171, 212, 118, 30, 181, 74, 154, 29, 68, 48, 65, 5, 181, 165, 188, 54, 148, 150, 189, 44, 162, 120, 47, 2, 164, 19, 163, 79, 217, 234, 174, 191, 46, 209, 243, 130, 88, 118, 163, 75, 127, 129, 147, 94, 153, 86, 247, 220, 86, 32, 87, 197, 9, 69, 248, 83, 254, 249, 15, 199, 93, 146, 114, 57, 32, 72, 167, 21, 169, 90, 251, 14, 144, 123, 186, 123, 122, 35, 61, 2, 225, 207, 130, 26, 76, 208, 246, 103, 85, 39, 47, 142, 167, 146, 104, 203, 84, 34, 165, 237, 144, 18, 38, 37, 170, 159, 119, 140, 231, 213, 60, 139, 93, 227, 84, 177, 3, 129, 243, 47, 185, 105, 235, 159, 109, 66, 146, 216, 73, 255, 26, 89, 11, 81, 139, 180, 173, 147, 146, 61, 72, 214, 91, 208, 179, 154, 134, 87, 4, 19, 84, 80, 229, 181, 93, 14, 234, 28, 73, 142, 17, 193, 4, 223, 86, 25, 104, 218, 137, 170, 141, 224, 254, 29, 135, 90, 199, 109, 69, 195, 61, 13, 132, 169, 96, 124, 241, 244, 107, 71, 112, 156, 244, 202, 56, 62, 93, 197, 31, 86, 78, 212, 155, 92, 12, 3, 93, 203, 160, 73, 211, 103, 57, 109, 180, 54, 153, 34, 85, 220, 156, 166, 138, 178, 8, 229, 159, 239, 13, 59, 244, 102, 191, 75, 34, 171, 26, 38, 170, 186, 161, 88, 114, 72, 2, 167, 13, 168, 228, 138, 136, 3, 132, 68, 242, 76, 162, 70, 73, 142, 41, 197, 148, 162, 162, 218, 0, 51, 18, 200, 97, 35, 113, 56, 26, 11, 3, 73, 22, 237, 1, 20, 128, 2, 11, 10, 197, 57, 237, 74, 18, 131, 36, 133, 138, 4, 4, 32, 3, 32, 1, 160, 0, 202, 5, 25, 88, 80, 108, 229, 116, 212, 199, 83, 154, 70, 218, 47, 23, 43, 66, 24, 212, 49, 246, 133, 246, 114, 219, 107, 207, 51, 13, 240, 61, 228, 153, 1, 201, 127, 238, 54, 60, 224, 38, 190, 105, 108, 181, 160, 198, 73, 159, 69, 4, 184, 13, 22, 57, 183, 4, 88, 110, 186, 46, 161, 202, 138, 254, 93, 79, 10, 7, 232, 252, 70, 80, 41, 74, 232, 241, 175, 54, 129, 81, 18, 103, 140, 64, 127, 208, 134, 126, 79, 65, 178, 6, 37, 173, 21, 60, 246, 46, 57, 234, 16, 109, 117, 139, 26, 251, 201, 9, 76, 180, 223, 14, 158, 143, 253, 103, 209, 7, 81, 21, 74, 161, 112, 245, 40, 202, 206, 142, 201, 43, 183, 186, 247, 75, 203, 227, 214, 192, 173, 26, 16, 118, 125, 130, 107, 130, 20, 210, 59, 137, 204, 5, 134, 71, 170, 34, 28, 77, 187, 65, 134, 153, 221, 102, 22, 137, 19, 146, 89, 121, 160, 123, 167, 193, 172, 104, 92, 112, 141, 195, 191, 248, 131, 125, 114, 117, 97, 15, 10, 79, 84, 50, 156, 242, 96, 129, 63, 17, 224, 192, 61, 90, 16, 74, 207, 236, 187, 120, 3, 89, 243, 53, 36, 135, 46, 160, 156, 126, 167, 238, 51, 156, 104, 60, 170, 181, 187, 24, 28, 99, 112, 9, 69, 163, 207, 157, 149, 60, 15, 176, 126, 109, 103, 59, 22, 163, 85, 122, 34, 169, 85, 146, 246, 67, 135, 73, 2, 13, 28, 166, 225, 80, 19, 172, 193, 210, 143, 66, 250, 129, 197, 103, 45, 249, 137, 180, 225, 3, 152, 208, 23, 7, 94, 198, 29, 226, 233, 10, 128, 67, 233, 213, 88, 106, 214, 76, 124, 235, 88, 80, 66, 124, 175, 72, 184, 233, 113, 232, 161, 22, 166, 134, 14, 92, 19, 152, 227, 22, 37, 49, 139, 110, 207, 254, 74, 86, 195, 129, 49, 58, 106, 71, 67, 137, 213, 67, 168, 111, 132, 253, 62, 134, 220, 185, 86, 83, 76, 215, 64, 164, 171, 42, 10, 217, 20, 211, 129, 219, 133, 126, 63, 37, 216, 182, 5, 184, 214, 178, 138, 69, 61, 180, 112, 181, 248, 172, 153, 181, 66, 159, 193, 83, 250, 231, 17, 80, 138, 142, 161, 163, 200, 220, 62, 178, 111, 182, 188, 43, 208, 174, 87, 60, 136, 95, 236, 46, 37, 2, 153, 30, 49, 107, 33, 69, 182, 88, 138, 67, 125, 179, 61, 23, 126, 27, 246, 111, 181, 94, 31, 241, 173, 1, 245, 32, 177, 247, 218, 85, 17, 6, 15, 158, 121, 150, 149, 55, 134, 141, 26, 93, 32, 101, 97, 62, 148, 237, 148, 191, 204, 8, 79, 6, 45, 246, 134, 59, 78, 188, 81, 109, 30, 102, 185, 92, 26, 31, 100, 85, 33, 89, 183, 64, 40, 72, 159, 102, 187, 225, 197, 209, 137, 183, 207, 71, 196, 252, 18, 8, 181, 171, 62, 2, 230, 27, 49, 241, 129, 160, 217, 204, 236, 134, 131, 184, 141, 132, 58, 34, 132, 5, 153, 234, 166, 4, 95, 196, 151, 115, 221, 72, 80, 4, 100, 212, 127, 158, 47, 26, 48, 129, 232, 9, 237, 71, 2, 139, 56, 0, 198, 96, 194, 110, 99, 56, 209, 203, 16, 178, 201, 192, 203, 206, 54, 199, 254, 135, 43, 83, 153, 187, 135, 218, 167, 74, 8, 214, 95, 44, 163, 211, 150, 81, 32, 238, 28, 240, 177, 82, 154, 0, 243, 129, 85, 224, 157, 187, 187, 216, 7, 197, 95, 21, 29, 92, 126, 75, 82, 65, 114, 98, 241, 2, 110, 25, 12, 137, 96, 156, 174, 102, 155, 41, 170, 190, 97, 59, 239, 0, 225, 22, 9, 32, 235, 26, 146, 190, 35, 45, 113, 0, 94, 132, 34, 170, 175, 22, 24, 136, 202, 193, 16, 93, 157, 170, 209, 233, 71, 153, 209, 45, 6, 217, 116, 35, 162, 52, 42, 232, 179, 232, 32, 47, 36, 227, 159, 99, 113, 95, 118, 159, 216, 203, 141, 136, 179, 248, 111, 187, 69, 198, 104, 127, 228, 217, 83, 14, 164, 121, 190, 182, 191, 114, 70, 71, 236, 180, 244, 240, 239, 87, 235, 243, 38, 163, 91, 216, 182, 125, 207, 79, 63, 27, 87, 133, 95, 64, 113, 150, 70, 195, 180, 117, 236, 242, 187, 74, 27, 236, 165, 241, 124, 175, 221, 214, 115, 133, 249, 148, 67, 4, 174, 218, 7, 207, 142, 13, 67, 43, 100, 48, 136, 206, 127, 23, 137, 1, 133, 165, 77, 75, 153, 102, 71, 127, 208, 78, 30, 248, 61, 23, 51, 235, 173, 25, 38, 129, 160, 178, 48, 249, 75, 175, 134, 45, 245, 200, 11, 218, 89, 243, 248, 86, 198, 99, 69, 122, 244, 41, 148, 71, 143, 210, 25, 68, 135, 149, 44, 48, 195, 90, 26, 65, 158, 226, 40, 56, 143, 59, 250, 64, 38, 79, 59, 93, 218, 84, 183, 57, 93, 243, 176, 187, 163, 8, 144, 147, 106, 112, 171, 37, 129, 151, 85, 49, 140, 95, 28, 185, 160, 118, 174, 241, 179, 238, 12, 84, 33, 135, 17, 187, 168, 197, 234, 35, 12, 133, 224, 157, 60, 237, 115, 84, 62, 162, 91, 157, 130, 71, 129, 122, 179, 72, 208, 176, 247, 77, 115, 169, 71, 37, 243, 26, 250, 178, 50, 106, 193, 219, 159, 80, 35, 88, 19, 137, 20, 18, 230, 78, 219, 10, 127, 197, 51, 127, 132, 30, 33, 13, 210, 194, 71, 231, 181, 118, 137, 136, 86, 252, 183, 57, 26, 108, 95, 140, 120, 1, 70, 232, 242, 26, 105, 70, 34, 65, 40, 210, 111, 74, 188, 210, 225, 81, 222, 64, 240, 126, 148, 147, 198, 11, 254, 49, 42, 14, 80, 226, 24, 33, 114, 33, 26, 130, 8, 29, 133, 98, 83, 183, 148, 90, 156, 121, 98, 182, 172, 147, 66, 126, 76, 56, 39, 181, 102, 227, 163, 225, 127, 164, 118, 233, 53, 202, 183, 252, 122, 77, 85, 179, 252, 24, 202, 28, 64, 64, 162, 244, 117, 202, 57, 181, 104, 17, 247, 167, 91, 240, 188, 26, 27, 109, 37, 113, 54, 205, 48, 83, 146, 89, 82, 244, 46, 244, 56, 133, 52, 246, 226, 28, 72, 57, 213, 180, 6, 232, 196, 27, 146, 252, 144, 215, 87, 149, 15, 31, 182, 155, 81, 96, 173, 162, 16, 207, 103, 152, 83, 8, 233, 188, 92, 117, 180, 129, 158, 136, 65, 111, 196, 11, 80, 8, 217, 142, 33, 244, 123, 234, 131, 226, 153, 34, 201, 99, 86, 101, 73, 219, 41, 171, 82, 110, 30, 24, 80, 218, 161, 57, 118, 132, 254, 161, 205, 70, 139, 114, 145, 181, 138, 36, 166, 229, 216, 124, 113, 67, 139, 139, 42, 210, 34, 28, 19, 83, 60, 115, 97, 48, 152, 99, 213, 85, 59, 66, 54, 146, 189, 194, 100, 65, 112, 186, 5, 45, 119, 128, 213, 130, 141, 187, 211, 80, 175, 146, 192, 168, 137, 11, 83, 90, 85, 97, 156, 129, 116, 247, 246, 62, 67, 246, 149, 75, 183, 134, 114, 209, 200, 156, 85, 27, 196, 163, 218, 151, 177, 75, 204, 11, 133, 187, 48, 183, 244, 239, 178, 85, 91, 207, 160, 35, 185, 112, 156, 174, 113, 139, 215, 50, 175, 84, 58, 145, 185, 31, 70, 1, 242, 22, 7, 232, 63, 31, 208, 117, 3, 231, 100, 131, 120, 64, 108, 184, 216, 120, 76, 153, 248, 0, 140, 4, 81, 23, 178, 109, 89, 188, 128, 104, 182, 190, 237, 240, 63, 102, 247, 62, 0, 77, 100, 61, 72, 130, 145, 111, 222, 236, 16, 105, 203, 133, 160, 255, 96, 45, 113, 170, 201, 43, 31, 229, 26, 148, 168, 201, 251, 176, 247, 164, 178, 181, 245, 152, 62, 37, 14, 156, 99, 234, 30, 136, 232, 249, 179, 51, 67, 140, 150, 134, 21, 156, 120, 201, 89, 141, 254, 62, 105, 243, 216, 231, 225, 190, 14, 40, 198, 229, 47, 100, 217, 228, 239, 142, 211, 234, 235, 199, 110, 76, 154, 105, 132, 76, 35, 180, 162, 147, 151, 203, 238, 50, 61, 97, 249, 205, 87, 217, 39, 42, 148, 88, 155, 6, 52, 248, 130, 238, 214, 57, 24, 127, 153, 16, 233, 94, 172, 42, 232, 209, 2, 172, 201, 181, 110, 11, 208, 108, 72, 150, 122, 13, 55, 95, 179, 245, 154, 250, 196, 59, 101, 67, 236, 179, 214, 62, 110, 80, 55, 7, 94, 8, 65, 200, 140, 180, 189, 17, 25, 80, 74, 177, 183, 142, 51, 171, 61, 236, 108, 124, 193, 137, 74, 41, 252, 255, 224, 0, 143, 238, 14, 143, 62, 124, 16, 185, 20, 22, 119, 13, 61, 4, 18, 245, 123, 141, 197, 35, 224, 233, 132, 38, 64, 50, 254, 201, 114, 99, 174, 35, 173, 227, 238, 158, 66, 161, 113, 222, 159, 0, 164, 69, 27, 136, 28, 142, 204, 215, 137, 32, 115, 54, 66, 41, 62, 108, 200, 15, 221, 73, 229, 119, 83, 27, 238, 110, 251, 107, 6, 112, 156, 22, 0, 164, 239, 236, 148, 88, 1, 125, 246, 48, 156, 103, 16, 97, 88, 221, 93, 133, 133, 204, 50, 191, 86, 234, 111, 172, 110, 55, 53, 56, 154, 29, 150, 175, 174, 200, 142, 104, 85, 246, 208, 238, 46, 210, 55, 118, 49, 188, 243, 131, 90, 252, 120, 156, 234, 136, 0, 49, 22, 193, 107, 106, 226, 169, 246, 33, 74, 182, 200, 25, 223, 69, 142, 221, 148, 177, 144, 17, 171, 49, 158, 220, 255, 66, 156, 252, 56, 41, 64, 40, 156, 75, 84, 67, 50, 226, 97, 246, 189, 4, 133, 173, 21, 26, 240, 155, 19, 48, 56, 93, 82, 133, 233, 49, 86, 82, 73, 3, 30, 108, 163, 177, 173, 195, 106, 124, 149, 249, 75, 107, 107, 144, 43, 91, 205, 78, 102, 156, 58, 167, 78, 246, 233, 68, 79, 152, 254, 129, 203, 232, 139, 227, 59, 84, 159, 110, 92, 229, 23, 87, 29, 201, 215, 233, 161, 84, 210, 16, 58, 35, 123, 166, 209, 32, 79, 3, 168, 243, 195, 112, 152, 178, 26, 118, 1, 115, 76, 222, 8, 225, 161, 178, 123, 249, 95, 104, 229, 115, 155, 52, 68, 234, 1, 229, 144, 201, 119, 179, 94, 18, 180, 151, 5, 80, 162, 22, 199, 5, 96, 30, 197, 247, 27, 238, 59, 171, 145, 11, 240, 6, 248, 246, 150, 236, 8, 223, 178, 159, 1, 164, 233, 240, 118, 55, 35, 88, 89, 114, 124, 112, 243, 38, 155, 74, 57, 132, 201, 69, 227, 170, 233, 28, 232, 227, 19, 231, 217, 252, 205, 5, 85, 206, 18, 188, 175, 57, 85, 81, 224, 186, 112, 146, 16, 48, 72, 197, 245, 124, 9, 131, 197, 240, 75, 227, 235, 242, 225, 184, 10, 151, 128, 124, 182, 65, 96, 101, 109, 102, 103, 47, 79, 46, 130, 203, 190, 205, 114, 228, 131, 170, 182, 175, 178, 196, 195, 199, 188, 195, 151, 130, 106, 98, 14, 165, 6, 82, 116, 164, 152, 156, 24, 3, 49, 85, 136, 12, 68, 95, 35, 212, 168, 35, 52, 71, 19, 91, 142, 184, 95, 195, 252, 224, 182, 173, 198, 204, 137, 13, 254, 34, 70, 140, 14, 16, 48, 160, 251, 148, 53, 73, 13, 152, 82, 226, 194, 44, 137, 60, 15, 71, 208, 199, 67, 75, 55, 58, 55, 9, 247, 179, 48, 56, 42, 209, 127, 6, 61, 192, 59, 8, 170, 64, 219, 250, 7, 173, 219, 68, 161, 113, 244, 101, 80, 39, 170, 175, 58, 175, 86, 129, 145, 40, 164, 234, 20, 66, 39, 102, 111, 16, 123, 10, 192, 27, 28, 80, 26, 87, 184, 186, 202, 126, 124, 141, 7, 35, 21, 235, 3, 81, 129, 79, 146, 19, 154, 190, 2, 175, 177, 0, 231, 28, 151, 73, 147, 239, 144, 128, 220, 180, 167, 167, 82, 221, 99, 57, 168, 246, 251, 35, 203, 180, 84, 102, 68, 249, 138, 37, 17, 229, 65, 217, 99, 21, 82, 37, 161, 253, 12, 34, 106, 17, 229, 1, 213, 70, 84, 105, 154, 252, 102, 128, 24, 19, 132, 116, 214, 240, 6, 110, 7, 59, 51, 83, 32, 133, 222, 175, 69, 134, 191, 64, 62, 176, 195, 3, 64, 113, 58, 188, 63, 68, 60, 35, 189, 198, 58, 75, 114, 132, 252, 179, 192, 181, 128, 93, 189, 255, 233, 78, 219, 176, 108, 60, 143, 48, 53, 63, 213, 167, 98, 75, 141, 73, 189, 59, 190, 147, 106, 69, 125, 206, 230, 251, 49, 147, 171, 252, 26, 47, 159, 230, 72, 26, 26, 145, 40, 64, 33, 172, 124, 166, 119, 90, 122, 137, 104, 254, 60, 25, 69, 224, 149, 111, 138, 191, 244, 81, 108, 205, 168, 48, 97, 15, 4, 98, 39, 156, 188, 162, 45, 29, 176, 254, 62, 121, 81, 106, 76, 238, 248, 113, 3, 13, 152, 253, 160, 145, 156, 86, 173, 8, 197, 252, 140, 86, 45, 39, 67, 54, 97, 56, 191, 161, 220, 69, 216, 215, 84, 171, 128, 2, 95, 181, 207, 238, 45, 221, 53, 147, 208, 68, 110, 18, 58, 255, 57, 143, 78, 52, 207, 148, 174, 10, 18, 196, 40, 213, 253, 101, 4, 7, 3, 223, 92, 125, 36, 183, 229, 71, 248, 120, 154, 33, 58, 211, 231, 17, 232, 151, 216, 255, 74, 201, 61, 253, 156, 209, 255, 167, 44, 202, 161, 56, 77, 180, 117, 5, 180, 52, 24, 8, 33, 72, 74, 30, 119, 13, 179, 187, 181, 115, 68, 197, 239, 10, 69, 79, 81, 200, 145, 209, 198, 237, 12, 152, 124, 200, 203, 170, 99, 151, 22, 62, 89, 198, 68, 116, 237, 139, 217, 107, 209, 109, 9, 96, 35, 250, 54, 149, 111, 53, 192, 225, 79, 26, 97, 60, 243, 162, 104, 147, 24, 175, 84, 2, 49, 174, 202, 38, 53, 34, 160, 82, 158, 101, 180, 144, 18, 238, 65, 63, 165, 108, 15, 108, 140, 170, 32, 122, 73, 76, 64, 188, 103, 225, 239, 100, 240, 12, 25, 39, 9, 187, 164, 112, 162, 100, 185, 27, 72, 122, 218, 28, 2, 20, 247, 7, 190, 131, 66, 116, 242, 180, 95, 189, 79, 158, 86, 246, 22, 14, 0, 104, 154, 105, 100, 39, 227, 139, 56, 221, 153, 88, 164, 163, 19, 248, 164, 72, 149, 49, 161, 247, 6, 100, 233, 26, 245, 44, 43, 115, 214, 91, 164, 205, 224, 59, 5, 48, 170, 187, 210, 184, 4, 83, 123, 170, 24, 194, 169, 181, 127, 47, 225, 198, 59, 145, 144, 8, 106, 166, 8, 121, 198, 120, 198, 155, 26, 143, 137, 243, 213, 27, 235, 203, 195, 28, 143, 144, 33, 123, 252, 32, 18, 248, 224, 59, 193, 210, 78, 21, 149, 16, 232, 130, 47, 93, 161, 37, 98, 80, 219, 199, 46, 45, 177, 231, 28, 127, 238, 28, 144, 0, 39, 54, 5, 215, 8, 70, 41, 196, 118, 117, 233, 11, 252, 41, 217, 123, 250, 53, 74, 20, 228, 84, 231, 254, 19, 211, 177, 231, 41, 16, 38, 47, 21, 158, 64, 255, 107, 29, 83, 142, 37, 37, 153, 116, 81, 210, 58, 227, 49, 184, 188, 219, 170, 168, 29, 19, 228, 8, 78, 45, 162, 75, 40, 157, 32, 224, 130, 72, 105, 24, 87, 20, 250, 9, 123, 187, 110, 77, 232, 243, 110, 45, 175, 67, 117, 168, 169, 57, 142, 12, 225, 19, 132, 2, 113, 42, 233, 47, 132, 241, 11, 189, 145, 11, 227, 175, 254, 14, 168, 95, 4, 241, 224, 97, 0, 196, 105, 146, 205, 254, 212, 1, 252, 81, 109, 177, 226, 171, 172, 44, 153, 216, 153, 245, 78, 167, 181, 63, 105, 184, 114, 92, 13, 107, 5, 21, 150, 22, 208, 65, 169, 159, 237, 9, 48, 206, 61, 24, 121, 172, 137, 75, 105, 105, 85, 149, 162, 190, 212, 129, 15, 74, 239, 185, 44, 162, 12, 192, 218, 84, 23, 132, 130, 120, 242, 243, 202, 192, 150, 177, 158, 242, 191, 184, 97, 16, 204, 35, 173, 159, 99, 33, 109, 204, 111, 3, 249, 253, 75, 113, 207, 98, 66, 218, 7, 81, 164, 106, 108, 77, 225, 64, 109, 33, 143, 88, 87, 76, 52, 48, 200, 172, 169, 190, 246, 172, 170, 230, 2, 43, 138, 226, 155, 225, 150, 250, 3, 234, 86, 75, 20, 18, 62, 163, 10, 172, 69, 38, 122, 35, 48, 48, 234, 21, 189, 158, 78, 153, 72, 62, 77, 157, 102, 248, 38, 151, 164, 15, 230, 232, 230, 230, 146, 195, 221, 244, 233, 250, 93, 118, 64, 249, 223, 158, 216, 33, 138, 44, 50, 225, 112, 56, 94, 44, 98, 154, 44, 31, 190, 150, 194, 223, 110, 165, 225, 157, 146, 115, 174, 157, 44, 76, 168, 155, 77, 222, 205, 138, 49, 160, 195, 193, 154, 228, 1, 60, 37, 239, 9, 18, 10, 238, 72, 220, 33, 88, 93, 40, 58, 88, 251, 117, 183, 246, 20, 109, 188, 79, 127, 251, 206, 90, 125, 178, 113, 34, 218, 135, 250, 57, 242, 163, 23, 203, 191, 231, 174, 34, 16, 210, 238, 64, 175, 248, 180, 16, 182, 177, 98, 231, 121, 51, 52, 88, 91, 236, 10, 11, 179, 145, 3, 66, 177, 33, 92, 244, 102, 231, 182, 106, 10, 237, 184, 148, 178, 39, 56, 14, 45, 223, 14, 14, 204, 22, 49, 75, 1, 241, 117, 246, 7, 29, 24, 122, 120, 132, 15, 171, 69, 223, 192, 162, 79, 44, 136, 9, 174, 170, 129, 118, 1, 74, 30, 218, 247, 39, 55, 99, 150, 72, 199, 214, 184, 4, 129, 72, 67, 121, 183, 235, 143, 183, 228, 130, 92, 160, 3, 194, 145, 242, 95, 85, 45, 170, 174, 157, 173, 73, 121, 213, 168, 95, 101, 58, 207, 57, 237, 51, 156, 67, 35, 207, 85, 161, 33, 129, 138, 8, 241, 58, 58, 218, 43, 97, 220, 177, 200, 65, 164, 152, 238, 19, 59, 174, 149, 178, 12, 116, 134, 0, 72, 43, 107, 23, 254, 57, 7, 86, 85, 22, 185, 194, 226, 25, 46, 23, 81, 132, 78, 65, 99, 41, 37, 91, 202, 168, 4, 103, 176, 70, 247, 112, 34, 178, 26, 38, 234, 249, 169, 232, 213, 141, 182, 155, 255, 2, 79, 139, 67, 182, 27, 8, 131, 32, 114, 21, 192, 243, 151, 58, 13, 202, 255, 52, 6, 209, 44, 79, 60, 83, 180, 39, 94, 235, 226, 156, 32, 152, 44, 75, 50, 22, 249, 148, 230, 69, 98, 136, 120, 252, 39, 11, 85, 109, 117, 181, 106, 249, 82, 163, 207, 240, 192, 56, 34, 98, 6, 11, 36, 89, 64, 181, 52, 148, 28, 174, 129, 74, 125, 2, 118, 246, 6, 140, 76, 196, 122, 215, 85, 51, 192, 137, 93, 192, 37, 30, 68, 155, 100, 224, 59, 192, 218, 1, 33, 57, 247, 155, 123, 126, 79, 101, 74, 8, 19, 169, 9, 41, 232, 229, 24, 102, 75, 78, 210, 239, 226, 219, 215, 170, 229, 116, 116, 190, 121, 212, 59, 20, 55, 80, 94, 246, 251, 114, 1, 252, 136, 224, 51, 243, 18, 200, 101, 13, 102, 133, 25, 157, 53, 245, 48, 241, 153, 68, 160, 148, 126, 93, 251, 113, 245, 174, 211, 43, 242, 95, 62, 43, 198, 25, 136, 140, 219, 98, 19, 42, 63, 93, 130, 63, 120, 203, 45, 113, 5, 110, 148, 163, 223, 73, 8, 202, 136, 41, 122, 54, 247, 148, 76, 211, 44, 33, 86, 36, 182, 163, 204, 160, 22, 126, 202, 172, 52, 174, 18, 132, 159, 92, 76, 90, 114, 170, 105, 4, 154, 131, 248, 128, 228, 101, 160, 212, 203, 39, 171, 149, 239, 57, 123, 168, 81, 5, 74, 147, 83, 42, 173, 196, 87, 198, 143, 248, 5, 165, 138, 198, 34, 196, 25, 1, 203, 100, 203, 238, 217, 141, 27, 158, 38, 149, 145, 45, 104, 34, 27, 237, 64, 74, 35, 68, 226, 142, 114, 174, 122, 142, 239, 104, 153, 247, 155, 19, 0, 113, 104, 228, 155, 119, 147, 216, 215, 90, 53, 47, 92, 112, 75, 201, 85, 95, 45, 29, 232, 100, 73, 61, 145, 220, 235, 94, 68, 16, 170, 210, 162, 205, 5, 118, 225, 147, 229, 142, 31, 91, 98, 235, 125, 214, 111, 222, 45, 79, 180, 40, 29, 126, 112, 149, 52, 52, 158, 53, 59, 209, 240, 231, 220, 239, 9, 17, 78, 58, 227, 80, 167, 87, 133, 110, 67, 101, 39, 147, 188, 60, 15, 243, 6, 162, 34, 162, 125, 184, 237, 10, 56, 81, 154, 213, 251, 47, 54, 245, 10, 115, 127, 166, 254, 237, 197, 167, 153, 118, 105, 92, 96, 254, 188, 140, 228, 183, 106, 153, 82, 122, 162, 242, 31, 233, 215, 186, 110, 200, 169, 178, 107, 83, 113, 130, 168, 158, 111, 20, 150, 140, 162, 125, 53, 200, 205, 128, 219, 38, 242, 196, 139, 150, 239, 78, 224, 157, 25, 104, 63, 159, 50, 48, 186, 33, 219, 82, 157, 194, 209, 13, 65, 120, 100, 254, 44, 9, 120, 31, 103, 89, 94, 79, 150, 142, 167, 115, 117, 146, 214, 96, 152, 213, 142, 228, 72, 127, 85, 102, 237, 129, 12, 220, 220, 105, 45, 43, 38, 6, 128, 133, 87, 48, 105, 136, 177, 240, 42, 185, 72, 0, 107, 230, 26, 172, 122, 251, 110, 2, 32, 170, 103, 101, 69, 49, 107, 46, 36, 226, 208, 68, 31, 178, 81, 21, 31, 30, 236, 191, 244, 50, 30, 54, 143, 67, 207, 180, 19, 116, 96, 16, 123, 210, 82, 168, 221, 199, 147, 189, 133, 60, 91, 41, 205, 62, 61, 134, 36, 46, 18, 78, 133, 139, 190, 114, 11, 16, 28, 71, 53, 175, 35, 164, 173, 144, 111, 33, 184, 196, 125, 36, 101, 243, 29, 80, 169, 81, 186, 41, 196, 124, 120, 63, 118, 15, 61, 0, 60, 177, 247, 142, 158, 220, 202, 24, 204, 68, 10, 180, 34, 54, 16, 114, 151, 107, 6, 32, 220, 210, 191, 129, 80, 190, 124, 140, 214, 61, 1, 34, 193, 136, 141, 251, 157, 193, 46, 232, 84, 160, 249, 138, 207, 67, 2, 2, 7, 8, 244, 179, 136, 166, 131, 1, 145, 14, 5, 47, 81, 190, 198, 188, 245, 5, 50, 60, 55, 70, 217, 89, 28, 3, 41, 47, 251, 77, 248, 33, 68, 6, 116, 121, 191, 24, 67, 197, 16, 215, 111, 229, 132, 37, 212, 180, 190, 21, 69, 211, 154, 114, 141, 69, 69, 16, 0, 60, 110, 57, 13, 184, 190, 241, 198, 7, 19, 89, 150, 66, 157, 141, 175, 0, 136, 156, 163, 218, 215, 127, 82, 255, 152, 215, 37, 251, 186, 223, 111, 242, 253, 233, 175, 46, 179, 1, 247, 225, 30, 19, 192, 85, 130, 137, 155, 219, 41, 33, 185, 33, 126, 131, 237, 0, 45, 246, 54, 86, 176, 133, 211, 6, 141, 230, 90, 73, 65, 75, 120, 47, 179, 96, 28, 193, 30, 17, 22, 43, 98, 93, 196, 105, 88, 201, 40, 82, 5, 186, 29, 165, 158, 119, 102, 58, 14, 85, 89, 47, 85, 29, 140, 17, 27, 113, 21, 217, 143, 195, 91, 38, 192, 181, 229, 0, 150, 248, 97, 36, 158, 62, 103, 179, 116, 191, 114, 121, 95, 124, 249, 112, 228, 21, 127, 248, 123, 5, 192, 167, 229, 174, 2, 242, 151, 132, 55, 183, 139, 51, 103, 138, 69, 210, 136, 33, 104, 169, 119, 127, 45, 152, 138, 226, 157, 201, 29, 80, 106, 224, 12, 30, 1, 132, 36, 248, 62, 0, 147, 132, 226, 104, 67, 211, 87, 38, 35, 99, 160, 131, 195, 32, 144, 10, 32, 252, 197, 133, 128, 180, 123, 104, 143, 82, 64, 74, 70, 188, 208, 2, 59, 77, 212, 247, 109, 161, 52, 248, 78, 230, 221, 102, 142, 40, 136, 142, 172, 69, 135, 25, 92, 126, 241, 174, 200, 85, 205, 44, 175, 144, 83, 54, 250, 11, 206, 204, 162, 120, 232, 215, 8, 198, 110, 71, 48, 136, 146, 12, 184, 0, 18, 30, 55, 48, 216, 77, 109, 17, 9, 249, 51, 71, 255, 170, 218, 62, 243, 195, 71, 45, 149, 217, 142, 83, 181, 38, 44, 9, 9, 66, 57, 175, 69, 15, 60, 170, 97, 112, 61, 249, 182, 34, 100, 11, 216, 137, 101, 195, 80, 14, 35, 111, 223, 11, 61, 106, 208, 91, 81, 142, 145, 96, 145, 226, 159, 88, 22, 18, 211, 192, 154, 185, 67, 93, 73, 144, 206, 221, 201, 179, 138, 223, 88, 151, 122, 128, 150, 6, 102, 9, 91, 68, 130, 217, 147, 125, 1, 225, 102, 245, 212, 7, 178, 203, 91, 139, 175, 43, 102, 221, 172, 214, 188, 107, 116, 54, 78, 92, 225, 4, 6, 241, 194, 148, 237, 44, 171, 149, 17, 180, 104, 33, 144, 86, 133, 205, 70, 236, 87, 40, 195, 147, 67, 8, 34, 112, 64, 22, 111, 196, 96, 246, 129, 131, 226, 36, 181, 250, 68, 98, 86, 159, 77, 5, 182, 147, 224, 21, 65, 18, 180, 36, 85, 224, 100, 229, 166, 85, 59, 255, 113, 41, 130, 120, 232, 2, 113, 114, 211, 53, 200, 45, 183, 238, 240, 174, 1, 68, 82, 167, 6, 198, 172, 55, 103, 200, 2, 8, 30, 53, 196, 99, 40, 138, 239, 185, 86, 191, 230, 174, 97, 61, 7, 120, 85, 142, 6, 202, 107, 114, 20, 202, 13, 209, 82, 46, 122, 14, 21, 27, 44, 152, 132, 217, 40, 254, 113, 170, 186, 229, 228, 81, 15, 148, 77, 26, 43, 113, 17, 100, 156, 33, 90, 38, 88, 129, 171, 199, 148, 30, 16, 94, 95, 182, 24, 159, 4, 96, 106, 98, 219, 36, 73, 218, 79, 152, 152, 176, 159, 34, 13, 80, 54, 176, 157, 191, 128, 46, 230, 117, 199, 127, 8, 36, 208, 7, 237, 41, 241, 160, 116, 172, 181, 90, 94, 233, 130, 233, 225, 35, 53, 155, 106, 115, 118, 192, 220, 118, 190, 248, 170, 110, 113, 23, 171, 120, 176, 247, 181, 130, 172, 197, 44, 111, 239, 3, 89, 217, 108, 182, 120, 190, 62, 138, 226, 232, 31, 233, 3, 77, 114, 53, 228, 157, 129, 209, 233, 26, 245, 254, 235, 164, 195, 194, 50, 73, 225, 14, 225, 251, 100, 59, 93, 167, 134, 171, 186, 46, 101, 169, 205, 33, 87, 23, 97, 138, 116, 226, 51, 2, 229, 221, 188, 16, 219, 175, 168, 202, 198, 113, 51, 183, 116, 137, 139, 224, 233, 20, 110, 121, 47, 206, 155, 201, 166, 114, 226, 30, 186, 157, 124, 241, 5, 119, 99, 101, 106, 151, 49, 60, 206, 210, 16, 66, 2, 247, 168, 159, 166, 192, 198, 55, 217, 22, 126, 235, 14, 203, 81, 72, 142, 194, 187, 42, 118, 189, 167, 4, 199, 59, 110, 8, 88, 121, 247, 138, 57, 180, 45, 96, 77, 227, 228, 29, 187, 65, 173, 142, 96, 100, 26, 22, 160, 88, 108, 210, 83, 138, 196, 35, 9, 58, 176, 71, 59, 21, 128, 59, 166, 47, 114, 158, 226, 145, 144, 199, 35, 25, 219, 22, 38, 104, 119, 65, 4, 222, 170, 224, 89, 206, 26, 96, 161, 59, 62, 37, 201, 27, 92, 91, 201, 64, 220, 109, 103, 222, 7, 100, 225, 114, 221, 19, 47, 192, 117, 243, 236, 23, 100, 113, 251, 111, 69, 196, 144, 237, 22, 0, 243, 251, 138, 240, 123, 95, 168, 224, 167, 223, 133, 197, 143, 144, 126, 100, 139, 36, 120, 185, 19, 175, 240, 251, 66, 46, 56, 197, 169, 168, 17, 168, 218, 183, 9, 186, 123, 140, 168, 226, 74, 117, 140, 191, 210, 161, 96, 53, 229, 192, 250, 224, 73, 189, 235, 153, 225, 28, 2, 12, 95, 25, 130, 167, 139, 189, 24, 71, 2, 102, 46, 149, 137, 237, 194, 61, 67, 138, 20, 249, 40, 35, 24, 176, 188, 60, 122, 73, 231, 156, 204, 253, 245, 41, 229, 144, 192, 152, 102, 71, 6, 241, 0, 37, 176, 223, 91, 213, 236, 216, 245, 235, 127, 83, 130, 229, 102, 244, 219, 40, 236, 135, 5, 153, 88, 186, 213, 62, 120, 187, 115, 9, 181, 44, 8, 212, 111, 78, 255, 237, 244, 101, 133, 113, 169, 31, 28, 202, 147, 120, 190, 147, 133, 123, 14, 223, 120, 41, 71, 114, 51, 165, 6, 90, 90, 113, 207, 246, 150, 40, 143, 124, 73, 170, 193, 232, 107, 43, 98, 59, 25, 123, 59, 250, 108, 7, 21, 105, 79, 72, 113, 27, 1, 88, 37, 20, 218, 254, 183, 233, 14, 124, 16, 59, 17, 164, 162, 242, 247, 9, 80, 7, 183, 151, 68, 41, 48, 22, 53, 134, 88, 223, 113, 154, 95, 205, 178, 170, 125, 216, 45, 152, 141, 76, 33, 184, 43, 186, 41, 151, 115, 223, 224, 97, 100, 154, 30, 74, 20, 148, 113, 180, 100, 226, 221, 19, 143, 119, 182, 45, 90, 99, 157, 90, 57, 80, 58, 227, 107, 36, 177, 138, 144, 245, 78, 4, 218, 205, 154, 147, 59, 62, 163, 67, 7, 174, 32, 91, 254, 145, 126, 187, 221, 208, 92, 111, 73, 170, 173, 107, 59, 69, 78, 7, 171, 135, 241, 148, 138, 50, 40, 228, 138, 10, 229, 228, 145, 95, 223, 13, 161, 183, 245, 41, 150, 149, 199, 7, 255, 138, 221, 142, 172, 65, 53, 31, 230, 47, 229, 126, 42, 131, 66, 18, 77, 203, 6, 206, 228, 215, 192, 209, 175, 98, 184, 159, 241, 106, 95, 255, 111, 55, 45, 234, 212, 4, 32, 208, 111, 37, 212, 53, 129, 70, 168, 156, 151, 188, 2, 121, 154, 140, 84, 155, 164, 51, 114, 142, 45, 24, 51, 99, 137, 224, 147, 212, 26, 220, 163, 19, 39, 180, 215, 53, 165, 162, 182, 233, 59, 221, 11, 90, 237, 112, 78, 36, 117, 233, 23, 229, 192, 94, 99, 96, 118, 171, 57, 42, 16, 98, 175, 43, 171, 196, 248, 18, 57, 19, 98, 181, 237, 235, 184, 177, 155, 6, 83, 179, 70, 162, 221, 121, 216, 116, 116, 200, 193, 164, 252, 59, 216, 48, 104, 112, 42, 207, 152, 246, 91, 109, 141, 68, 104, 49, 225, 210, 8, 79, 179, 62, 10, 31, 156, 189, 216, 179, 81, 102, 220, 79, 187, 167, 207, 11, 119, 83, 130, 24, 100, 215, 115, 143, 96, 213, 132, 109, 77, 35, 168, 40, 247, 133, 60, 53, 179, 26, 159, 70, 149, 59, 249, 130, 175, 113, 97, 166, 123, 156, 54, 129, 126, 197, 171, 18, 105, 91, 254, 211, 78, 233, 206, 145, 166, 101, 97, 32, 157, 236, 137, 252, 183, 59, 234, 219, 181, 236, 190, 76, 56, 145, 170, 245, 59, 208, 29, 16, 116, 45, 138, 135, 248, 118, 228, 3, 251, 244, 177, 85, 107, 13, 57, 60, 35, 237, 73, 5, 58, 140, 120, 165, 47, 223, 127, 98, 136, 84, 16, 18, 225, 126, 38, 100, 120, 35, 194, 204, 170, 144, 253, 217, 18, 86, 133, 225, 191, 220, 178, 177, 11, 51, 146, 205, 132, 128, 33, 90, 195, 234, 116, 68, 20, 73, 194, 135, 137, 0, 16, 169, 243, 123, 5, 130, 172, 162, 48, 240, 232, 208, 158, 32, 49, 140, 245, 51, 37, 131, 92, 67, 126, 44, 13, 31, 62, 240, 80, 131, 136, 187, 222, 199, 19, 28, 229, 240, 122, 208, 244, 180, 58, 232, 46, 1, 83, 171, 236, 220, 69, 6, 43, 152, 203, 3, 16, 246, 17, 69, 116, 54, 64, 9, 240, 109, 189, 32, 237, 189, 153, 148, 107, 2, 7, 224, 144, 242, 114, 76, 46, 66, 91, 31, 228, 112, 115, 124, 108, 39, 108, 225, 232, 245, 175, 122, 57, 47, 175, 12, 179, 39, 27, 172, 167, 249, 76, 135, 106, 133, 82, 162, 27, 220, 11, 94, 144, 228, 95, 114, 158, 217, 58, 24, 211, 24, 42, 118, 88, 178, 81, 163, 27, 41, 116, 193, 231, 88, 164, 166, 21, 95, 207, 245, 47, 245, 173, 56, 11, 144, 87, 124, 231, 79, 214, 60, 160, 185, 39, 102, 146, 204, 70, 202, 222, 203, 101, 183, 165, 180, 33, 216, 127, 96, 249, 7, 143, 237, 96, 186, 72, 40, 64, 213, 23, 251, 103, 123, 251, 135, 182, 237, 169, 43, 46, 30, 140, 133, 53, 127, 17, 18, 37, 31, 123, 86, 187, 5, 75, 64, 27, 13, 175, 180, 152, 249, 135, 82, 16, 139, 136, 204, 175, 27, 135, 255, 204, 39, 223, 160, 78, 6, 151, 95, 65, 13, 41, 64, 93, 64, 1, 218, 99, 109, 134, 201, 25, 62, 0, 191, 212, 140, 170, 8, 19, 28, 119, 45, 2, 53, 228, 169, 150, 252, 218, 233, 121, 176, 198, 208, 137, 58, 62, 37, 8, 150, 83, 247, 152, 133, 121, 85, 85, 2, 54, 179, 179, 105, 251, 99, 239, 223, 90, 42, 76, 49, 187, 250, 187, 197, 150, 141, 139, 36, 178, 143, 241, 206, 44, 80, 255, 14, 198, 156, 112, 154, 232, 11, 75, 53, 213, 83, 123, 94, 141, 155, 201, 113, 241, 56, 70, 252, 64, 158, 166, 165, 96, 152, 186, 2, 92, 3, 114, 52, 156, 134, 7, 222, 31, 90, 137, 52, 48, 12, 201, 84, 147, 254, 138, 19, 184, 114, 245, 138, 7, 90, 49, 167, 145, 107, 182, 83, 253, 40, 52, 160, 187, 243, 67, 151, 81, 3, 218, 68, 56, 202, 178, 144, 175, 238, 77, 145, 191, 171, 245, 128, 4, 208, 195, 102, 119, 57, 240, 6, 66, 254, 211, 45, 130, 58, 225, 51, 99, 73, 13, 56, 58, 28, 35, 110, 33, 180, 51, 26, 140, 70, 26, 229, 180, 229, 176, 138, 226, 9, 134, 129, 185, 187, 239, 223, 2, 229, 233, 150, 121, 138, 51, 41, 143, 68, 57, 118, 56, 31, 87, 195, 1, 75, 87, 156, 253, 225, 48, 243, 60, 94, 212, 205, 205, 151, 180, 100, 135, 245, 23, 108, 18, 5, 132, 244, 135, 177, 10, 37, 12, 28, 10, 127, 93, 103, 207, 148, 27, 227, 93, 148, 246, 204, 17, 88, 121, 29, 100, 198, 40, 185, 62, 104, 157, 5, 56, 71, 213, 100, 127, 249, 128, 244, 137, 235, 154, 144, 197, 8, 208, 124, 114, 242, 13, 251, 50, 254, 34, 91, 56, 10, 193, 195, 147, 85, 84, 21, 114, 112, 185, 50, 108, 118, 235, 123, 103, 247, 179, 202, 50, 17, 200, 66, 193, 58, 63, 43, 104, 163, 165, 140, 252, 54, 59, 102, 13, 117, 138, 175, 183, 48, 220, 215, 173, 86, 24, 135, 190, 226, 209, 212, 8, 111, 15, 152, 3, 126, 226, 149, 168, 204, 178, 165, 4, 230, 32, 34, 8, 79, 242, 94, 100, 141, 5, 125, 159, 109, 205, 161, 61, 95, 14, 59, 3, 132, 196, 133, 176, 198, 172, 25, 243, 70, 148, 96, 196, 241, 24, 65, 116, 30, 177, 162, 251, 228, 156, 147, 77, 244, 65, 138, 223, 212, 22, 40, 122, 1, 202, 219, 51, 101, 78, 118, 96, 101, 146, 112, 10, 172, 36, 211, 254, 136, 208, 48, 88, 82, 217, 33, 32, 148, 185, 234, 217, 100, 29, 141, 88, 247, 168, 34, 215, 165, 136, 149, 42, 203, 97, 227, 69, 216, 67, 65, 14, 27, 19, 84, 33, 141, 58, 75, 72, 178, 44, 16, 160, 251, 174, 94, 248, 52, 184, 125, 190, 77, 251, 88, 72, 11, 153, 160, 127, 77, 22, 127, 219, 245, 89, 76, 136, 192, 202, 239, 219, 248, 248, 171, 164, 198, 78, 148, 85, 159, 72, 218, 223, 99, 53, 38, 201, 186, 121, 68, 137, 194, 174, 136, 239, 224, 160, 67, 111, 220, 229, 93, 245, 31, 250, 193, 91, 110, 252, 12, 7, 131, 47, 62, 73, 10, 100, 129, 88, 40, 230, 245, 208, 146, 14, 132, 120, 204, 222, 135, 68, 47, 222, 19, 60, 161, 7, 67, 64, 68, 70, 29, 152, 64, 7, 183, 251, 225, 148, 61, 155, 127, 233, 89, 112, 169, 73, 157, 76, 150, 85, 219, 41, 71, 220, 234, 15, 173, 98, 124, 209, 206, 71, 56, 201, 187, 64, 16, 103, 159, 78, 9, 84, 187, 250, 154, 196, 49, 125, 168, 154, 127, 40, 15, 139, 198, 155, 71, 7, 80, 98, 219, 105, 202, 183, 96, 32, 115, 28, 168, 81, 69, 23, 103, 33, 219, 47, 154, 131, 125, 7, 229, 140, 163, 248, 62, 156, 231, 8, 141, 34, 232, 193, 150, 171, 224, 190, 62, 76, 47, 203, 161, 1, 186, 3, 67, 55, 0, 117, 153, 152, 165, 90, 146, 124, 169, 150, 90, 241, 163, 67, 146, 64, 13, 165, 218, 131, 135, 166, 193, 186, 200, 149, 8, 55, 9, 227, 66, 157, 212, 226, 97, 91, 172, 199, 196, 59, 131, 75, 170, 88, 8, 242, 30, 148, 211, 214, 208, 102, 225, 102, 165, 119, 155, 69, 208, 18, 168, 81, 84, 153, 79, 240, 92, 216, 36, 99, 75, 125, 249, 93, 182, 54, 232, 169, 235, 184, 210, 169, 104, 11, 163, 110, 116, 174, 218, 205, 75, 188, 68, 8, 194, 219, 137, 103, 93, 23, 10, 64, 49, 217, 198, 215, 166, 151, 189, 209, 148, 92, 61, 14, 11, 101, 129, 79, 230, 112, 234, 42, 125, 185, 107, 178, 135, 186, 78, 220, 33, 145, 91, 144, 176, 224, 134, 93, 16, 202, 31, 211, 10, 221, 21, 202, 245, 141, 245, 51, 147, 27, 192, 146, 205, 175, 255, 21, 186, 205, 62, 177, 127, 20, 231, 2, 81, 3, 161, 67, 225, 24, 66, 9, 102, 150, 218, 178, 3, 255, 65, 4, 141, 81, 0, 197, 134, 168, 72, 163, 246, 235, 224, 14, 62, 70, 205, 42, 161, 183, 151, 76, 86, 78, 101, 168, 253, 154, 46, 206, 132, 135, 104, 60, 217, 8, 128, 64, 60, 88, 6, 152, 85, 189, 49, 186, 230, 62, 156, 64, 47, 172, 148, 77, 114, 199, 27, 222, 122, 225, 213, 230, 57, 233, 175, 32, 113, 1, 36, 30, 146, 82, 127, 199, 75, 195, 196, 117, 250, 190, 80, 4, 229, 168, 125, 109, 55, 135, 0, 189, 75, 14, 58, 177, 239, 93, 131, 234, 227, 168, 209, 224, 140, 99, 240, 36, 225, 141, 184, 71, 253, 235, 142, 103, 83, 120, 97, 74, 94, 20, 13, 176, 36, 55, 204, 132, 64, 162, 157, 251, 233, 127, 119, 51, 143, 194, 94, 249, 60, 10, 141, 252, 138, 129, 160, 193, 213, 122, 197, 216, 74, 4, 20, 59, 47, 197, 124, 199, 186, 87, 30, 88, 120, 70, 15, 171, 134, 218, 144, 167, 229, 168, 35, 179, 203, 208, 151, 121, 47, 192, 83, 179, 102, 112, 147, 20, 118, 169, 148, 69, 103, 200, 134, 204, 254, 162, 24, 3, 120, 7, 194, 166, 163, 175, 153, 35, 252, 209, 15, 164, 29, 133, 23, 74, 177, 174, 196, 118, 97, 220, 139, 245, 22, 58, 125, 146, 250, 198, 163, 228, 225, 101, 103, 214, 180, 18, 111, 105, 127, 33, 249, 2, 217, 144, 86, 167, 107, 236, 76, 40, 72, 64, 24, 94, 2, 238, 173, 42, 26, 117, 41, 124, 44, 108, 0, 7, 49, 228, 158, 225, 78, 88, 247, 141, 142, 242, 207, 128, 58, 142, 40, 141, 36, 93, 17, 54, 9, 210, 175, 248, 170, 142, 121, 4, 221, 108, 1, 184, 162, 113, 221, 64, 181, 30, 9, 32, 13, 69, 14, 154, 11, 237, 136, 237, 188, 146, 233, 171, 57, 159, 80, 235, 12, 80, 151, 11, 42, 157, 137, 44, 104, 53, 241, 188, 62, 99, 253, 118, 220, 242, 169, 182, 146, 31, 113, 19, 16, 61, 6, 75, 128, 18, 5, 52, 168, 187, 7, 139, 94, 14, 12, 107, 223, 20, 134, 162, 13, 12, 142, 51, 39, 158, 99, 191, 124, 233, 4, 96, 172, 172, 84, 138, 84, 49, 91, 8, 133, 190, 160, 59, 122, 114, 72, 82, 57, 6, 93, 108, 9, 88, 252, 240, 247, 185, 170, 28, 163, 243, 228, 81, 212, 118, 86, 5, 30, 20, 80, 46, 173, 177, 119, 216, 111, 84, 139, 132, 97, 122, 67, 108, 176, 171, 31, 192, 71, 108, 22, 65, 42, 83, 221, 166, 15, 32, 207, 141, 92, 177, 170, 65, 169, 83, 65, 54, 118, 184, 156, 7, 197, 130, 29, 9, 157, 87, 71, 235, 66, 54, 225, 220, 48, 160, 193, 88, 185, 231, 251, 229, 157, 118, 66, 206, 143, 242, 42, 72, 52, 178, 243, 198, 193, 43, 12, 81, 121, 178, 65, 82, 39, 113, 135, 191, 197, 25, 142, 148, 52, 46, 123, 192, 188, 246, 95, 87, 173, 225, 162, 39, 182, 51, 169, 185, 228, 25, 115, 30, 210, 225, 47, 168, 93, 139, 76, 121, 224, 61, 30, 24, 45, 34, 37, 181, 180, 128, 113, 155, 43, 70, 224, 60, 218, 30, 252, 249, 131, 154, 168, 9, 191, 85, 234, 233, 1, 44, 212, 224, 137, 138, 217, 13, 22, 242, 242, 53, 56, 105, 189, 221, 117, 62, 23, 174, 5, 224, 90, 248, 165, 13, 60, 67, 82, 189, 152, 105, 3, 139, 183, 12, 172, 166, 171, 255, 217, 124, 209, 99, 54, 24, 190, 163, 255, 2, 240, 164, 227, 85, 33, 161, 145, 116, 165, 236, 167, 159, 144, 242, 3, 146, 19, 50, 41, 147, 107, 91, 175, 196, 255, 199, 237, 77, 251, 219, 134, 189, 244, 68, 254, 6, 75, 127, 198, 102, 251, 159, 11, 184, 93, 83, 138, 212, 140, 140, 6, 36, 173, 187, 180, 108, 151, 133, 118, 66, 79, 12, 118, 208, 46, 125, 226, 42, 57, 213, 210, 197, 108, 152, 71, 173, 149, 135, 237, 62, 232, 173, 29, 172, 126, 113, 71, 106, 218, 86, 188, 1, 33, 158, 245, 155, 87, 41, 192, 89, 211, 249, 179, 104, 18, 33, 85, 24, 147, 141, 184, 80, 179, 223, 73, 21, 49, 7, 51, 100, 176, 0, 147, 244, 197, 172, 193, 132, 53, 85, 13, 245, 234, 12, 200, 81, 229, 103, 54, 92, 103, 85, 26, 128, 20, 35, 187, 4, 27, 213, 225, 155, 33, 131, 173, 198, 30, 7, 9, 53, 196, 10, 94, 237, 163, 5, 172, 28, 113, 80, 194, 43, 145, 4, 236, 3, 72, 133, 153, 203, 227, 3, 246, 104, 97, 142, 157, 88, 45, 227, 179, 186, 37, 91, 31, 179, 62, 102, 144, 76, 199, 215, 113, 163, 177, 129, 129, 96, 215, 157, 4, 245, 192, 127, 80, 107, 219, 227, 216, 148, 203, 227, 212, 164, 165, 165, 83, 55, 18, 157, 178, 38, 72, 132, 180, 238, 70, 3, 12, 5, 97, 58, 155, 168, 184, 115, 175, 123, 17, 168, 187, 243, 74, 109, 199, 96, 126, 228, 98, 132, 15, 144, 164, 246, 57, 19, 83, 230, 184, 222, 50, 245, 22, 162, 245, 162, 146, 89, 186, 89, 5, 177, 128, 97, 29, 86, 147, 172, 67, 139, 249, 165, 137, 110, 149, 113, 229, 162, 164, 59, 218, 41, 17, 124, 43, 130, 13, 113, 199, 215, 165, 33, 146, 8, 220, 14, 151, 124, 1, 70, 231, 102, 246, 217, 176, 97, 79, 191, 243, 204, 172, 78, 71, 4, 239, 151, 227, 221, 255, 133, 178, 140, 248, 91, 235, 79, 111, 48, 181, 151, 236, 142, 165, 198, 189, 28, 53, 136, 250, 153, 75, 195, 82, 131, 204, 217, 175, 219, 137, 72, 87, 207, 28, 73, 112, 14, 44, 55, 68, 97, 88, 27, 154, 179, 9, 200, 145, 146, 232, 191, 19, 150, 223, 15, 205, 21, 161, 118, 30, 188, 186, 171, 208, 8, 63, 88, 180, 56, 192, 72, 228, 135, 104, 243, 190, 238, 39, 179, 179, 122, 84, 54, 120, 48, 154, 174, 253, 192, 59, 249, 111, 119, 73, 17, 139, 121, 27, 98, 57, 161, 222, 147, 146, 37, 54, 159, 66, 191, 158, 89, 60, 147, 6, 126, 84, 165, 19, 22, 147, 43, 148, 87, 63, 174, 214, 178, 22, 233, 112, 25, 157, 123, 118, 219, 179, 249, 182, 114, 217, 218, 80, 33, 248, 103, 89, 0, 87, 200, 154, 249, 23, 157, 67, 106, 97, 249, 183, 20, 67, 56, 75, 84, 176, 40, 0, 50, 144, 58, 38, 89, 93, 107, 197, 123, 90, 164, 99, 48, 17, 13, 212, 121, 152, 96, 84, 166, 118, 106, 128, 230, 107, 95, 26, 107, 4, 161, 48, 191, 181, 197, 150, 66, 18, 252, 11, 235, 79, 238, 66, 233, 26, 137, 89, 16, 5, 249, 174, 96, 250, 242, 12, 16, 241, 94, 73, 232, 36, 244, 54, 140, 38, 43, 213, 89, 53, 115, 212, 223, 21, 84, 167, 119, 246, 0, 5, 218, 87, 141, 124, 140, 206, 146, 171, 26, 171, 128, 9, 221, 33, 116, 110, 98, 87, 46, 11, 34, 41, 60, 123, 115, 8, 168, 183, 63, 117, 171, 129, 157, 216, 92, 75, 128, 46, 59, 169, 53, 33, 115, 65, 162, 155, 178, 128, 25, 109, 237, 41, 89, 107, 48, 23, 79, 191, 16, 205, 172, 148, 171, 201, 246, 104, 166, 6, 134, 23, 233, 136, 106, 157, 246, 136, 102, 57, 76, 34, 221, 231, 144, 129, 9, 26, 234, 97, 208, 33, 94, 134, 86, 25, 206, 224, 129, 138, 240, 108, 64, 17, 97, 248, 188, 16, 16, 184, 9, 123, 43, 18, 135, 33, 252, 11, 100, 46, 42, 20, 209, 144, 173, 136, 115, 65, 129, 236, 137, 53, 9, 5, 109, 211, 100, 75, 199, 57, 141, 40, 42, 32, 10, 66, 177, 93, 91, 215, 170, 24, 79, 41, 9, 230, 65, 104, 193, 139, 75, 233, 180, 90, 204, 152, 170, 244, 35, 149, 77, 41, 120, 50, 106, 72, 8, 103, 152, 32, 198, 161, 133, 129, 250, 38, 148, 229, 225, 133, 5, 81, 134, 16, 45, 17, 145, 114, 193, 12, 41, 18, 161, 219, 118, 197, 208, 151, 77, 227, 115, 137, 121, 225, 156, 42, 251, 13, 233, 206, 235, 129, 94, 197, 158, 104, 19, 26, 117, 164, 6, 236, 54, 97, 246, 84, 239, 138, 233, 18, 151, 202, 152, 137, 218, 168, 73, 128, 167, 7, 162, 193, 86, 129, 128, 95, 5, 237, 98, 57, 8, 155, 11, 199, 247, 109, 71, 90, 58, 206, 232, 80, 164, 210, 115, 126, 230, 26, 251, 216, 109, 3, 37, 203, 62, 194, 123, 27, 87, 107, 146, 154, 64, 194, 130, 148, 138, 89, 40, 242, 253, 235, 64, 128, 99, 74, 225, 162, 211, 246, 170, 219, 168, 158, 47, 173, 210, 184, 231, 53, 225, 124, 18, 57, 137, 223, 144, 48, 164, 114, 106, 209, 216, 70, 29, 69, 114, 131, 174, 112, 40, 234, 73, 138, 176, 194, 110, 119, 204, 79, 241, 81, 1, 18, 72, 164, 80, 97, 203, 114, 152, 4, 27, 118, 67, 177, 81, 49, 58, 15, 106, 163, 227, 43, 14, 91, 251, 72, 129, 99, 15, 173, 239, 36, 41, 54, 107, 131, 4, 66, 9, 42, 152, 125, 34, 68, 170, 80, 188, 250, 63, 62, 198, 231, 62, 246, 254, 127, 11, 248, 242, 76, 15, 173, 32, 230, 106, 145, 228, 85, 175, 156, 71, 40, 30, 78, 202, 15, 233, 254, 63, 68, 191, 238, 126, 87, 79, 31, 78, 135, 113, 199, 114, 193, 181, 215, 192, 108, 128, 120, 62, 34, 247, 87, 5, 111, 105, 244, 85, 56, 77, 112, 206, 109, 50, 74, 1, 163, 18, 158, 27, 21, 65, 122, 11, 232, 11, 85, 145, 177, 4, 246, 1, 133, 84, 70, 68, 61, 155, 51, 232, 150, 77, 34, 2, 64, 205, 110, 1, 179, 229, 251, 168, 238, 45, 9, 246, 52, 91, 13, 93, 109, 252, 70, 184, 105, 79, 40, 199, 91, 65, 31, 2, 163, 248, 150, 245, 2, 208, 223, 162, 18, 170, 125, 201, 16, 195, 242, 148, 17, 197, 153, 149, 234, 129, 134, 71, 30, 146, 2, 227, 248, 213, 121, 212, 153, 29, 101, 7, 246, 119, 92, 30, 63, 55, 73, 129, 27, 128, 162, 96, 10, 248, 250, 55, 99, 115, 129, 101, 230, 163, 14, 8, 158, 92, 159, 97, 2, 192, 149, 22, 3, 196, 9, 176, 114, 137, 2, 104, 182, 5, 134, 58, 60, 97, 146, 148, 6, 54, 33, 203, 162, 53, 23, 50, 45, 30, 228, 13, 233, 55, 200, 65, 150, 39, 104, 168, 200, 140, 65, 178, 143, 114, 40, 64, 225, 60, 43, 248, 40, 191, 0, 138, 172, 254, 185, 91, 2, 67, 184, 237, 169, 95, 69, 57, 162, 110, 78, 143, 92, 24, 7, 4, 63, 151, 107, 144, 82, 60, 19, 170, 227, 90, 163, 221, 81, 180, 224, 102, 136, 144, 152, 237, 77, 247, 168, 212, 87, 160, 135, 76, 58, 139, 227, 103, 212, 184, 10, 77, 150, 189, 39, 90, 149, 197, 204, 253, 99, 171, 79, 66, 202, 131, 89, 1, 15, 10, 85, 202, 30, 107, 110, 156, 181, 213, 87, 68, 44, 0, 13, 19, 69, 235, 242, 150, 69, 138, 65, 200, 55, 48, 178, 69, 211, 139, 121, 53, 182, 165, 252, 203, 117, 40, 100, 248, 16, 110, 70, 94, 39, 211, 236, 178, 194, 163, 191, 249, 233, 188, 244, 124, 122, 192, 107, 230, 78, 27, 175, 65, 222, 1, 217, 198, 37, 181, 19, 162, 241, 159, 133, 55, 110, 82, 134, 43, 192, 149, 126, 201, 214, 254, 223, 73, 62, 227, 220, 138, 83, 117, 190, 169, 25, 161, 135, 38, 83, 133, 204, 56, 212, 115, 38, 88, 46, 237, 27, 228, 40, 68, 24, 169, 116, 28, 119, 95, 36, 205, 134, 129, 220, 194, 44, 198, 222, 121, 227, 126, 192, 26, 175, 204, 149, 162, 71, 159, 158, 238, 116, 123, 249, 201, 74, 206, 30, 11, 40, 16, 72, 162, 42, 127, 197, 252, 159, 6, 9, 3, 110, 70, 213, 133, 181, 153, 92, 140, 105, 86, 185, 71, 115, 231, 85, 241, 218, 137, 34, 32, 52, 195, 234, 49, 220, 123, 165, 126, 247, 177, 10, 69, 93, 145, 71, 89, 211, 206, 234, 148, 198, 199, 206, 211, 35, 19, 96, 130, 231, 137, 108, 217, 123, 17, 167, 78, 141, 242, 196, 17, 129, 9, 159, 237, 183, 133, 1, 95, 26, 231, 8, 204, 152, 184, 96, 56, 144, 136, 128, 42, 236, 247, 18, 217, 172, 141, 57, 187, 21, 23, 198, 26, 109, 218, 180, 199, 199, 52, 118, 164, 120, 51, 3, 19, 152, 144, 249, 152, 74, 129, 82, 55, 204, 102, 66, 211, 97, 180, 104, 113, 209, 27, 229, 238, 44, 123, 251, 114, 201, 0, 8, 11, 126, 113, 102, 100, 1, 233, 218, 52, 166, 231, 69, 75, 10, 166, 179, 78, 191, 117, 254, 97, 201, 153, 1, 179, 188, 140, 137, 132, 34, 108, 132, 26, 216, 175, 234, 36, 196, 161, 45, 149, 180, 217, 174, 75, 129, 84, 205, 21, 110, 248, 108, 53, 154, 47, 4, 152, 72, 146, 46, 208, 106, 168, 37, 201, 232, 44, 211, 129, 57, 134, 251, 150, 29, 46, 60, 104, 20, 67, 56, 116, 61, 181, 52, 191, 143, 128, 5, 214, 81, 68, 73, 182, 179, 32, 23, 84, 124, 205, 49, 41, 137, 195, 167, 189, 38, 89, 22, 118, 242, 76, 52, 158, 92, 160, 224, 36, 154, 168, 212, 60, 182, 143, 12, 51, 123, 142, 80, 60, 112, 0, 213, 34, 3, 27, 161, 9, 108, 141, 28, 97, 102, 130, 29, 95, 191, 220, 148, 138, 190, 64, 49, 170, 159, 245, 227, 255, 3, 116, 128, 174, 124, 214, 165, 98, 78, 9, 216, 65, 206, 0, 240, 109, 119, 67, 165, 0, 22, 168, 170, 130, 2, 94, 14, 206, 158, 149, 157, 26, 44, 241, 21, 176, 84, 200, 91, 59, 14, 3, 138, 69, 84, 146, 150, 138, 226, 172, 18, 96, 49, 156, 163, 18, 212, 26, 169, 99, 98, 8, 205, 231, 18, 191, 36, 118, 189, 185, 60, 128, 83, 107, 88, 253, 42, 205, 163, 48, 163, 18, 221, 148, 128, 219, 103, 135, 36, 168, 232, 116, 68, 122, 38, 10, 62, 71, 41, 169, 34, 131, 174, 122, 58, 59, 82, 24, 59, 79, 184, 118, 242, 27, 214, 199, 140, 39, 105, 78, 148, 153, 43, 176, 126, 83, 217, 240, 118, 100, 76, 234, 70, 92, 22, 48, 46, 216, 75, 133, 119, 92, 108, 32, 99, 211, 25, 142, 175, 226, 156, 53, 178, 36, 117, 218, 218, 130, 5, 49, 215, 164, 191, 34, 234, 90, 1, 60, 151, 105, 226, 255, 94, 126, 182, 52, 164, 105, 139, 126, 178, 244, 160, 252, 170, 140, 160, 99, 186, 139, 43, 143, 92, 129, 250, 33, 139, 91, 252, 207, 17, 154, 169, 53, 140, 170, 64, 216, 181, 181, 69, 231, 198, 224, 170, 71, 21, 82, 187, 224, 216, 164, 51, 161, 2, 68, 131, 137, 107, 206, 196, 203, 20, 77, 51, 160, 234, 153, 61, 217, 109, 184, 164, 61, 249, 210, 156, 67, 254, 94, 254, 35, 139, 189, 123, 49, 111, 194, 101, 82, 135, 234, 205, 215, 109, 63, 84, 79, 221, 20, 132, 133, 79, 208, 84, 170, 123, 187, 24, 159, 243, 26, 124, 217, 103, 225, 238, 200, 80, 47, 245, 48, 17, 219, 60, 162, 146, 241, 182, 133, 72, 132, 4, 206, 197, 20, 181, 1, 135, 121, 121, 102, 202, 98, 211, 29, 88, 61, 100, 149, 6, 24, 103, 138, 194, 101, 107, 177, 206, 250, 179, 154, 47, 29, 144, 246, 120, 115, 27, 188, 252, 18, 150, 214, 198, 144, 182, 149, 178, 71, 12, 252, 147, 243, 126, 143, 187, 181, 21, 250, 253, 120, 103, 240, 28, 73, 36, 139, 61, 124, 6, 180, 161, 218, 142, 82, 245, 168, 60, 7, 197, 252, 83, 83, 68, 102, 64, 138, 25, 132, 194, 88, 236, 135, 232, 53, 70, 19, 212, 62, 102, 170, 32, 22, 5, 208, 231, 207, 89, 208, 157, 87, 96, 148, 67, 164, 172, 97, 249, 238, 116, 233, 217, 10, 225, 246, 202, 56, 222, 205, 23, 245, 76, 19, 201, 146, 68, 28, 166, 127, 67, 168, 145, 135, 194, 8, 129, 29, 180, 70, 38, 80, 142, 94, 9, 254, 58, 249, 113, 90, 121, 11, 27, 55, 110, 80, 43, 62, 116, 209, 48, 7, 133, 100, 72, 227, 79, 69, 25, 253, 109, 6, 127, 214, 182, 234, 26, 231, 79, 201, 180, 42, 209, 200, 185, 110, 118, 71, 103, 233, 178, 98, 56, 70, 193, 27, 30, 133, 115, 89, 37, 192, 103, 138, 49, 222, 9, 166, 94, 84, 214, 119, 147, 161, 190, 93, 253, 110, 110, 208, 89, 174, 143, 83, 164, 147, 39, 228, 244, 128, 66, 8, 46, 42, 225, 45, 150, 234, 138, 17, 139, 48, 33, 36, 88, 43, 219, 159, 3, 28, 230, 122, 23, 4, 116, 204, 220, 129, 173, 42, 0, 176, 17, 23, 221, 184, 218, 68, 210, 178, 163, 102, 122, 148, 105, 208, 188, 158, 52, 134, 84, 62, 90, 242, 66, 174, 54, 14, 51, 96, 205, 239, 250, 121, 155, 33, 163, 224, 42, 57, 199, 183, 224, 242, 114, 96, 160, 253, 199, 53, 253, 61, 158, 9, 32, 103, 93, 232, 0, 125, 247, 146, 32, 217, 137, 214, 186, 110, 15, 91, 127, 246, 127, 33, 135, 7, 44, 2, 162, 224, 205, 152, 69, 128, 162, 87, 10, 160, 38, 36, 59, 72, 118, 204, 166, 236, 102, 149, 44, 13, 60, 187, 63, 83, 19, 49, 253, 110, 147, 55, 20, 172, 83, 120, 0, 177, 96, 25, 45, 154, 37, 135, 8, 145, 124, 182, 7, 12, 47, 170, 118, 175, 60, 131, 98, 0, 128, 43, 58, 251, 84, 47, 10, 77, 140, 175, 223, 52, 132, 221, 193, 62, 191, 80, 150, 188, 62, 194, 149, 9, 145, 250, 79, 199, 24, 233, 21, 13, 55, 35, 212, 59, 6, 124, 64, 93, 67, 61, 98, 219, 129, 3, 163, 178, 107, 8, 173, 253, 110, 79, 167, 255, 253, 215, 170, 129, 49, 148, 31, 58, 203, 79, 101, 113, 18, 123, 212, 29, 194, 173, 8, 1, 14, 232, 64, 95, 205, 2, 18, 64, 181, 240, 112, 39, 155, 254, 68, 182, 53, 203, 108, 109, 215, 168, 12, 186, 184, 4, 45, 21, 222, 54, 155, 212, 64, 96, 186, 246, 158, 161, 32, 68, 205, 3, 240, 2, 207, 218, 168, 147, 50, 219, 208, 252, 74, 112, 131, 200, 28, 86, 42, 228, 62, 6, 128, 202, 234, 205, 32, 102, 143, 154, 128, 165, 77, 208, 44, 20, 134, 200, 75, 221, 112, 218, 178, 194, 170, 245, 151, 185, 16, 201, 98, 209, 37, 129, 168, 175, 23, 99, 72, 251, 40, 217, 139, 209, 131, 185, 222, 232, 197, 152, 198, 147, 33, 226, 225, 66, 211, 51, 150, 105, 103, 241, 27, 44, 236, 24, 170, 51, 142, 222, 8, 157, 106, 232, 145, 236, 170, 1, 17, 89, 91, 216, 40, 238, 187, 81, 30, 53, 51, 146, 206, 216, 142, 62, 189, 71, 145, 64, 40, 244, 96, 92, 51, 186, 135, 165, 172, 17, 180, 165, 204, 104, 232, 84, 147, 125, 49, 217, 183, 133, 14, 208, 208, 207, 195, 139, 234, 193, 139, 16, 25, 22, 131, 233, 222, 232, 96, 177, 245, 73, 223, 134, 164, 24, 121, 190, 150, 229, 85, 177, 233, 82, 164, 96, 175, 62, 105, 247, 93, 3, 84, 254, 101, 226, 65, 71, 70, 161, 190, 127, 111, 31, 239, 186, 185, 119, 191, 66, 238, 32, 58, 187, 136, 8, 3, 210, 127, 197, 17, 70, 225, 84, 248, 206, 18, 94, 163, 26, 93, 105, 96, 217, 210, 142, 12, 14, 91, 182, 61, 62, 208, 0, 91, 118, 195, 221, 38, 127, 81, 166, 106, 206, 141, 43, 191, 27, 205, 130, 156, 33, 135, 135, 38, 245, 222, 64, 39, 162, 70, 207, 152, 249, 105, 249, 4, 200, 130, 77, 65, 132, 230, 174, 163, 227, 57, 235, 106, 70, 186, 163, 244, 173, 248, 45, 238, 86, 108, 215, 68, 243, 114, 185, 124, 203, 135, 227, 122, 201, 215, 100, 19, 206, 13, 5, 29, 116, 117, 80, 19, 19, 112, 63, 63, 235, 42, 57, 7, 19, 253, 206, 106, 4, 143, 78, 61, 244, 217, 71, 252, 226, 229, 130, 205, 45, 254, 194, 233, 40, 250, 208, 32, 163, 106, 241, 161, 218, 23, 238, 94, 126, 208, 142, 223, 231, 43, 103, 178, 149, 172, 62, 33, 0, 198, 45, 197, 208, 157, 106, 21, 40, 88, 9, 211, 112, 8, 130, 246, 234, 102, 193, 185, 158, 176, 61, 40, 85, 16, 39, 238, 25, 205, 29, 100, 166, 5, 109, 34, 165, 187, 210, 36, 190, 170, 57, 243, 144, 157, 243, 24, 251, 95, 239, 23, 44, 149, 164, 179, 147, 231, 141, 111, 223, 3, 48, 167, 187, 172, 174, 225, 98, 187, 98, 180, 154, 99, 207, 38, 79, 233, 142, 163, 169, 59, 63, 151, 235, 70, 63, 32, 110, 112, 210, 11, 31, 221, 250, 245, 142, 90, 123, 8, 207, 96, 97, 29, 1, 178, 16, 151, 21, 4, 34, 19, 170, 74, 136, 70, 75, 164, 117, 97, 7, 209, 49, 64, 39, 67, 211, 233, 201, 255, 147, 85, 141, 238, 60, 253, 3, 26, 62, 66, 50, 69, 64, 4, 218, 85, 154, 254, 54, 24, 27, 136, 127, 254, 10, 77, 5, 60, 74, 116, 36, 4, 98, 129, 167, 228, 134, 187, 106, 250, 136, 174, 45, 180, 102, 38, 209, 246, 192, 231, 164, 95, 56, 74, 228, 22, 67, 141, 36, 124, 53, 192, 99, 254, 21, 110, 116, 72, 112, 231, 100, 195, 39, 222, 90, 212, 189, 174, 78, 220, 228, 36, 54, 54, 138, 230, 117, 22, 228, 24, 146, 90, 182, 180, 37, 142, 173, 194, 115, 146, 236, 191, 82, 132, 141, 5, 126, 82, 203, 70, 33, 147, 197, 234, 90, 201, 200, 180, 161, 34, 90, 156, 99, 108, 181, 185, 244, 105, 182, 12, 152, 53, 171, 149, 41, 243, 158, 153, 243, 14, 38, 161, 177, 181, 33, 27, 15, 194, 135, 20, 31, 156, 61, 53, 84, 209, 114, 179, 83, 178, 160, 170, 46, 15, 101, 178, 94, 60, 43, 22, 149, 141, 49, 199, 172, 178, 186, 23, 138, 173, 41, 244, 95, 129, 232, 165, 232, 32, 172, 45, 78, 227, 148, 56, 20, 163, 104, 35, 236, 99, 73, 132, 19, 138, 182, 171, 73, 185, 246, 99, 11, 62, 190, 255, 149, 83, 20, 37, 221, 202, 233, 83, 224, 78, 153, 149, 224, 4, 209, 138, 204, 161, 38, 50, 79, 187, 219, 29, 201, 189, 191, 107, 171, 0, 6, 23, 119, 144, 217, 146, 27, 249, 243, 234, 22, 146, 198, 248, 99, 200, 164, 120, 12, 147, 174, 101, 88, 248, 180, 111, 219, 38, 236, 203, 74, 76, 14, 73, 204, 131, 220, 92, 255, 176, 63, 133, 157, 99, 165, 237, 108, 195, 247, 104, 180, 228, 0, 128, 47, 135, 74, 184, 226, 134, 106, 118, 36, 34, 95, 80, 243, 17, 191, 4, 68, 48, 19, 28, 227, 232, 85, 147, 24, 173, 54, 20, 138, 240, 105, 203, 133, 145, 20, 134, 169, 85, 21, 168, 214, 136, 206, 46, 18, 85, 191, 167, 15, 255, 182, 60, 63, 93, 42, 61, 47, 22, 18, 82, 120, 223, 24, 50, 136, 141, 218, 227, 224, 120, 171, 49, 221, 134, 68, 222, 222, 123, 72, 17, 112, 23, 183, 227, 200, 170, 121, 13, 251, 113, 0, 184, 12, 128, 123, 75, 103, 100, 200, 161, 51, 255, 63, 83, 237, 198, 191, 117, 144, 109, 212, 34, 220, 180, 68, 69, 137, 55, 96, 216, 89, 42, 186, 104, 144, 227, 5, 102, 170, 118, 161, 133, 41, 227, 25, 244, 127, 249, 252, 132, 81, 115, 107, 59, 151, 158, 71, 69, 36, 52, 220, 254, 120, 107, 3, 100, 8, 25, 64, 174, 6, 71, 203, 11, 43, 41, 79, 75, 55, 50, 190, 208, 109, 48, 185, 253, 105, 126, 25, 1, 9, 136, 131, 150, 92, 200, 64, 154, 187, 74, 55, 167, 21, 193, 217, 202, 181, 65, 28, 213, 40, 105, 129, 212, 54, 141, 205, 106, 110, 7, 68, 109, 21, 73, 201, 173, 56, 193, 154, 144, 174, 152, 3, 81, 195, 27, 100, 231, 16, 28, 217, 11, 186, 123, 79, 149, 180, 167, 126, 93, 206, 180, 33, 45, 178, 250, 52, 96, 242, 26, 96, 128, 119, 128, 5, 24, 142, 156, 173, 159, 47, 97, 153, 16, 102, 86, 217, 161, 236, 31, 99, 33, 255, 206, 150, 165, 247, 136, 45, 175, 175, 211, 130, 174, 3, 21, 95, 41, 216, 230, 109, 168, 48, 10, 48, 97, 87, 201, 3, 221, 206, 15, 59, 6, 33, 88, 107, 115, 33, 0, 90, 170, 162, 68, 98, 150, 102, 85, 114, 79, 125, 72, 153, 218, 188, 221, 145, 206, 165, 157, 136, 96, 46, 175, 41, 99, 190, 46, 249, 224, 131, 74, 125, 229, 129, 156, 152, 248, 100, 215, 64, 40, 64, 98, 75, 249, 120, 171, 74, 65, 160, 210, 0, 215, 248, 207, 129, 148, 171, 192, 96, 79, 35, 196, 165, 232, 4, 48, 107, 145, 31, 1, 64, 145, 143, 235, 75, 43, 122, 197, 193, 97, 73, 13, 142, 36, 62, 34, 109, 47, 161, 122, 207, 184, 192, 76, 238, 209, 142, 195, 205, 178, 136, 233, 41, 184, 135, 53, 251, 69, 167, 190, 247, 16, 95, 116, 70, 225, 177, 113, 197, 94, 21, 252, 105, 245, 235, 93, 100, 226, 203, 253, 224, 214, 107, 187, 133, 152, 220, 200, 234, 237, 64, 252, 25, 76, 96, 58, 80, 201, 68, 154, 131, 141, 202, 221, 199, 26, 186, 87, 110, 199, 201, 251, 60, 170, 68, 240, 6, 15, 122, 149, 213, 110, 94, 246, 11, 50, 31, 170, 9, 3, 4, 84, 132, 9, 73, 147, 39, 120, 106, 52, 35, 73, 2, 226, 214, 68, 214, 228, 91, 4, 31, 196, 39, 129, 78, 61, 170, 247, 156, 136, 233, 67, 80, 154, 115, 140, 149, 159, 250, 206, 22, 26, 152, 199, 195, 240, 163, 80, 78, 92, 97, 238, 106, 145, 105, 18, 191, 108, 86, 197, 194, 227, 157, 51, 127, 25, 178, 11, 56, 114, 15, 102, 78, 165, 59, 53, 200, 28, 206, 141, 235, 10, 61, 154, 192, 58, 228, 132, 135, 241, 19, 116, 114, 185, 103, 210, 146, 117, 162, 19, 163, 244, 251, 123, 194, 148, 19, 209, 218, 105, 158, 87, 242, 132, 219, 4, 188, 104, 0, 219, 95, 47, 151, 15, 115, 87, 217, 154, 124, 220, 237, 40, 45, 188, 241, 81, 110, 249, 17, 69, 70, 13, 230, 76, 68, 26, 118, 147, 250, 254, 76, 195, 46, 65, 79, 181, 24, 143, 125, 55, 49, 109, 57, 171, 53, 45, 93, 198, 137, 254, 229, 160, 116, 221, 4, 20, 22, 202, 4, 87, 64, 235, 68, 180, 214, 192, 169, 224, 96, 104, 250, 56, 49, 87, 70, 38, 239, 58, 124, 27, 69, 83, 232, 127, 154, 42, 186, 53, 91, 76, 129, 202, 72, 209, 197, 182, 57, 64, 2, 34, 82, 214, 42, 126, 198, 170, 222, 241, 87, 230, 6, 162, 158, 199, 39, 215, 119, 83, 72, 172, 176, 208, 204, 67, 174, 212, 153, 70, 2, 150, 162, 175, 242, 13, 170, 143, 4, 45, 96, 44, 190, 62, 148, 184, 239, 234, 134, 116, 239, 63, 195, 15, 136, 12, 238, 69, 18, 46, 22, 187, 103, 212, 202, 66, 185, 44, 68, 55, 85, 29, 82, 181, 184, 183, 61, 200, 152, 103, 13, 82, 236, 12, 213, 158, 205, 33, 177, 139, 117, 206, 105, 78, 80, 153, 27, 222, 169, 37, 112, 79, 99, 182, 217, 35, 9, 210, 28, 241, 196, 236, 51, 104, 204, 247, 74, 118, 216, 247, 107, 182, 56, 105, 185, 131, 225, 2, 58, 78, 59, 75, 218, 52, 166, 17, 52, 0, 149, 191, 153, 67, 56, 36, 10, 169, 247, 143, 175, 203, 160, 41, 77, 251, 166, 119, 153, 146, 101, 149, 114, 22, 23, 25, 95, 128, 254, 130, 30, 100, 28, 164, 202, 224, 231, 159, 170, 9, 101, 210, 211, 144, 16, 83, 146, 204, 101, 168, 56, 133, 169, 168, 7, 65, 46, 224, 177, 28, 233, 43, 7, 27, 93, 58, 239, 75, 237, 14, 197, 213, 232, 57, 30, 39, 211, 248, 243, 192, 246, 85, 190, 64, 215, 7, 136, 60, 10, 67, 168, 185, 128, 60, 77, 210, 235, 211, 123, 24, 55, 66, 163, 201, 141, 30, 212, 130, 125, 171, 104, 55, 254, 60, 106, 25, 41, 109, 172, 195, 46, 50, 183, 222, 15, 55, 171, 47, 79, 1, 40, 32, 241, 140, 103, 13, 70, 187, 151, 50, 192, 125, 54, 108, 98, 39, 134, 10, 211, 94, 62, 198, 206, 100, 58, 220, 107, 30, 237, 113, 236, 157, 202, 244, 132, 239, 230, 147, 248, 166, 249, 79, 251, 123, 198, 203, 207, 46, 147, 37, 200, 158, 18, 237, 175, 91, 12, 225, 179, 140, 145, 84, 137, 5, 34, 56, 36, 102, 199, 89, 101, 225, 185, 38, 200, 1, 251, 73, 98, 211, 137, 135, 22, 32, 241, 144, 245, 140, 106, 22, 158, 105, 45, 192, 109, 25, 249, 251, 42, 206, 58, 20, 71, 169, 175, 96, 37, 147, 146, 34, 56, 220, 19, 137, 142, 151, 49, 174, 177, 103, 143, 251, 245, 165, 93, 105, 122, 52, 78, 57, 65, 25, 21, 241, 1, 221, 30, 228, 250, 89, 49, 51, 171, 21, 155, 92, 201, 1, 143, 132, 91, 124, 192, 40, 59, 79, 10, 185, 189, 76, 188, 123, 120, 181, 78, 208, 139, 217, 222, 121, 208, 224, 212, 175, 25, 202, 29, 122, 175, 168, 211, 52, 146, 3, 4, 50, 37, 161, 159, 183, 223, 7, 181, 180, 190, 147, 118, 119, 120, 81, 27, 132, 2, 111, 182, 81, 192, 95, 145, 229, 95, 61, 226, 51, 208, 197, 151, 207, 221, 165, 180, 219, 71, 50, 248, 72, 250, 38, 118, 202, 190, 235, 60, 246, 243, 163, 217, 101, 132, 31, 163, 89, 1, 1, 248, 13, 148, 100, 176, 29, 186, 10, 154, 87, 253, 143, 209, 162, 216, 130, 91, 229, 29, 187, 250, 150, 193, 67, 80, 165, 162, 148, 91, 54, 17, 187, 179, 154, 233, 234, 41, 185, 102, 176, 132, 48, 233, 133, 97, 225, 68, 142, 131, 90, 239, 63, 224, 150, 164, 91, 24, 251, 33, 2, 135, 117, 188, 154, 104, 59, 129, 88, 186, 141, 130, 165, 198, 149, 66, 110, 201, 20, 104, 195, 30, 7, 14, 66, 9, 32, 73, 120, 168, 111, 28, 58, 171, 103, 164, 57, 173, 10, 182, 125, 27, 169, 15, 97, 200, 167, 41, 187, 184, 141, 180, 176, 77, 43, 242, 232, 131, 252, 98, 76, 67, 254, 210, 239, 183, 232, 132, 16, 253, 129, 155, 236, 170, 13, 42, 244, 88, 86, 150, 60, 103, 59, 214, 240, 75, 20, 46, 9, 212, 71, 63, 64, 64, 135, 240, 67, 72, 253, 112, 73, 152, 250, 231, 142, 192, 149, 23, 137, 14, 115, 60, 135, 29, 134, 12, 4, 138, 86, 47, 7, 122, 51, 134, 249, 28, 222, 227, 191, 96, 107, 151, 157, 4, 200, 161, 131, 50, 248, 55, 222, 99, 97, 171, 84, 209, 146, 75, 78, 33, 37, 129, 172, 194, 235, 181, 248, 146, 127, 66, 72, 189, 59, 77, 211, 157, 5, 241, 113, 111, 47, 185, 24, 142, 240, 212, 125, 96, 166, 132, 16, 57, 30, 83, 164, 63, 243, 225, 56, 62, 87, 111, 75, 102, 154, 175, 213, 41, 186, 116, 42, 51, 144, 94, 22, 179, 252, 103, 231, 125, 45, 235, 218, 57, 232, 207, 132, 2, 221, 118, 176, 232, 181, 222, 247, 46, 2, 49, 120, 172, 47, 206, 38, 148, 117, 106, 135, 201, 193, 118, 63, 253, 24, 133, 68, 133, 95, 1, 152, 35, 6, 109, 234, 25, 183, 59, 113, 192, 238, 0, 112, 90, 30, 61, 39, 240, 75, 65, 75, 158, 162, 45, 38, 104, 227, 112, 194, 159, 141, 220, 187, 60, 121, 227, 233, 192, 197, 207, 249, 183, 20, 57, 3, 235, 71, 88, 146, 178, 101, 78, 32, 20, 255, 17, 95, 139, 112, 195, 73, 69, 86, 222, 21, 157, 86, 30, 42, 152, 188, 77, 191, 35, 212, 40, 88, 107, 162, 186, 102, 98, 40, 110, 179, 174, 198, 123, 69, 177, 169, 179, 107, 182, 249, 232, 28, 37, 193, 162, 99, 36, 171, 32, 27, 152, 97, 167, 55, 141, 248, 67, 132, 152, 125, 113, 60, 183, 139, 232, 96, 196, 91, 47, 104, 109, 249, 128, 171, 19, 153, 23, 112, 142, 191, 90, 146, 188, 161, 112, 31, 110, 31, 50, 65, 137, 55, 6, 44, 234, 57, 112, 190, 39, 71, 112, 115, 56, 177, 158, 35, 190, 153, 119, 97, 128, 72, 38, 252, 67, 27, 130, 18, 68, 149, 0, 246, 236, 9, 194, 140, 219, 18, 131, 227, 224, 116, 68, 154, 140, 79, 135, 223, 154, 73, 141, 84, 177, 6, 149, 233, 48, 234, 166, 74, 8, 9, 228, 241, 33, 84, 205, 226, 241, 43, 63, 9, 70, 163, 184, 58, 204, 53, 160, 46, 248, 38, 67, 155, 157, 207, 182, 112, 171, 65, 140, 50, 174, 80, 17, 226, 170, 243, 169, 80, 130, 101, 242, 89, 137, 5, 158, 52, 16, 139, 119, 175, 210, 112, 63, 50, 53, 173, 35, 64, 13, 40, 133, 102, 197, 242, 170, 152, 13, 102, 105, 138, 61, 100, 1, 109, 248, 107, 190, 169, 15, 45, 182, 36, 236, 34, 188, 125, 44, 119, 140, 63, 87, 74, 197, 201, 85, 193, 36, 71, 152, 130, 186, 122, 234, 175, 99, 73, 241, 207, 131, 134, 210, 136, 211, 25, 61, 202, 242, 167, 189, 163, 112, 162, 132, 55, 64, 94, 113, 111, 60, 51, 100, 136, 83, 238, 135, 190, 14, 147, 201, 36, 240, 173, 37, 45, 25, 153, 71, 15, 36, 200, 0, 241, 149, 194, 180, 141, 54, 37, 17, 72, 88, 157, 107, 137, 145, 203, 178, 208, 5, 190, 112, 19, 200, 90, 152, 8, 122, 212, 172, 130, 0, 156, 83, 106, 199, 126, 53, 126, 118, 78, 142, 164, 110, 2, 51, 206, 229, 115, 164, 191, 188, 96, 242, 143, 76, 210, 19, 63, 160, 210, 53, 167, 191, 74, 137, 36, 107, 94, 236, 129, 8, 128, 42, 156, 72, 104, 220, 101, 196, 198, 141, 191, 235, 202, 210, 187, 143, 3, 222, 146, 109, 142, 94, 19, 176, 150, 161, 130, 14, 191, 77, 100, 101, 96, 10, 249, 193, 34, 40, 141, 99, 39, 170, 25, 64, 196, 228, 160, 7, 219, 209, 252, 9, 114, 137, 126, 157, 36, 124, 50, 106, 130, 138, 182, 166, 54, 247, 227, 157, 200, 78, 225, 82, 14, 233, 140, 69, 26, 10, 67, 15, 41, 109, 11, 178, 125, 76, 165, 155, 68, 205, 194, 3, 146, 142, 85, 112, 3, 191, 97, 46, 210, 36, 135, 212, 160, 164, 87, 223, 8, 242, 110, 0, 138, 113, 115, 3, 255, 95, 124, 195, 237, 171, 192, 244, 168, 74, 174, 184, 181, 149, 17, 63, 110, 106, 173, 219, 66, 203, 120, 137, 222, 69, 236, 124, 226, 216, 137, 75, 217, 128, 79, 121, 189, 237, 116, 142, 247, 17, 9, 193, 66, 160, 232, 27, 85, 174, 153, 198, 4, 238, 28, 199, 138, 28, 204, 64, 178, 151, 43, 24, 208, 179, 88, 149, 94, 59, 255, 108, 237, 122, 86, 199, 172, 246, 24, 3, 13, 142, 84, 140, 207, 186, 6, 112, 201, 69, 44, 94, 160, 76, 155, 125, 146, 24, 254, 41, 204, 125, 175, 32, 233, 112, 251, 221, 52, 2, 96, 153, 128, 81, 191, 165, 233, 101, 20, 22, 49, 15, 235, 228, 193, 200, 48, 165, 179, 192, 154, 192, 52, 56, 235, 8, 216, 21, 72, 50, 4, 173, 34, 50, 135, 19, 114, 142, 54, 97, 247, 23, 218, 64, 223, 120, 196, 97, 37, 123, 214, 227, 245, 42, 110, 7, 225, 122, 146, 39, 159, 151, 108, 229, 130, 237, 169, 6, 61, 178, 237, 105, 121, 90, 22, 228, 249, 12, 29, 143, 207, 179, 52, 17, 163, 169, 120, 149, 242, 51, 228, 235, 95, 194, 26, 35, 226, 224, 47, 203, 138, 159, 183, 208, 41, 20, 130, 86, 9, 99, 131, 192, 175, 123, 54, 43, 120, 190, 0, 203, 178, 80, 119, 181, 39, 159, 210, 140, 147, 69, 24, 220, 168, 50, 255, 51, 34, 123, 137, 167, 160, 138, 67, 189, 206, 207, 230, 193, 95, 190, 161, 33, 231, 80, 77, 15, 134, 216, 33, 208, 235, 88, 131, 41, 146, 214, 30, 229, 220, 248, 114, 132, 10, 175, 38, 124, 55, 160, 172, 152, 37, 64, 124, 21, 233, 63, 1, 36, 239, 231, 54, 4, 79, 48, 109, 203, 128, 130, 25, 64, 83, 151, 227, 15, 226, 78, 8, 14, 113, 100, 58, 192, 243, 65, 6, 69, 216, 195, 180, 11, 140, 127, 182, 70, 187, 24, 156, 129, 20, 88, 212, 145, 235, 158, 107, 37, 39, 141, 1, 234, 111, 244, 25, 209, 37, 187, 30, 130, 177, 141, 161, 170, 129, 255, 139, 111, 40, 20, 61, 23, 60, 17, 104, 35, 134, 120, 241, 132, 25, 171, 119, 184, 22, 54, 66, 79, 153, 9, 78, 173, 9, 104, 93, 75, 177, 0, 250, 15, 254, 84, 67, 40, 99, 19, 171, 46, 3, 229, 22, 164, 144, 224, 219, 23, 98, 161, 224, 118, 52, 129, 201, 15, 164, 180, 156, 217, 139, 213, 108, 43, 61, 36, 218, 200, 85, 54, 157, 11, 47, 121, 6, 249, 158, 231, 22, 143, 28, 5, 82, 88, 188, 160, 250, 244, 237, 15, 63, 139, 235, 244, 224, 12, 62, 238, 177, 75, 197, 192, 225, 203, 38, 43, 197, 17, 178, 92, 224, 234, 100, 204, 83, 28, 209, 46, 156, 213, 31, 48, 32, 94, 118, 226, 27, 36, 212, 223, 0, 153, 208, 193, 156, 145, 100, 148, 119, 213, 20, 106, 96, 6, 105, 229, 182, 199, 33, 153, 118, 148, 36, 54, 80, 199, 254, 116, 202, 39, 201, 245, 163, 177, 236, 75, 159, 233, 37, 27, 37, 31, 25, 237, 65, 19, 190, 222, 251, 179, 199, 245, 147, 197, 238, 205, 16, 169, 250, 233, 174, 212, 235, 9, 115, 105, 161, 145, 199, 19, 202, 208, 98, 213, 47, 27, 53, 57, 124, 248, 12, 245, 2, 234, 64, 107, 213, 182, 5, 243, 29, 238, 192, 110, 132, 174, 114, 243, 123, 102, 119, 241, 100, 86, 27, 13, 210, 46, 7, 204, 144, 180, 223, 55, 47, 37, 126, 104, 16, 62, 77, 75, 245, 4, 128, 241, 149, 0, 93, 154, 82, 0, 146, 255, 99, 57, 57, 247, 120, 185, 201, 183, 102, 10, 66, 221, 252, 235, 33, 64, 60, 69, 250, 119, 211, 223, 118, 189, 253, 229, 194, 13, 230, 100, 111, 209, 71, 90, 217, 141, 40, 196, 171, 168, 118, 252, 16, 192, 124, 148, 41, 109, 126, 234, 85, 219, 95, 122, 167, 217, 196, 199, 231, 219, 77, 100, 190, 106, 253, 225, 180, 190, 193, 0, 76, 181, 254, 210, 241, 196, 76, 50, 158, 234, 120, 116, 136, 75, 52, 192, 192, 6, 16, 9, 0, 137, 110, 112, 246, 55, 14, 204, 135, 140, 93, 226, 121, 120, 0, 112, 2, 165, 151, 57, 96, 215, 201, 178, 237, 229, 193, 76, 145, 83, 87, 17, 121, 130, 192, 21, 116, 6, 252, 97, 219, 72, 173, 174, 227, 26, 128, 206, 197, 51, 31, 122, 29, 187, 60, 132, 168, 148, 90, 39, 219, 87, 117, 178, 210, 99, 121, 43, 116, 82, 21, 209, 134, 11, 3, 24, 117, 15, 222, 207, 206, 41, 242, 2, 150, 44, 174, 28, 218, 155, 181, 71, 196, 137, 193, 135, 105, 16, 172, 54, 79, 115, 79, 192, 207, 130, 21, 195, 213, 37, 244, 50, 82, 36, 62, 236, 31, 79, 193, 244, 166, 96, 239, 250, 238, 181, 65, 254, 193, 246, 135, 204, 94, 71, 6, 198, 168, 141, 48, 0, 228, 153, 70, 86, 4, 28, 87, 208, 182, 82, 12, 93, 32, 70, 176, 196, 176, 106, 36, 30, 166, 151, 128, 33, 89, 28, 171, 26, 120, 184, 227, 229, 5, 106, 165, 100, 57, 82, 248, 165, 3, 172, 98, 114, 235, 68, 178, 80, 228, 66, 139, 50, 107, 235, 68, 148, 115, 127, 111, 199, 8, 95, 64, 190, 239, 90, 232, 64, 0, 6, 234, 225, 143, 45, 171, 9, 242, 88, 109, 135, 246, 54, 31, 158, 46, 196, 2, 189, 147, 152, 70, 147, 170, 150, 134, 77, 87, 165, 64, 134, 254, 202, 193, 190, 200, 89, 21, 217, 241, 229, 110, 154, 16, 15, 20, 111, 112, 183, 208, 75, 130, 111, 201, 84, 41, 9, 133, 8, 7, 224, 162, 168, 20, 118, 191, 48, 134, 215, 129, 68, 223, 44, 193, 132, 2, 94, 177, 33, 166, 248, 249, 106, 16, 36, 231, 134, 245, 48, 213, 23, 155, 109, 206, 95, 77, 211, 49, 193, 95, 6, 63, 113, 52, 75, 163, 225, 78, 242, 245, 34, 153, 240, 53, 187, 224, 205, 223, 173, 78, 196, 129, 100, 150, 139, 157, 111, 145, 145, 176, 203, 100, 190, 115, 50, 94, 43, 137, 96, 175, 169, 91, 204, 155, 101, 35, 121, 68, 254, 116, 65, 85, 63, 75, 187, 28, 104, 224, 7, 117, 149, 129, 209, 50, 89, 60, 199, 215, 117, 147, 205, 221, 36, 39, 103, 69, 5, 91, 43, 115, 26, 131, 98, 153, 144, 123, 149, 82, 120, 45, 177, 229, 37, 3, 134, 3, 25, 25, 184, 6, 41, 142, 180, 82, 218, 18, 152, 89, 155, 83, 237, 55, 171, 31, 193, 37, 232, 246, 138, 105, 215, 81, 37, 35, 15, 80, 198, 146, 21, 41, 18, 128, 242, 250, 32, 56, 47, 150, 116, 193, 46, 178, 84, 7, 39, 124, 147, 132, 29, 94, 255, 48, 164, 66, 255, 9, 228, 33, 195, 122, 6, 125, 64, 113, 90, 186, 179, 51, 52, 90, 224, 112, 204, 14, 92, 37, 179, 184, 62, 169, 189, 97, 143, 199, 179, 212, 55, 196, 106, 26, 201, 36, 192, 253, 157, 170, 209, 155, 153, 2, 232, 152, 154, 107, 233, 138, 245, 110, 208, 41, 38, 7, 216, 79, 185, 21, 17, 47, 80, 0, 116, 242, 11, 247, 93, 85, 116, 81, 108, 129, 246, 103, 41, 56, 161, 167, 108, 143, 107, 93, 165, 115, 215, 33, 66, 113, 122, 49, 89, 38, 225, 162, 94, 221, 169, 44, 81, 225, 195, 233, 14, 65, 188, 17, 86, 245, 52, 185, 69, 2, 179, 210, 185, 45, 211, 134, 178, 166, 115, 53, 239, 161, 187, 176, 206, 216, 31, 191, 63, 65, 193, 192, 150, 237, 9, 132, 13, 147, 243, 87, 148, 116, 213, 205, 43, 243, 242, 188, 76, 28, 49, 49, 23, 25, 240, 67, 227, 120, 46, 124, 153, 165, 127, 13, 91, 250, 140, 65, 79, 67, 59, 49, 37, 124, 125, 245, 226, 224, 150, 193, 165, 6, 92, 189, 189, 114, 199, 239, 13, 11, 78, 42, 4, 195, 24, 115, 23, 231, 32, 232, 201, 24, 166, 12, 113, 53, 46, 6, 126, 74, 245, 144, 37, 22, 63, 36, 29, 149, 11, 229, 83, 109, 7, 78, 199, 22, 129, 204, 162, 118, 44, 133, 11, 234, 253, 12, 40, 110, 150, 187, 80, 66, 126, 16, 121, 32, 36, 237, 19, 235, 217, 50, 94, 253, 46, 25, 54, 124, 191, 67, 128, 143, 42, 184, 117, 108, 218, 112, 116, 123, 163, 187, 1, 209, 135, 24, 107, 156, 168, 193, 71, 247, 36, 117, 246, 4, 6, 51, 32, 147, 42, 170, 142, 101, 142, 216, 148, 9, 170, 154, 108, 165, 208, 106, 179, 236, 100, 17, 214, 232, 158, 145, 58, 210, 148, 100, 65, 255, 69, 232, 172, 194, 200, 56, 80, 66, 244, 90, 42, 3, 244, 123, 171, 22, 102, 1, 134, 9, 165, 208, 173, 136, 221, 156, 4, 57, 185, 34, 149, 106, 140, 21, 227, 60, 35, 1, 107, 176, 74, 109, 81, 66, 147, 172, 91, 32, 251, 21, 168, 167, 188, 93, 142, 159, 188, 16, 134, 67, 51, 137, 234, 158, 123, 112, 31, 186, 28, 160, 137, 8, 7, 202, 94, 190, 250, 24, 169, 229, 130, 232, 112, 166, 225, 153, 46, 29, 148, 108, 241, 111, 97, 103, 125, 32, 21, 119, 25, 185, 241, 35, 116, 211, 138, 35, 11, 140, 1, 50, 178, 91, 134, 31, 89, 69, 22, 53, 119, 150, 81, 48, 39, 29, 224, 77, 102, 117, 139, 139, 40, 32, 17, 153, 24, 17, 228, 3, 142, 9, 43, 147, 22, 88, 113, 105, 213, 11, 252, 157, 187, 174, 53, 201, 193, 239, 146, 244, 163, 122, 203, 41, 99, 32, 211, 22, 29, 32, 147, 13, 142, 239, 67, 44, 69, 185, 0, 18, 242, 222, 11, 86, 211, 59, 104, 196, 181, 152, 143, 248, 62, 42, 193, 1, 88, 157, 77, 37, 227, 81, 165, 213, 176, 198, 92, 178, 15, 200, 176, 67, 190, 21, 168, 146, 219, 164, 0, 168, 147, 110, 132, 1, 72, 131, 228, 128, 52, 183, 124, 198, 223, 172, 123, 135, 244, 217, 13, 246, 241, 207, 7, 149, 50, 180, 21, 206, 254, 34, 64, 200, 235, 210, 217, 43, 28, 171, 8, 111, 66, 96, 122, 29, 178, 7, 31, 150, 156, 42, 26, 16, 42, 117, 8, 141, 189, 104, 175, 27, 159, 237, 255, 232, 62, 221, 210, 6, 138, 159, 14, 199, 115, 146, 70, 143, 242, 80, 233, 9, 182, 197, 191, 70, 246, 98, 66, 216, 11, 123, 31, 236, 123, 39, 144, 67, 118, 202, 86, 217, 24, 86, 20, 21, 245, 34, 247, 186, 201, 134, 65, 169, 196, 231, 87, 152, 62, 97, 122, 38, 69, 180, 26, 81, 100, 88, 175, 203, 26, 107, 1, 209, 180, 202, 141, 4, 254, 108, 129, 190, 124, 23, 214, 130, 213, 6, 154, 17, 9, 204, 169, 47, 142, 113, 161, 125, 89, 56, 230, 112, 129, 212, 189, 164, 89, 145, 95, 107, 253, 37, 251, 80, 174, 134, 57, 230, 71, 96, 211, 74, 226, 191, 103, 45, 9, 49, 20, 141, 205, 246, 134, 236, 194, 62, 102, 23, 155, 67, 50, 74, 18, 164, 52, 20, 149, 193, 121, 75, 253, 217, 224, 74, 157, 179, 202, 11, 73, 63, 224, 175, 9, 228, 182, 51, 193, 218, 108, 140, 217, 141, 107, 243, 41, 170, 215, 184, 109, 9, 250, 187, 123, 28, 254, 94, 4, 116, 24, 193, 28, 106, 54, 71, 147, 229, 246, 248, 241, 143, 163, 219, 146, 137, 12, 6, 240, 226, 7, 207, 24, 234, 243, 108, 0, 120, 104, 189, 104, 203, 153, 201, 109, 142, 89, 214, 89, 59, 244, 210, 187, 164, 135, 156, 122, 42, 206, 6, 108, 97, 197, 73, 145, 78, 24, 204, 168, 7, 224, 221, 209, 48, 254, 29, 67, 34, 1, 144, 220, 143, 43, 109, 52, 56, 200, 150, 169, 17, 236, 11, 252, 209, 36, 155, 147, 36, 4, 48, 13, 172, 29, 178, 65, 206, 245, 57, 7, 228, 239, 210, 132, 79, 68, 219, 165, 174, 169, 132, 212, 11, 236, 243, 130, 195, 118, 57, 109, 137, 186, 208, 62, 202, 14, 138, 60, 6, 86, 116, 129, 172, 242, 27, 124, 14, 184, 68, 81, 195, 59, 124, 98, 214, 22, 50, 47, 218, 125, 181, 77, 125, 0, 170, 53, 202, 202, 10, 227, 195, 167, 32, 230, 102, 193, 187, 80, 246, 42, 143, 48, 167, 17, 129, 246, 5, 195, 134, 79, 251, 148, 55, 84, 215, 101, 73, 52, 134, 60, 65, 211, 14, 226, 131, 243, 136, 83, 3, 246, 249, 130, 137, 71, 141, 250, 152, 45, 20, 92, 98, 248, 223, 50, 149, 86, 182, 191, 107, 178, 14, 96, 1, 120, 83, 109, 65, 165, 174, 171, 166, 91, 6, 51, 72, 123, 128, 169, 104, 194, 53, 154, 59, 122, 16, 111, 220, 253, 113, 207, 131, 236, 170, 244, 16, 176, 188, 9, 234, 126, 78, 210, 169, 162, 105, 165, 138, 179, 56, 233, 48, 51, 170, 188, 215, 233, 186, 145, 18, 54, 209, 203, 75, 92, 158, 198, 58, 10, 120, 51, 52, 244, 55, 117, 188, 177, 145, 41, 173, 98, 110, 28, 74, 244, 141, 60, 198, 80, 174, 246, 95, 120, 176, 247, 149, 91, 22, 218, 94, 113, 108, 250, 0, 200, 17, 127, 144, 206, 107, 9, 139, 229, 206, 233, 44, 253, 100, 155, 142, 72, 20, 118, 157, 254, 144, 236, 79, 219, 33, 174, 104, 14, 217, 193, 249, 59, 28, 238, 207, 106, 38, 25, 6, 75, 32, 88, 124, 158, 30, 98, 60, 34, 172, 35, 163, 216, 134, 111, 198, 166, 120, 54, 109, 118, 250, 86, 31, 6, 27, 5, 81, 182, 187, 226, 162, 43, 80, 61, 35, 235, 127, 28, 113, 172, 157, 225, 69, 2, 9, 94, 11, 117, 103, 40, 189, 236, 131, 75, 136, 12, 60, 112, 66, 159, 208, 178, 200, 175, 37, 217, 225, 97, 130, 113, 221, 120, 69, 149, 8, 155, 10, 107, 183, 247, 75, 108, 165, 115, 121, 133, 46, 35, 11, 18, 59, 5, 5, 31, 102, 199, 163, 159, 112, 58, 19, 229, 72, 185, 188, 120, 198, 252, 213, 139, 7, 68, 33, 139, 255, 154, 14, 229, 156, 23, 2, 129, 169, 220, 13, 222, 23, 70, 251, 249, 106, 81, 145, 11, 38, 185, 108, 97, 133, 15, 27, 180, 3, 179, 138, 129, 132, 234, 199, 28, 42, 194, 246, 31, 201, 124, 189, 160, 217, 209, 19, 53, 204, 199, 181, 194, 149, 166, 142, 223, 241, 81, 154, 26, 68, 151, 41, 188, 90, 32, 208, 162, 247, 39, 43, 139, 64, 145, 170, 245, 56, 210, 102, 166, 86, 205, 54, 225, 128, 151, 208, 125, 131, 204, 124, 175, 67, 44, 11, 198, 180, 230, 51, 96, 122, 30, 212, 104, 225, 105, 213, 104, 166, 37, 42, 72, 184, 90, 67, 184, 20, 62, 83, 127, 162, 165, 72, 147, 219, 30, 23, 12, 215, 100, 101, 172, 87, 108, 46, 154, 157, 227, 1, 164, 46, 254, 50, 176, 155, 39, 230, 243, 36, 169, 17, 141, 100, 223, 68, 196, 200, 144, 39, 37, 154, 252, 70, 211, 122, 69, 94, 74, 12, 36, 224, 193, 39, 66, 245, 15, 17, 157, 254, 38, 162, 51, 11, 213, 83, 116, 216, 206, 23, 14, 4, 204, 128, 247, 192, 199, 4, 33, 169, 186, 117, 231, 31, 18, 195, 225, 185, 58, 22, 196, 57, 23, 197, 112, 17, 115, 45, 120, 250, 109, 147, 116, 133, 129, 68, 170, 73, 60, 59, 58, 182, 18, 194, 225, 75, 250, 59, 172, 151, 228, 238, 198, 181, 73, 27, 154, 238, 125, 222, 1, 9, 211, 17, 28, 144, 53, 8, 102, 12, 121, 73, 180, 146, 61, 226, 64, 77, 22, 154, 93, 141, 56, 68, 61, 65, 61, 26, 41, 32, 18, 19, 12, 237, 175, 159, 130, 7, 80, 17, 176, 104, 146, 7, 178, 13, 131, 14, 17, 110, 41, 100, 171, 214, 92, 131, 187, 184, 45, 39, 17, 46, 24, 143, 4, 142, 146, 225, 225, 143, 131, 95, 65, 127, 64, 58, 87, 205, 141, 120, 246, 189, 17, 0, 252, 254, 231, 37, 76, 71, 7, 171, 92, 227, 247, 196, 133, 212, 211, 20, 103, 109, 4, 77, 56, 62, 60, 227, 229, 55, 65, 143, 126, 163, 198, 85, 187, 241, 95, 116, 132, 34, 20, 234, 153, 211, 106, 192, 144, 104, 112, 18, 131, 232, 80, 180, 202, 178, 238, 64, 228, 35, 250, 236, 188, 178, 67, 140, 158, 187, 164, 18, 188, 27, 249, 67, 94, 91, 71, 3, 196, 103, 222, 127, 153, 23, 112, 252, 55, 113, 197, 22, 31, 84, 186, 253, 218, 242, 39, 232, 116, 246, 142, 219, 140, 107, 85, 10, 226, 137, 151, 115, 242, 6, 166, 179, 68, 47, 80, 100, 148, 160, 101, 219, 89, 28, 125, 180, 28, 232, 26, 227, 234, 141, 225, 18, 223, 106, 109, 0, 7, 225, 103, 41, 193, 96, 43, 242, 206, 192, 50, 110, 39, 187, 177, 241, 184, 80, 40, 163, 147, 130, 55, 99, 218, 9, 192, 169, 157, 123, 22, 129, 220, 254, 30, 118, 32, 49, 76, 232, 255, 194, 113, 153, 79, 137, 156, 100, 13, 162, 96, 155, 105, 176, 159, 81, 21, 120, 210, 200, 53, 145, 169, 55, 212, 244, 24, 26, 113, 70, 57, 9, 203, 202, 143, 148, 190, 118, 22, 76, 210, 58, 92, 23, 33, 110, 6, 250, 95, 3, 103, 223, 131, 219, 102, 135, 43, 20, 124, 179, 65, 100, 236, 109, 117, 39, 199, 101, 238, 202, 5, 103, 167, 137, 30, 164, 154, 214, 200, 89, 146, 147, 158, 76, 170, 105, 179, 73, 208, 65, 188, 47, 85, 213, 232, 30, 207, 144, 53, 18, 106, 3, 54, 209, 3, 209, 104, 173, 123, 183, 62, 46, 117, 90, 172, 157, 181, 117, 252, 125, 72, 11, 42, 234, 98, 214, 80, 46, 143, 44, 122, 31, 193, 78, 109, 225, 129, 148, 217, 190, 20, 206, 141, 129, 149, 225, 204, 69, 171, 33, 195, 123, 252, 54, 114, 155, 71, 159, 44, 209, 10, 220, 246, 70, 192, 122, 105, 15, 113, 212, 224, 80, 144, 33, 215, 60, 214, 119, 84, 6, 168, 24, 201, 202, 51, 52, 8, 199, 123, 153, 253, 213, 152, 186, 167, 206, 92, 32, 169, 53, 219, 212, 166, 121, 198, 131, 95, 146, 229, 11, 146, 43, 112, 224, 134, 189, 110, 216, 90, 32, 228, 85, 83, 91, 184, 229, 244, 177, 178, 247, 168, 28, 196, 178, 243, 100, 34, 128, 106, 232, 218, 219, 215, 216, 87, 186, 192, 46, 111, 102, 111, 27, 6, 229, 233, 246, 144, 64, 119, 189, 95, 211, 215, 109, 202, 86, 223, 33, 160, 104, 17, 224, 223, 126, 96, 0, 213, 44, 186, 217, 236, 100, 93, 104, 176, 212, 210, 56, 32, 101, 205, 28, 11, 6, 95, 251, 209, 232, 12, 107, 182, 231, 64, 129, 68, 65, 110, 67, 137, 5, 100, 167, 145, 36, 133, 187, 35, 43, 77, 150, 129, 198, 82, 234, 220, 170, 168, 205, 15, 132, 186, 88, 5, 78, 80, 20, 44, 103, 202, 194, 36, 149, 217, 148, 212, 103, 64, 114, 46, 214, 32, 18, 36, 93, 129, 48, 177, 201, 168, 0, 137, 192, 55, 156, 172, 226, 87, 45, 63, 240, 88, 65, 12, 121, 22, 124, 6, 8, 87, 182, 161, 180, 87, 215, 226, 144, 190, 229, 12, 123, 62, 249, 14, 177, 133, 196, 193, 37, 50, 161, 83, 156, 233, 128, 162, 167, 26, 114, 112, 95, 252, 115, 64, 243, 140, 176, 41, 220, 155, 105, 105, 47, 7, 118, 96, 244, 98, 67, 34, 145, 166, 175, 166, 223, 195, 3, 194, 35, 243, 59, 68, 24, 245, 166, 161, 234, 14, 121, 172, 1, 142, 157, 105, 246, 173, 212, 14, 11, 184, 212, 187, 133, 140, 122, 190, 165, 233, 148, 156, 126, 175, 58, 64, 91, 67, 124, 199, 38, 132, 191, 150, 93, 53, 135, 147, 224, 134, 4, 20, 135, 62, 17, 247, 251, 18, 251, 190, 75, 177, 68, 105, 131, 38, 176, 194, 169, 197, 20, 103, 75, 112, 0, 35, 34, 166, 130, 115, 151, 220, 190, 6, 169, 185, 164, 56, 14, 121, 13, 78, 166, 131, 99, 94, 57, 217, 200, 235, 86, 46, 76, 77, 20, 40, 73, 52, 72, 50, 245, 196, 59, 193, 6, 25, 120, 42, 75, 17, 229, 190, 218, 25, 28, 20, 137, 21, 126, 76, 244, 82, 205, 135, 86, 127, 119, 248, 147, 16, 168, 178, 127, 3, 192, 138, 57, 139, 1, 249, 9, 63, 10, 119, 83, 83, 3, 230, 194, 13, 249, 235, 246, 34, 92, 165, 92, 55, 251, 48, 177, 251, 236, 227, 34, 124, 60, 222, 117, 76, 163, 190, 192, 54, 200, 62, 51, 136, 114, 206, 70, 16, 187, 107, 140, 105, 142, 9, 251, 53, 236, 30, 143, 236, 169, 96, 196, 90, 0, 228, 52, 33, 87, 67, 112, 54, 27, 42, 204, 164, 113, 163, 186, 217, 107, 197, 47, 76, 21, 49, 98, 176, 227, 144, 236, 110, 43, 57, 243, 104, 97, 59, 58, 48, 172, 84, 193, 103, 140, 45, 254, 226, 179, 79, 26, 27, 16, 208, 62, 222, 105, 22, 56, 4, 219, 67, 42, 186, 142, 113, 162, 162, 224, 178, 115, 245, 128, 221, 194, 5, 13, 52, 108, 95, 54, 12, 226, 37, 130, 184, 38, 14, 136, 32, 28, 43, 132, 25, 126, 69, 79, 113, 70, 14, 153, 45, 3, 82, 233, 253, 19, 198, 10, 233, 213, 133, 52, 152, 217, 146, 2, 147, 13, 102, 45, 80, 119, 254, 163, 164, 113, 161, 125, 79, 199, 185, 88, 144, 72, 233, 21, 6, 125, 231, 23, 8, 151, 49, 152, 154, 119, 37, 130, 196, 194, 200, 151, 24, 223, 184, 25, 215, 215, 193, 224, 8, 73, 73, 244, 201, 117, 209, 217, 196, 21, 239, 114, 161, 138, 250, 248, 240, 190, 225, 219, 50, 191, 58, 232, 218, 126, 243, 50, 28, 232, 161, 156, 192, 60, 97, 161, 23, 4, 77, 54, 148, 232, 42, 140, 80, 224, 103, 9, 166, 101, 20, 14, 148, 138, 81, 64, 129, 70, 78, 235, 132, 67, 48, 227, 194, 205, 246, 154, 169, 100, 127, 12, 231, 111, 88, 23, 191, 63, 251, 4, 111, 236, 137, 55, 122, 240, 209, 166, 184, 132, 186, 10, 138, 42, 194, 197, 48, 243, 206, 219, 79, 53, 145, 24, 100, 119, 116, 128, 99, 12, 17, 173, 79, 74, 222, 170, 193, 228, 22, 108, 137, 218, 186, 133, 160, 193, 190, 131, 202, 160, 182, 236, 87, 222, 197, 25, 89, 59, 3, 59, 224, 228, 72, 83, 187, 12, 38, 156, 224, 171, 23, 35, 234, 206, 56, 34, 132, 9, 25, 224, 28, 15, 27, 31, 122, 206, 89, 66, 46, 184, 212, 69, 112, 93, 153, 12, 68, 44, 132, 116, 115, 128, 127, 45, 128, 248, 30, 123, 214, 86, 25, 214, 46, 40, 31, 180, 238, 34, 71, 78, 85, 178, 19, 28, 237, 133, 16, 183, 58, 220, 88, 117, 171, 40, 50, 57, 229, 39, 28, 162, 89, 224, 32, 48, 42, 9, 70, 69, 200, 114, 164, 18, 80, 139, 255, 8, 245, 214, 198, 186, 112, 109, 51, 40, 154, 173, 3, 248, 41, 252, 186, 21, 152, 99, 162, 138, 72, 74, 98, 234, 124, 57, 135, 125, 75, 184, 107, 91, 35, 89, 149, 170, 101, 45, 255, 52, 194, 231, 8, 71, 53, 151, 232, 147, 106, 193, 32, 171, 218, 107, 175, 130, 147, 58, 199, 14, 166, 56, 84, 245, 182, 131, 210, 77, 140, 145, 67, 39, 36, 81, 74, 50, 59, 175, 65, 108, 69, 176, 119, 111, 5, 220, 228, 215, 249, 151, 25, 193, 88, 104, 245, 3, 166, 241, 56, 24, 85, 116, 252, 110, 31, 45, 31, 53, 135, 25, 184, 240, 2, 165, 102, 56, 14, 203, 151, 32, 183, 137, 174, 112, 232, 137, 49, 192, 76, 194, 48, 51, 3, 18, 202, 128, 171, 244, 35, 28, 200, 1, 21, 28, 132, 83, 66, 47, 117, 147, 113, 37, 106, 80, 118, 217, 100, 229, 126, 182, 183, 183, 81, 65, 33, 181, 235, 223, 130, 118, 54, 177, 90, 10, 187, 200, 6, 102, 189, 93, 76, 254, 55, 69, 103, 130, 201, 57, 98, 207, 5, 152, 231, 64, 101, 0, 222, 78, 244, 13, 38, 248, 63, 163, 31, 175, 155, 203, 77, 249, 24, 139, 52, 224, 68, 199, 157, 103, 40, 131, 224, 242, 137, 225, 181, 131, 29, 128, 229, 242, 92, 42, 58, 85, 101, 69, 120, 167, 86, 99, 57, 220, 94, 231, 162, 99, 132, 221, 55, 37, 174, 194, 195, 194, 178, 232, 61, 38, 66, 42, 168, 182, 23, 106, 241, 198, 192, 217, 215, 50, 59, 225, 217, 8, 24, 147, 240, 54, 209, 158, 154, 47, 7, 212, 225, 38, 19, 4, 241, 170, 42, 2, 107, 13, 240, 77, 158, 228, 103, 237, 64, 173, 177, 143, 48, 208, 217, 140, 31, 108, 229, 140, 70, 10, 51, 122, 64, 75, 12, 145, 211, 165, 169, 145, 240, 228, 255, 115, 84, 244, 84, 125, 231, 86, 8, 52, 248, 112, 145, 221, 45, 53, 9, 92, 53, 66, 180, 172, 242, 22, 113, 106, 211, 138, 42, 63, 66, 178, 2, 160, 86, 191, 169, 237, 86, 87, 70, 78, 62, 1, 213, 97, 167, 104, 63, 60, 222, 61, 77, 55, 70, 198, 23, 8, 135, 250, 188, 93, 66, 134, 227, 192, 20, 182, 81, 129, 108, 60, 88, 141, 93, 205, 132, 52, 179, 95, 168, 181, 39, 38, 7, 206, 107, 214, 181, 101, 190, 56, 89, 60, 178, 166, 107, 99, 154, 3, 129, 39, 242, 99, 206, 124, 171, 178, 132, 138, 177, 200, 26, 11, 83, 208, 126, 142, 130, 38, 169, 82, 225, 242, 213, 101, 234, 176, 14, 229, 79, 19, 58, 72, 4, 201, 238, 77, 94, 151, 153, 10, 128, 254, 183, 134, 62, 42, 170, 39, 226, 231, 213, 223, 31, 74, 61, 94, 199, 136, 181, 153, 45, 48, 157, 50, 0, 60, 251, 155, 235, 37, 42, 168, 203, 8, 246, 116, 56, 66, 99, 34, 92, 170, 73, 29, 32, 185, 65, 23, 178, 124, 2, 254, 140, 196, 162, 33, 208, 190, 145, 237, 96, 137, 104, 94, 114, 2, 37, 83, 2, 59, 241, 115, 1, 208, 157, 193, 165, 118, 17, 156, 91, 135, 158, 192, 108, 229, 212, 236, 9, 28, 232, 75, 152, 109, 156, 152, 207, 180, 242, 34, 100, 12, 112, 243, 72, 166, 219, 31, 150, 89, 73, 243, 4, 219, 157, 46, 75, 247, 234, 143, 10, 88, 150, 67, 124, 219, 10, 6, 26, 15, 78, 177, 77, 114, 221, 121, 214, 54, 107, 254, 196, 239, 216, 168, 230, 230, 28, 94, 69, 11, 67, 161, 37, 39, 191, 18, 246, 116, 211, 14, 236, 250, 100, 23, 87, 174, 118, 164, 193, 229, 87, 38, 151, 122, 79, 217, 111, 231, 135, 82, 222, 183, 14, 208, 217, 233, 1, 121, 21, 121, 251, 162, 112, 186, 24, 65, 154, 7, 50, 186, 246, 24, 173, 198, 186, 89, 38, 117, 87, 26, 10, 94, 50, 193, 16, 135, 68, 167, 148, 251, 144, 115, 60, 48, 28, 187, 104, 161, 255, 192, 223, 214, 21, 143, 212, 214, 194, 44, 128, 162, 174, 96, 166, 91, 17, 247, 83, 230, 57, 106, 16, 104, 142, 57, 78, 235, 132, 164, 183, 174, 244, 56, 103, 113, 118, 96, 65, 40, 163, 7, 30, 134, 159, 76, 247, 31, 213, 30, 211, 203, 74, 188, 201, 38, 148, 123, 234, 157, 17, 192, 247, 26, 71, 201, 37, 226, 94, 89, 80, 180, 133, 94, 22, 94, 64, 39, 236, 227, 143, 163, 140, 126, 160, 125, 29, 99, 25, 56, 107, 89, 224, 93, 213, 48, 6, 174, 250, 127, 228, 165, 247, 193, 169, 53, 114, 176, 103, 191, 116, 118, 23, 97, 219, 73, 32, 245, 48, 81, 200, 42, 64, 190, 25, 126, 59, 198, 254, 136, 198, 30, 154, 159, 115, 133, 150, 85, 84, 81, 198, 220, 150, 67, 242, 28, 203, 189, 175, 18, 152, 74, 40, 37, 157, 101, 110, 50, 144, 94, 53, 103, 188, 60, 29, 26, 46, 38, 83, 193, 5, 41, 184, 184, 43, 65, 187, 143, 212, 123, 83, 233, 166, 99, 246, 45, 86, 5, 154, 252, 76, 189, 21, 225, 45, 46, 102, 104, 8, 225, 163, 7, 24, 22, 178, 179, 22, 211, 176, 8, 21, 171, 190, 105, 171, 201, 153, 254, 143, 184, 143, 79, 44, 99, 68, 83, 14, 221, 163, 40, 137, 30, 178, 150, 183, 168, 122, 148, 165, 126, 56, 195, 175, 162, 202, 69, 219, 175, 193, 166, 186, 252, 212, 135, 62, 240, 153, 66, 35, 240, 111, 129, 19, 45, 140, 227, 201, 185, 173, 12, 198, 97, 228, 10, 41, 101, 107, 165, 106, 140, 26, 165, 166, 212, 16, 53, 231, 73, 16, 53, 1, 76, 73, 68, 160, 75, 156, 36, 124, 36, 235, 158, 89, 98, 139, 130, 113, 19, 7, 232, 95, 112, 121, 125, 246, 130, 143, 5, 190, 216, 150, 246, 149, 254, 80, 102, 35, 174, 82, 169, 90, 189, 234, 242, 87, 91, 255, 78, 98, 197, 208, 42, 141, 31, 17, 233, 217, 151, 135, 31, 87, 71, 132, 255, 79, 98, 62, 168, 221, 172, 247, 225, 46, 155, 228, 196, 76, 95, 161, 68, 233, 203, 192, 236, 146, 149, 43, 85, 98, 110, 35, 242, 116, 216, 226, 78, 157, 114, 40, 157, 241, 33, 12, 14, 205, 192, 201, 12, 219, 255, 249, 6, 105, 86, 80, 101, 184, 26, 56, 101, 227, 25, 69, 140, 68, 35, 245, 46, 110, 221, 50, 51, 237, 20, 23, 174, 4, 137, 44, 207, 0, 201, 52, 147, 202, 111, 190, 72, 177, 228, 97, 210, 163, 150, 154, 2, 241, 97, 151, 93, 210, 199, 127, 218, 57, 45, 91, 96, 194, 160, 131, 205, 120, 102, 209, 51, 28, 68, 48, 199, 130, 77, 209, 13, 204, 141, 240, 217, 165, 87, 56, 119, 167, 53, 207, 74, 106, 163, 27, 100, 6, 252, 238, 114, 63, 40, 162, 86, 5, 153, 91, 98, 106, 124, 126, 91, 105, 173, 98, 74, 222, 85, 125, 64, 213, 102, 107, 3, 158, 243, 8, 167, 224, 50, 213, 167, 203, 19, 16, 235, 4, 43, 104, 115, 28, 1, 168, 41, 94, 241, 67, 161, 140, 45, 89, 118, 172, 162, 117, 224, 95, 245, 214, 214, 220, 117, 32, 163, 250, 84, 55, 174, 20, 7, 238, 213, 19, 177, 36, 105, 6, 75, 15, 72, 154, 18, 64, 85, 108, 213, 56, 86, 240, 124, 142, 134, 82, 100, 199, 198, 243, 12, 146, 80, 148, 251, 223, 79, 153, 181, 188, 100, 167, 228, 175, 227, 241, 164, 28, 120, 133, 170, 177, 202, 232, 101, 171, 207, 2, 32, 212, 173, 147, 117, 171, 218, 83, 216, 241, 94, 3, 103, 187, 230, 26, 168, 180, 159, 4, 173, 108, 61, 76, 182, 54, 115, 135, 144, 2, 39, 81, 126, 253, 172, 101, 144, 19, 3, 202, 12, 234, 87, 11, 222, 188, 82, 204, 27, 81, 216, 250, 163, 94, 103, 73, 149, 233, 251, 140, 172, 85, 138, 51, 203, 121, 30, 64, 184, 120, 46, 233, 199, 59, 106, 115, 123, 102, 145, 129, 213, 216, 74, 92, 11, 166, 50, 79, 3, 13, 80, 245, 241, 248, 193, 208, 78, 77, 229, 21, 67, 229, 192, 61, 115, 213, 93, 52, 225, 217, 147, 236, 135, 88, 184, 240, 49, 182, 109, 95, 67, 184, 204, 181, 176, 213, 34, 36, 149, 98, 143, 193, 225, 48, 180, 219, 69, 244, 64, 96, 234, 83, 5, 113, 122, 23, 115, 55, 87, 212, 130, 154, 96, 152, 92, 29, 136, 202, 217, 58, 236, 195, 153, 17, 14, 13, 213, 145, 36, 159, 163, 58, 191, 3, 11, 124, 34, 155, 237, 58, 57, 3, 144, 222, 25, 234, 107, 15, 183, 234, 160, 27, 44, 77, 149, 128, 57, 87, 142, 236, 113, 192, 44, 95, 140, 168, 65, 170, 167, 167, 38, 131, 33, 140, 27, 10, 248, 16, 71, 99, 115, 210, 177, 65, 198, 48, 11, 13, 1, 247, 24, 222, 248, 24, 73, 117, 11, 249, 29, 226, 114, 41, 64, 147, 58, 10, 52, 76, 19, 128, 25, 96, 78, 56, 108, 40, 200, 163, 225, 39, 179, 7, 84, 210, 59, 167, 133, 135, 35, 177, 111, 9, 96, 25, 142, 26, 71, 203, 43, 18, 176, 75, 224, 206, 24, 157, 10, 0, 133, 216, 218, 121, 210, 52, 164, 86, 148, 80, 18, 156, 150, 18, 197, 44, 74, 110, 158, 202, 194, 40, 132, 234, 166, 98, 208, 166, 193, 25, 225, 231, 118, 0, 136, 194, 251, 212, 237, 49, 94, 92, 250, 222, 143, 52, 229, 213, 147, 96, 189, 214, 182, 11, 149, 41, 202, 15, 64, 33, 216, 207, 177, 186, 8, 104, 161, 240, 145, 252, 200, 39, 45, 17, 161, 97, 92, 19, 73, 212, 7, 244, 26, 121, 77, 143, 178, 161, 48, 158, 113, 14, 2, 65, 152, 91, 51, 229, 240, 117, 52, 69, 236, 248, 75, 195, 136, 161, 56, 0, 23, 112, 252, 156, 183, 148, 116, 31, 215, 235, 78, 32, 227, 131, 219, 238, 212, 252, 43, 42, 128, 55, 12, 182, 80, 113, 168, 229, 158, 225, 54, 105, 162, 106, 41, 139, 28, 74, 213, 152, 209, 193, 3, 150, 77, 235, 193, 20, 105, 99, 66, 169, 242, 111, 229, 169, 14, 6, 26, 138, 220, 112, 172, 16, 75, 232, 233, 186, 153, 185, 253, 168, 242, 85, 202, 128, 167, 112, 84, 210, 132, 250, 61, 132, 1, 125, 51, 232, 128, 164, 2, 53, 141, 55, 237, 54, 114, 104, 0, 129, 0, 193, 109, 124, 129, 83, 48, 234, 47, 210, 47, 50, 95, 62, 156, 180, 113, 73, 81, 202, 149, 63, 161, 102, 201, 28, 165, 21, 108, 118, 205, 67, 107, 1, 242, 249, 196, 248, 179, 171, 198, 129, 145, 136, 228, 121, 198, 99, 87, 83, 133, 192, 17, 176, 12, 81, 54, 19, 66, 108, 58, 203, 110, 50, 112, 189, 12, 124, 32, 108, 70, 3, 184, 2, 11, 57, 206, 188, 255, 33, 137, 78, 63, 170, 63, 236, 212, 38, 102, 226, 116, 148, 26, 22, 30, 220, 80, 0, 244, 42, 166, 19, 192, 1, 151, 213, 35, 69, 244, 40, 88, 47, 251, 77, 95, 95, 77, 88, 40, 37, 119, 122, 50, 235, 233, 158, 215, 48, 199, 214, 84, 232, 211, 139, 193, 220, 144, 193, 94, 223, 110, 90, 146, 145, 98, 176, 143, 66, 215, 70, 157, 227, 114, 24, 187, 64, 249, 185, 134, 81, 219, 11, 187, 148, 239, 34, 232, 15, 29, 132, 225, 157, 46, 100, 93, 168, 237, 161, 86, 129, 132, 59, 67, 32, 58, 231, 132, 191, 42, 194, 2, 45, 50, 22, 180, 120, 142, 49, 191, 153, 215, 200, 224, 118, 235, 211, 196, 116, 27, 45, 116, 240, 68, 85, 168, 162, 100, 58, 10, 82, 102, 116, 177, 52, 16, 153, 61, 221, 111, 245, 128, 163, 191, 101, 108, 13, 58, 102, 171, 160, 161, 170, 129, 12, 197, 172, 228, 29, 225, 174, 214, 114, 97, 65, 160, 66, 90, 250, 229, 36, 204, 142, 163, 106, 182, 120, 67, 199, 184, 80, 147, 5, 167, 59, 117, 16, 135, 89, 69, 171, 210, 17, 226, 147, 117, 58, 33, 60, 80, 78, 103, 65, 79, 221, 48, 40, 148, 165, 149, 169, 106, 174, 50, 174, 186, 228, 122, 103, 65, 100, 3, 252, 57, 16, 176, 193, 199, 52, 103, 50, 146, 89, 87, 218, 84, 108, 175, 13, 195, 161, 111, 69, 128, 6, 191, 152, 120, 143, 177, 211, 94, 130, 41, 47, 136, 158, 165, 217, 25, 65, 234, 139, 212, 146, 51, 216, 59, 224, 4, 97, 77, 223, 128, 248, 95, 81, 39, 225, 183, 242, 69, 191, 48, 37, 177, 24, 119, 11, 227, 80, 254, 109, 164, 229, 55, 101, 88, 89, 168, 113, 244, 176, 100, 126, 79, 164, 212, 180, 241, 82, 196, 39, 81, 185, 106, 20, 3, 132, 98, 158, 244, 6, 125, 8, 77, 234, 34, 142, 170, 146, 224, 189, 127, 215, 124, 34, 24, 17, 243, 7, 74, 146, 166, 128, 179, 6, 98, 114, 190, 79, 67, 219, 171, 197, 129, 213, 239, 132, 144, 44, 234, 52, 230, 16, 94, 220, 92, 136, 0, 186, 244, 229, 53, 148, 233, 73, 249, 152, 217, 100, 6, 196, 77, 97, 138, 6, 5, 41, 196, 19, 142, 92, 46, 110, 54, 151, 156, 156, 177, 129, 2, 62, 200, 189, 193, 181, 93, 68, 60, 90, 149, 84, 203, 83, 201, 26, 18, 52, 156, 65, 179, 59, 3, 125, 19, 204, 236, 61, 163, 85, 36, 237, 47, 144, 140, 87, 154, 95, 60, 0, 22, 37, 155, 6, 7, 0, 176, 46, 247, 159, 37, 173, 224, 210, 12, 217, 248, 79, 132, 93, 138, 135, 78, 17, 227, 18, 45, 252, 48, 58, 254, 85, 36, 176, 69, 114, 1, 92, 207, 85, 193, 254, 112, 204, 78, 157, 146, 103, 123, 196, 100, 10, 46, 184, 161, 162, 78, 144, 141, 50, 86, 252, 50, 235, 184, 151, 55, 73, 187, 10, 37, 50, 198, 0, 207, 155, 104, 37, 137, 196, 54, 132, 15, 22, 93, 114, 237, 90, 250, 96, 61, 18, 152, 194, 63, 239, 16, 92, 110, 63, 209, 229, 27, 61, 154, 245, 208, 226, 145, 184, 219, 48, 187, 2, 193, 78, 24, 51, 81, 34, 172, 109, 33, 8, 23, 232, 115, 57, 152, 233, 140, 200, 196, 108, 8, 65, 251, 72, 68, 76, 181, 220, 62, 34, 119, 9, 126, 13, 186, 100, 214, 191, 149, 154, 131, 254, 200, 126, 152, 142, 103, 127, 57, 81, 255, 99, 129, 250, 33, 25, 183, 235, 134, 117, 115, 108, 95, 28, 86, 141, 217, 180, 116, 61, 201, 51, 90, 59, 160, 254, 213, 93, 21, 55, 204, 97, 62, 113, 100, 6, 107, 57, 64, 201, 157, 228, 173, 229, 35, 61, 235, 102, 161, 14, 189, 164, 112, 76, 75, 127, 18, 231, 145, 130, 79, 66, 150, 63, 30, 164, 181, 68, 176, 81, 217, 135, 54, 172, 66, 60, 232, 8, 206, 224, 245, 102, 177, 243, 64, 87, 233, 193, 244, 95, 68, 78, 255, 14, 144, 223, 147, 32, 36, 230, 212, 218, 185, 120, 243, 3, 64, 139, 233, 70, 90, 136, 5, 171, 221, 87, 98, 15, 43, 200, 131, 182, 75, 81, 139, 243, 233, 218, 246, 61, 246, 189, 204, 39, 168, 208, 131, 142, 200, 109, 158, 159, 54, 35, 91, 244, 135, 204, 241, 171, 25, 55, 255, 101, 15, 169, 221, 208, 223, 109, 244, 74, 78, 126, 25, 199, 151, 191, 110, 7, 74, 60, 169, 101, 212, 84, 228, 234, 187, 204, 110, 158, 131, 28, 21, 186, 158, 193, 129, 10, 199, 206, 160, 140, 85, 209, 196, 9, 167, 6, 157, 187, 234, 179, 190, 131, 250, 100, 34, 13, 98, 40, 94, 92, 80, 253, 7, 188, 233, 45, 45, 253, 101, 65, 250, 138, 64, 231, 109, 103, 163, 213, 33, 183, 99, 129, 181, 119, 96, 30, 234, 220, 121, 7, 109, 255, 191, 243, 188, 128, 33, 88, 16, 143, 190, 7, 175, 181, 7, 136, 203, 156, 61, 136, 2, 69, 232, 15, 168, 44, 87, 109, 95, 162, 79, 8, 203, 107, 170, 255, 6, 142, 43, 24, 69, 126, 184, 121, 213, 43, 132, 164, 198, 90, 213, 28, 144, 14, 208, 129, 24, 87, 170, 144, 6, 210, 3, 76, 220, 223, 12, 223, 191, 33, 42, 214, 218, 4, 236, 194, 78, 55, 215, 50, 24, 189, 64, 174, 166, 176, 110, 190, 23, 1, 240, 177, 109, 233, 48, 246, 116, 99, 168, 128, 246, 212, 113, 10, 168, 40, 72, 17, 184, 129, 191, 38, 158, 23, 192, 155, 21, 229, 218, 137, 168, 21, 5, 65, 28, 231, 85, 4, 162, 146, 77, 99, 228, 4, 175, 0, 27, 51, 79, 18, 111, 97, 103, 172, 198, 6, 91, 139, 38, 66, 197, 242, 219, 5, 14, 8, 127, 229, 156, 139, 219, 109, 240, 174, 20, 236, 133, 43, 9, 16, 154, 83, 150, 171, 193, 155, 217, 243, 153, 236, 53, 153, 145, 224, 243, 157, 117, 96, 254, 115, 134, 149, 101, 59, 101, 15, 198, 164, 71, 7, 151, 178, 173, 211, 235, 229, 9, 9, 216, 99, 178, 234, 127, 134, 80, 226, 219, 50, 22, 218, 153, 150, 38, 209, 194, 32, 66, 149, 30, 149, 124, 77, 60, 85, 118, 172, 161, 20, 91, 231, 157, 210, 37, 69, 134, 33, 41, 44, 94, 151, 67, 239, 251, 3, 113, 169, 83, 73, 192, 111, 144, 160, 228, 150, 146, 175, 125, 222, 155, 123, 120, 75, 181, 150, 133, 17, 143, 51, 247, 178, 66, 113, 249, 92, 118, 95, 180, 201, 132, 159, 86, 91, 191, 124, 12, 73, 198, 125, 183, 26, 228, 56, 235, 78, 33, 22, 9, 155, 187, 49, 250, 236, 170, 144, 254, 195, 101, 129, 204, 91, 228, 232, 83, 34, 133, 250, 46, 165, 21, 160, 235, 156, 158, 172, 126, 180, 15, 106, 81, 212, 178, 143, 108, 132, 145, 237, 39, 123, 72, 143, 134, 212, 135, 27, 181, 113, 35, 239, 62, 130, 93, 164, 198, 100, 252, 46, 187, 226, 50, 86, 186, 179, 196, 12, 114, 191, 240, 54, 83, 30, 201, 49, 217, 127, 202, 74, 23, 109, 216, 68, 15, 233, 13, 104, 156, 230, 200, 214, 101, 233, 175, 45, 5, 172, 142, 11, 77, 59, 228, 0, 66, 239, 70, 115, 148, 7, 67, 156, 0, 219, 132, 98, 27, 9, 144, 144, 30, 53, 134, 115, 149, 61, 197, 154, 111, 239, 224, 80, 8, 112, 195, 96, 237, 218, 127, 219, 175, 24, 53, 17, 216, 165, 180, 141, 129, 29, 101, 54, 56, 100, 229, 159, 192, 145, 52, 2, 153, 108, 127, 155, 32, 254, 200, 17, 46, 107, 205, 54, 29, 73, 214, 178, 101, 9, 180, 115, 31, 88, 253, 161, 26, 155, 120, 10, 213, 21, 61, 170, 228, 187, 227, 229, 20, 13, 78, 254, 11, 124, 55, 50, 212, 53, 166, 57, 186, 207, 11, 213, 242, 19, 215, 140, 210, 48, 136, 185, 131, 193, 183, 132, 145, 191, 195, 179, 86, 138, 83, 78, 219, 176, 27, 23, 80, 193, 113, 109, 148, 119, 97, 141, 92, 177, 70, 159, 13, 162, 139, 226, 84, 187, 120, 201, 21, 43, 242, 165, 195, 138, 70, 31, 24, 41, 58, 171, 25, 33, 30, 148, 108, 195, 238, 74, 70, 117, 66, 159, 139, 32, 185, 29, 159, 14, 174, 35, 224, 103, 147, 56, 1, 125, 46, 177, 13, 15, 3, 210, 81, 64, 203, 182, 202, 93, 111, 154, 2, 2, 86, 44, 152, 8, 167, 132, 60, 182, 67, 198, 182, 59, 84, 227, 96, 138, 251, 2, 21, 239, 58, 230, 57, 146, 193, 221, 12, 196, 61, 207, 231, 98, 11, 4, 177, 246, 216, 157, 89, 172, 178, 170, 175, 209, 162, 131, 47, 188, 103, 192, 165, 115, 97, 209, 252, 98, 231, 65, 187, 46, 16, 110, 192, 45, 167, 91, 57, 155, 96, 143, 39, 54, 55, 180, 107, 144, 184, 96, 68, 85, 87, 192, 17, 40, 90, 175, 225, 73, 82, 213, 27, 132, 105, 207, 130, 108, 238, 253, 31, 9, 225, 127, 214, 181, 236, 100, 148, 115, 164, 35, 73, 14, 16, 234, 43, 172, 86, 134, 180, 41, 169, 247, 54, 159, 144, 53, 44, 127, 207, 23, 253, 167, 50, 123, 106, 3, 74, 109, 111, 6, 105, 58, 228, 41, 2, 35, 131, 31, 117, 123, 73, 250, 146, 154, 175, 173, 76, 76, 196, 238, 132, 163, 150, 146, 219, 219, 162, 17, 80, 195, 1, 218, 225, 161, 23, 203, 47, 33, 130, 142, 104, 196, 107, 96, 40, 22, 79, 138, 143, 242, 139, 17, 13, 26, 49, 232, 163, 53, 24, 253, 191, 27, 53, 110, 165, 218, 243, 64, 82, 172, 181, 41, 86, 38, 50, 91, 32, 139, 109, 78, 246, 77, 178, 120, 213, 175, 168, 119, 85, 63, 220, 60, 161, 201, 134, 51, 147, 129, 22, 230, 17, 123, 201, 180, 236, 130, 33, 64, 141, 142, 12, 201, 155, 226, 224, 151, 19, 253, 200, 162, 85, 156, 199, 249, 221, 157, 217, 185, 123, 36, 209, 173, 203, 130, 132, 217, 6, 18, 248, 105, 46, 201, 184, 214, 35, 26, 85, 104, 33, 158, 236, 154, 152, 193, 82, 146, 188, 134, 42, 198, 199, 161, 4, 182, 101, 172, 233, 217, 160, 119, 161, 2, 90, 189, 238, 44, 85, 141, 207, 17, 249, 162, 228, 140, 189, 155, 68, 199, 162, 0, 132, 149, 176, 161, 112, 217, 249, 30, 64, 124, 242, 238, 62, 5, 87, 48, 254, 192, 199, 77, 152, 131, 116, 175, 242, 42, 211, 29, 157, 15, 182, 203, 230, 173, 217, 218, 88, 177, 68, 11, 33, 110, 198, 0, 105, 207, 231, 126, 70, 112, 244, 48, 89, 31, 101, 149, 200, 80, 177, 197, 120, 228, 183, 140, 107, 113, 148, 66, 159, 249, 136, 175, 156, 119, 43, 167, 238, 171, 11, 20, 101, 203, 192, 18, 167, 199, 29, 251, 102, 76, 232, 240, 168, 229, 75, 93, 95, 228, 194, 163, 91, 45, 178, 60, 161, 107, 85, 229, 36, 214, 247, 122, 140, 102, 109, 158, 125, 93, 248, 250, 188, 104, 44, 4, 222, 138, 241, 141, 40, 203, 30, 217, 206, 190, 170, 131, 112, 1, 69, 65, 14, 85, 36, 244, 2, 205, 80, 101, 222, 204, 48, 231, 92, 211, 65, 7, 227, 18, 31, 115, 153, 150, 78, 41, 226, 101, 210, 13, 110, 156, 132, 29, 245, 109, 49, 141, 108, 77, 166, 30, 11, 52, 79, 198, 110, 30, 15, 49, 55, 48, 13, 23, 185, 127, 78, 123, 135, 67, 15, 112, 114, 38, 222, 58, 98, 160, 206, 51, 76, 172, 101, 138, 116, 230, 163, 165, 233, 145, 62, 14, 124, 232, 137, 116, 177, 16, 22, 226, 104, 163, 35, 74, 61, 203, 245, 215, 72, 251, 49, 65, 7, 77, 7, 6, 138, 248, 242, 40, 136, 207, 167, 248, 67, 30, 30, 136, 55, 159, 249, 37, 174, 247, 63, 39, 253, 106, 206, 229, 75, 69, 189, 151, 181, 237, 72, 64, 125, 125, 232, 145, 140, 5, 99, 41, 42, 34, 117, 161, 73, 35, 72, 40, 188, 200, 69, 218, 45, 5, 149, 3, 137, 122, 109, 28, 57, 220, 58, 248, 252, 221, 14, 6, 21, 190, 98, 192, 220, 163, 225, 169, 23, 1, 133, 25, 85, 34, 126, 242, 240, 22, 158, 123, 116, 121, 129, 90, 72, 137, 80, 197, 206, 210, 141, 232, 107, 126, 235, 147, 34, 192, 217, 34, 110, 226, 16, 91, 2, 36, 156, 26, 187, 34, 68, 135, 197, 228, 157, 229, 166, 149, 134, 41, 163, 123, 119, 92, 136, 33, 73, 41, 246, 241, 122, 172, 240, 245, 6, 233, 221, 207, 2, 65, 153, 58, 47, 74, 210, 112, 19, 215, 194, 139, 148, 53, 188, 199, 134, 143, 188, 37, 27, 27, 0, 106, 213, 176, 59, 56, 180, 90, 175, 191, 202, 177, 181, 124, 101, 249, 87, 12, 177, 136, 127, 99, 141, 23, 131, 241, 241, 51, 40, 251, 127, 172, 55, 185, 112, 200, 105, 211, 95, 230, 55, 128, 199, 59, 150, 209, 84, 43, 66, 147, 102, 177, 240, 2, 51, 21, 170, 129, 145, 154, 228, 251, 62, 199, 21, 217, 126, 2, 9, 72, 23, 123, 67, 77, 145, 188, 116, 239, 164, 9, 180, 17, 229, 93, 167, 200, 35, 53, 20, 148, 11, 90, 7, 128, 38, 149, 96, 76, 211, 162, 86, 247, 47, 219, 153, 228, 208, 174, 1, 77, 130, 206, 8, 56, 77, 178, 126, 103, 64, 66, 173, 130, 178, 15, 157, 82, 151, 6, 31, 32, 24, 254, 116, 177, 125, 94, 103, 50, 23, 88, 167, 177, 178, 127, 154, 65, 221, 58, 221, 59, 226, 100, 212, 90, 195, 98, 94, 191, 30, 232, 150, 153, 106, 253, 109, 235, 75, 64, 207, 222, 250, 116, 71, 33, 65, 213, 195, 126, 156, 152, 66, 192, 144, 40, 227, 151, 193, 175, 99, 224, 91, 60, 164, 255, 6, 122, 7, 67, 247, 68, 73, 212, 29, 46, 88, 182, 8, 140, 159, 12, 53, 10, 134, 178, 137, 239, 153, 185, 79, 82, 248, 233, 246, 212, 236, 69, 141, 78, 223, 143, 137, 36, 152, 203, 115, 15, 73, 227, 247, 216, 141, 74, 85, 92, 252, 219, 11, 86, 24, 36, 132, 246, 133, 77, 210, 94, 247, 210, 48, 169, 100, 17, 141, 75, 195, 158, 42, 251, 39, 47, 60, 157, 65, 57, 125, 28, 71, 111, 42, 158, 47, 14, 42, 28, 117, 50, 96, 232, 48, 42, 244, 34, 57, 12, 138, 203, 106, 250, 25, 67, 23, 176, 220, 128, 5, 19, 7, 102, 171, 23, 9, 30, 96, 230, 35, 15, 34, 132, 122, 139, 178, 231, 226, 252, 122, 142, 51, 52, 11, 84, 228, 93, 72, 237, 102, 129, 75, 238, 112, 182, 84, 130, 158, 130, 41, 139, 174, 56, 166, 174, 139, 242, 44, 145, 148, 133, 123, 42, 62, 163, 116, 84, 154, 57, 28, 58, 32, 154, 34, 151, 21, 127, 143, 122, 136, 139, 252, 101, 165, 227, 105, 4, 244, 58, 116, 125, 45, 98, 76, 103, 94, 178, 138, 217, 234, 42, 40, 152, 61, 28, 185, 62, 43, 88, 177, 3, 57, 129, 36, 0, 238, 63, 194, 253, 71, 206, 114, 243, 137, 92, 79, 175, 23, 62, 120, 193, 114, 13, 142, 244, 4, 131, 205, 14, 186, 248, 29, 212, 164, 52, 12, 111, 31, 124, 143, 212, 208, 173, 96, 133, 27, 194, 239, 242, 62, 141, 119, 203, 52, 113, 243, 31, 84, 235, 5, 5, 64, 191, 252, 81, 217, 200, 232, 68, 61, 213, 171, 145, 221, 224, 102, 138, 6, 53, 167, 130, 6, 206, 196, 226, 4, 174, 108, 86, 154, 134, 37, 59, 110, 9, 191, 10, 117, 191, 133, 114, 72, 86, 93, 113, 19, 75, 34, 46, 2, 185, 169, 224, 240, 13, 200, 128, 24, 118, 36, 233, 120, 115, 6, 192, 92, 12, 228, 224, 111, 192, 137, 188, 16, 155, 62, 198, 60, 154, 52, 196, 125, 70, 58, 33, 43, 11, 168, 35, 190, 161, 124, 108, 153, 90, 186, 113, 57, 176, 154, 172, 202, 179, 55, 179, 115, 45, 183, 90, 4, 216, 112, 48, 228, 230, 219, 58, 70, 142, 78, 74, 9, 135, 22, 40, 70, 146, 224, 171, 128, 68, 8, 228, 90, 35, 220, 41, 184, 91, 212, 34, 57, 143, 189, 6, 215, 17, 90, 143, 19, 92, 97, 0, 32, 3, 71, 160, 179, 249, 172, 83, 31, 79, 228, 235, 186, 237, 88, 60, 223, 16, 150, 62, 200, 199, 30, 185, 44, 207, 192, 77, 194, 159, 154, 169, 139, 30, 66, 92, 141, 190, 237, 210, 202, 206, 242, 79, 195, 207, 22, 106, 63, 29, 195, 112, 209, 66, 25, 0, 132, 115, 0, 202, 40, 194, 111, 241, 33, 135, 53, 223, 250, 204, 154, 93, 179, 199, 141, 86, 243, 91, 194, 109, 181, 226, 69, 138, 254, 216, 121, 193, 63, 120, 2, 134, 176, 156, 166, 74, 11, 81, 70, 173, 20, 22, 53, 20, 94, 78, 223, 122, 51, 83, 235, 222, 40, 243, 124, 92, 42, 236, 168, 151, 228, 224, 219, 96, 235, 105, 253, 68, 151, 63, 159, 213, 61, 96, 8, 224, 24, 28, 90, 129, 156, 22, 25, 66, 66, 143, 239, 196, 171, 29, 13, 95, 163, 56, 87, 48, 212, 215, 72, 227, 81, 104, 53, 139, 236, 188, 128, 188, 39, 63, 223, 221, 87, 39, 250, 188, 147, 17, 199, 187, 191, 223, 149, 255, 172, 2, 174, 180, 30, 3, 20, 9, 179, 209, 14, 135, 177, 230, 230, 197, 6, 214, 127, 184, 220, 182, 147, 196, 1, 233, 166, 208, 117, 53, 27, 239, 167, 250, 146, 188, 191, 44, 63, 126, 25, 131, 251, 155, 209, 124, 244, 61, 128, 33, 161, 254, 124, 17, 223, 157, 9, 174, 72, 136, 130, 99, 2, 218, 76, 248, 115, 52, 140, 75, 220, 169, 145, 119, 90, 154, 55, 179, 3, 247, 245, 224, 97, 120, 11, 63, 95, 248, 227, 205, 148, 9, 156, 121, 111, 198, 183, 194, 240, 224, 127, 172, 161, 40, 176, 174, 198, 115, 39, 21, 135, 93, 120, 52, 77, 227, 203, 226, 47, 228, 208, 254, 86, 42, 178, 168, 118, 24, 219, 101, 28, 233, 205, 124, 126, 162, 249, 141, 40, 110, 247, 247, 167, 36, 186, 206, 2, 218, 68, 198, 144, 175, 3, 72, 97, 133, 245, 21, 59, 121, 75, 124, 96, 81, 44, 114, 14, 155, 78, 83, 4, 100, 18, 134, 220, 4, 88, 1, 176, 47, 235, 54, 199, 40, 55, 162, 55, 29, 186, 218, 192, 34, 234, 96, 241, 128, 217, 64, 204, 95, 238, 170, 235, 230, 242, 14, 87, 111, 159, 173, 38, 146, 75, 197, 5, 115, 239, 112, 251, 19, 178, 192, 186, 135, 123, 127, 45, 136, 135, 4, 78, 178, 164, 252, 8, 36, 171, 74, 21, 243, 236, 22, 204, 242, 123, 6, 114, 138, 102, 239, 74, 238, 255, 233, 3, 164, 62, 58, 143, 197, 248, 147, 172, 165, 4, 14, 1, 147, 251, 79, 85, 50, 48, 118, 108, 30, 77, 81, 140, 29, 143, 198, 121, 197, 19, 225, 49, 93, 53, 73, 33, 122, 100, 234, 165, 67, 183, 100, 195, 168, 123, 37, 235, 86, 147, 164, 71, 20, 232, 206, 20, 228, 22, 17, 177, 2, 116, 163, 136, 187, 43, 160, 176, 83, 52, 39, 224, 140, 250, 66, 232, 255, 36, 166, 132, 97, 252, 44, 246, 106, 21, 113, 16, 166, 70, 54, 222, 228, 10, 51, 19, 106, 141, 31, 102, 129, 132, 219, 84, 27, 192, 66, 145, 133, 208, 111, 137, 81, 145, 121, 176, 155, 133, 222, 27, 156, 93, 19, 244, 230, 154, 5, 113, 177, 247, 70, 125, 202, 138, 60, 3, 29, 182, 33, 211, 112, 136, 107, 223, 175, 131, 92, 13, 23, 133, 238, 136, 130, 231, 215, 211, 199, 47, 70, 75, 104, 253, 172, 61, 246, 99, 80, 154, 169, 205, 208, 105, 43, 2, 110, 203, 246, 16, 176, 11, 152, 190, 185, 100, 102, 6, 125, 63, 101, 184, 157, 6, 52, 237, 85, 121, 193, 4, 245, 227, 178, 121, 91, 208, 31, 149, 32, 198, 6, 44, 160, 127, 164, 97, 113, 61, 8, 129, 126, 48, 10, 29, 100, 71, 211, 225, 40, 9, 0, 3, 68, 93, 210, 80, 229, 218, 36, 186, 188, 107, 182, 149, 10, 6, 152, 149, 89, 117, 111, 83, 95, 195, 187, 170, 69, 248, 36, 46, 55, 27, 32, 176, 49, 156, 89, 40, 187, 234, 208, 124, 4, 208, 147, 55, 234, 237, 170, 226, 161, 111, 205, 227, 202, 198, 15, 149, 253, 102, 56, 203, 135, 155, 57, 133, 7, 109, 38, 45, 84, 8, 201, 120, 98, 237, 208, 163, 213, 53, 176, 121, 188, 246, 40, 141, 178, 27, 12, 74, 154, 55, 231, 250, 214, 249, 165, 18, 187, 143, 85, 131, 175, 192, 203, 220, 173, 219, 162, 181, 130, 100, 203, 31, 68, 146, 157, 10, 1, 49, 123, 56, 175, 34, 92, 31, 205, 201, 39, 97, 89, 162, 176, 166, 198, 242, 192, 212, 230, 208, 253, 110, 118, 141, 136, 68, 241, 174, 93, 119, 157, 164, 70, 52, 222, 125, 170, 235, 170, 115, 129, 254, 58, 191, 19, 12, 9, 76, 159, 116, 183, 185, 166, 169, 247, 179, 96, 43, 63, 202, 50, 91, 14, 150, 45, 142, 89, 161, 224, 94, 7, 25, 127, 143, 190, 148, 251, 243, 246, 157, 36, 116, 199, 185, 196, 245, 6, 4, 255, 135, 86, 236, 255, 223, 240, 191, 8, 186, 178, 34, 247, 77, 40, 193, 224, 191, 235, 56, 14, 246, 154, 127, 15, 214, 232, 95, 120, 83, 143, 147, 159, 97, 207, 96, 9, 174, 129, 106, 21, 250, 164, 65, 103, 111, 23, 160, 242, 127, 5, 172, 168, 68, 41, 119, 189, 125, 79, 82, 22, 58, 113, 205, 193, 107, 168, 144, 220, 34, 198, 164, 235, 153, 160, 200, 39, 196, 87, 81, 195, 247, 81, 215, 98, 5, 153, 67, 60, 255, 1, 229, 149, 1, 43, 195, 242, 114, 27, 7, 17, 7, 48, 7, 15, 179, 77, 91, 7, 173, 203, 172, 82, 199, 183, 45, 3, 129, 165, 46, 118, 88, 51, 37, 119, 226, 88, 128, 248, 41, 126, 17, 63, 63, 4, 255, 115, 59, 255, 240, 220, 172, 123, 102, 29, 135, 40, 107, 120, 53, 184, 127, 231, 193, 184, 153, 137, 247, 151, 78, 69, 91, 191, 61, 101, 207, 63, 105, 107, 14, 17, 32, 90, 219, 46, 140, 31, 62, 162, 109, 58, 9, 130, 12, 43, 19, 47, 212, 0, 90, 155, 76, 81, 171, 218, 9, 247, 3, 109, 2, 16, 172, 132, 3, 110, 169, 67, 209, 224, 73, 187, 152, 1, 69, 219, 82, 197, 108, 65, 235, 90, 151, 104, 66, 213, 115, 201, 79, 245, 192, 44, 117, 92, 194, 188, 160, 230, 5, 218, 50, 149, 8, 178, 46, 251, 29, 25, 152, 183, 68, 232, 119, 92, 180, 46, 74, 54, 196, 101, 98, 232, 155, 48, 80, 197, 12, 73, 58, 21, 146, 48, 187, 167, 6, 244, 119, 130, 90, 213, 218, 183, 48, 80, 166, 206, 163, 4, 184, 126, 190, 35, 86, 79, 221, 49, 160, 109, 215, 63, 102, 96, 125, 91, 10, 111, 205, 186, 170, 6, 107, 177, 75, 228, 128, 132, 185, 17, 65, 18, 94, 203, 211, 252, 238, 28, 191, 99, 67, 146, 56, 57, 126, 71, 134, 71, 28, 227, 119, 92, 120, 100, 173, 101, 30, 73, 218, 119, 132, 56, 125, 71, 5, 181, 139, 117, 185, 40, 5, 226, 158, 223, 241, 42, 73, 251, 206, 37, 98, 169, 239, 248, 240, 88, 189, 99, 3, 175, 122, 199, 133, 73, 83, 164, 222, 113, 161, 222, 81, 129, 114, 143, 64, 96, 60, 133, 174, 253, 166, 169, 213, 33, 255, 223, 133, 252, 243, 29, 29, 250, 123, 0, 213, 244, 43, 218, 0, 161, 152, 29, 213, 213, 52, 252, 144, 149, 137, 23, 62, 84, 49, 67, 159, 239, 216, 112, 126, 41, 200, 31, 217, 249, 142, 11, 26, 137, 131, 52, 246, 72, 131, 182, 109, 154, 162, 7, 213, 140, 116, 126, 0, 100, 192, 175, 99, 249, 142, 11, 213, 210, 209, 38, 223, 177, 17, 225, 174, 65, 154, 178, 223, 161, 37, 99, 40, 203, 102, 28, 30, 65, 190, 192, 115, 210, 50, 161, 126, 107, 129, 208, 148, 253, 15, 72, 179, 36, 229, 35, 195, 59, 6, 192, 19, 45, 119, 132, 120, 4, 2, 91, 119, 92, 64, 24, 71, 17, 28, 119, 132, 136, 224, 184, 163, 194, 51, 211, 70, 142, 59, 54, 112, 220, 209, 193, 184, 163, 2, 117, 71, 5, 12, 147, 201, 29, 25, 182, 29, 31, 175, 158, 218, 145, 33, 181, 163, 163, 181, 149, 61, 111, 156, 144, 79, 112, 132, 52, 213, 158, 224, 200, 176, 38, 56, 54, 244, 119, 77, 112, 100, 240, 53, 193, 145, 34, 237, 251, 50, 52, 193, 49, 98, 77, 112, 108, 224, 164, 104, 130, 35, 228, 155, 54, 118, 236, 113, 142, 16, 206, 47, 115, 125, 253, 92, 142, 233, 163, 87, 117, 92, 127, 219, 57, 46, 248, 149, 56, 152, 111, 219, 206, 113, 193, 76, 91, 180, 32, 182, 31, 122, 152, 125, 118, 142, 143, 166, 177, 115, 124, 72, 218, 115, 112, 109, 233, 188, 233, 108, 52, 109, 251, 33, 110, 37, 238, 120, 239, 101, 80, 99, 135, 76, 140, 93, 206, 81, 226, 119, 57, 127, 114, 57, 199, 134, 235, 182, 182, 206, 145, 225, 17, 8, 109, 157, 227, 162, 162, 206, 81, 65, 251, 121, 42, 67, 74, 213, 57, 54, 208, 42, 73, 235, 154, 23, 39, 196, 30, 69, 227, 254, 164, 206, 145, 241, 252, 166, 101, 54, 169, 115, 124, 60, 41, 169, 115, 100, 208, 246, 42, 40, 169, 243, 71, 57, 71, 135, 71, 57, 71, 5, 215, 166, 101, 63, 92, 45, 132, 58, 80, 119, 215, 118, 11, 252, 225, 147, 118, 87, 148, 115, 132, 84, 148, 115, 84, 80, 12, 46, 155, 226, 72, 237, 241, 181, 212, 241, 71, 165, 25, 173, 170, 147, 210, 204, 160, 230, 110, 93, 176, 214, 74, 26, 52, 120, 211, 137, 26, 197, 161, 150, 46, 243, 187, 32, 117, 132, 120, 36, 123, 209, 102, 229, 154, 208, 233, 28, 31, 92, 23, 67, 2, 197, 144, 164, 149, 237, 55, 117, 72, 83, 58, 199, 70, 82, 197, 9, 185, 100, 15, 171, 159, 131, 75, 22, 225, 148, 54, 120, 68, 215, 146, 174, 177, 71, 208, 183, 106, 246, 71, 37, 159, 52, 178, 240, 67, 194, 249, 166, 233, 66, 223, 30, 105, 228, 42, 101, 200, 61, 49, 72, 206, 120, 178, 59, 209, 55, 59, 58, 24, 243, 130, 210, 54, 118, 116, 120, 218, 126, 86, 211, 216, 209, 161, 203, 155, 16, 209, 217, 216, 177, 161, 117, 162, 140, 29, 23, 189, 216, 241, 161, 77, 182, 78, 34, 154, 159, 95, 181, 139, 29, 25, 96, 111, 21, 59, 54, 248, 132, 4, 18, 200, 61, 34, 73, 236, 200, 192, 203, 75, 225, 171, 180, 33, 90, 223, 165, 74, 20, 193, 11, 161, 129, 15, 141, 211, 38, 118, 92, 64, 44, 254, 240, 164, 93, 236, 30, 206, 113, 173, 146, 116, 17, 107, 25, 73, 82, 220, 24, 104, 147, 7, 93, 79, 49, 123, 180, 109, 222, 226, 198, 65, 66, 242, 52, 199, 135, 228, 105, 142, 10, 238, 155, 163, 2, 242, 230, 216, 32, 73, 233, 40, 220, 28, 25, 46, 155, 194, 220, 28, 25, 78, 122, 101, 36, 218, 28, 27, 79, 69, 69, 54, 71, 6, 143, 36, 244, 104, 38, 11, 134, 89, 133, 176, 97, 237, 63, 212, 184, 201, 86, 46, 155, 163, 67, 155, 223, 31, 126, 33, 218, 156, 208, 179, 227, 200, 101, 115, 116, 144, 100, 115, 116, 172, 75, 247, 204, 113, 241, 104, 188, 15, 174, 173, 84, 34, 247, 204, 113, 194, 57, 230, 168, 176, 128, 0, 13, 15, 146, 148, 206, 113, 102, 230, 232, 104, 91, 89, 182, 28, 23, 106, 155, 183, 28, 25, 154, 183, 28, 29, 154, 183, 28, 21, 36, 219, 120, 57, 50, 36, 94, 142, 10, 232, 160, 24, 214, 91, 34, 77, 187, 28, 29, 13, 78, 117, 57, 46, 60, 32, 54, 151, 99, 176, 216, 59, 13, 223, 148, 53, 238, 157, 52, 69, 19, 85, 11, 90, 81, 3, 253, 92, 142, 11, 174, 139, 8, 12, 142, 231, 114, 92, 104, 90, 46, 199, 133, 135, 217, 8, 9, 179, 179, 40, 165, 225, 97, 246, 29, 232, 208, 120, 127, 21, 90, 114, 57, 74, 120, 75, 101, 18, 199, 69, 47, 92, 169, 115, 43, 113, 108, 240, 168, 88, 71, 199, 122, 203, 214, 247, 117, 116, 76, 122, 29, 21, 244, 189, 75, 56, 108, 58, 9, 57, 26, 183, 117, 92, 208, 182, 139, 162, 173, 1, 74, 231, 8, 33, 208, 195, 236, 2, 143, 160, 135, 217, 5, 84, 49, 230, 73, 65, 41, 53, 232, 155, 160, 206, 37, 151, 135, 206, 69, 87, 69, 197, 82, 28, 60, 237, 251, 126, 190, 71, 64, 144, 142, 63, 240, 190, 203, 169, 123, 68, 112, 254, 37, 43, 91, 246, 104, 187, 34, 188, 225, 141, 211, 66, 22, 172, 156, 60, 154, 33, 24, 43, 7, 54, 172, 79, 108, 29, 25, 154, 187, 21, 33, 236, 181, 102, 29, 25, 32, 223, 84, 186, 10, 104, 191, 111, 104, 93, 217, 154, 117, 92, 180, 102, 29, 29, 173, 207, 172, 35, 195, 51, 235, 168, 160, 106, 29, 33, 107, 242, 28, 199, 133, 181, 255, 30, 13, 43, 223, 4, 69, 16, 181, 30, 59, 142, 12, 207, 142, 163, 130, 227, 233, 52, 154, 29, 71, 135, 42, 110, 104, 93, 162, 135, 89, 199, 142, 35, 68, 69, 151, 227, 184, 240, 168, 4, 125, 211, 137, 178, 117, 28, 27, 172, 100, 29, 199, 133, 231, 153, 117, 28, 25, 60, 2, 65, 181, 58, 46, 105, 69, 33, 120, 68, 146, 212, 73, 207, 111, 194, 67, 93, 38, 135, 76, 154, 162, 181, 212, 113, 108, 56, 52, 45, 23, 117, 28, 31, 80, 3, 123, 158, 142, 35, 131, 235, 116, 28, 23, 28, 199, 134, 174, 101, 212, 53, 86, 190, 9, 234, 43, 223, 4, 117, 88, 249, 38, 232, 227, 24, 194, 214, 113, 36, 161, 141, 23, 54, 180, 62, 185, 28, 74, 73, 58, 142, 144, 206, 8, 122, 240, 200, 74, 248, 144, 144, 142, 163, 130, 174, 101, 208, 4, 18, 68, 72, 199, 241, 161, 107, 25, 4, 65, 58, 142, 13, 8, 210, 113, 84, 240, 8, 132, 116, 28, 25, 118, 37, 84, 81, 140, 35, 195, 209, 97, 93, 54, 20, 241, 234, 234, 188, 58, 54, 216, 58, 142, 36, 208, 171, 99, 195, 202, 73, 218, 198, 172, 211, 65, 175, 142, 11, 90, 255, 181, 65, 175, 142, 14, 85, 173, 190, 18, 198, 136, 166, 173, 36, 241, 90, 208, 171, 35, 228, 97, 22, 186, 147, 86, 71, 6, 36, 73, 249, 254, 77, 89, 99, 231, 159, 7, 88, 61, 245, 246, 186, 129, 123, 172, 147, 210, 180, 109, 154, 124, 164, 93, 0, 215, 77, 128, 250, 82, 102, 27, 86, 249, 169, 156, 146, 200, 39, 56, 98, 32, 225, 173, 79, 46, 148, 106, 97, 185, 80, 218, 165, 77, 209, 214, 234, 144, 235, 226, 70, 44, 151, 0, 18, 175, 146, 244, 22, 244, 77, 153, 46, 213, 222, 226, 148, 6, 152, 164, 32, 253, 220, 196, 238, 14, 30, 80, 154, 117, 137, 26, 184, 235, 106, 7, 36, 98, 89, 18, 72, 0, 65, 84, 84, 181, 125, 52, 78, 59, 73, 6, 233, 164, 213, 177, 161, 27, 221, 15, 143, 32, 126, 6, 141, 61, 130, 15, 15, 179, 169, 57, 40, 22, 179, 147, 36, 102, 14, 187, 18, 106, 208, 138, 93, 250, 38, 168, 99, 99, 130, 58, 42, 248, 149, 188, 235, 59, 176, 171, 40, 122, 250, 219, 46, 231, 17, 234, 153, 144, 166, 166, 223, 212, 177, 97, 109, 50, 213, 212, 81, 131, 218, 110, 84, 239, 162, 154, 58, 50, 124, 237, 63, 200, 35, 241, 208, 0, 161, 205, 50, 190, 159, 142, 222, 245, 83, 187, 17, 0, 195, 172, 66, 173, 19, 166, 142, 15, 213, 11, 113, 215, 133, 246, 121, 66, 251, 30, 188, 0, 254, 203, 24, 35, 0, 33, 188, 201, 71, 24, 209, 58, 217, 86, 139, 82, 36, 38, 58, 35, 72, 27, 47, 246, 182, 233, 82, 199, 7, 218, 66, 43, 182, 161, 76, 157, 8, 159, 52, 218, 32, 228, 143, 13, 175, 236, 144, 63, 46, 92, 115, 200, 31, 25, 252, 209, 241, 184, 240, 71, 37, 13, 249, 35, 131, 127, 37, 137, 37, 137, 153, 147, 184, 194, 136, 112, 9, 253, 236, 102, 29, 18, 40, 151, 12, 249, 35, 67, 195, 240, 216, 144, 36, 102, 40, 178, 248, 166, 174, 237, 144, 47, 242, 199, 6, 127, 132, 184, 63, 58, 214, 4, 199, 101, 55, 200, 31, 35, 252, 17, 242, 73, 93, 69, 145, 63, 54, 190, 169, 106, 248, 227, 227, 241, 33, 157, 63, 82, 52, 63, 253, 184, 240, 251, 244, 227, 2, 63, 122, 250, 17, 162, 189, 157, 208, 211, 143, 13, 100, 188, 58, 246, 250, 113, 161, 139, 97, 94, 63, 46, 156, 127, 24, 210, 215, 143, 13, 167, 121, 220, 143, 12, 19, 190, 246, 159, 196, 87, 244, 81, 74, 150, 251, 49, 98, 229, 78, 182, 31, 33, 88, 234, 130, 116, 185, 237, 199, 135, 107, 219, 53, 241, 78, 179, 173, 180, 193, 25, 134, 35, 92, 219, 46, 182, 253, 40, 193, 182, 31, 21, 60, 130, 13, 10, 93, 94, 106, 117, 207, 107, 90, 110, 63, 46, 120, 152, 93, 164, 246, 248, 82, 197, 204, 177, 214, 74, 26, 174, 141, 246, 35, 164, 109, 58, 9, 57, 168, 183, 78, 178, 127, 33, 30, 65, 14, 42, 219, 159, 108, 1, 132, 71, 36, 254, 234, 72, 53, 165, 146, 148, 253, 184, 160, 223, 162, 25, 190, 105, 167, 211, 148, 253, 248, 152, 32, 130, 126, 84, 112, 154, 199, 143, 16, 39, 61, 126, 92, 232, 236, 230, 71, 9, 247, 92, 14, 223, 236, 223, 236, 104, 101, 218, 134, 23, 59, 126, 132, 120, 152, 93, 142, 109, 196, 3, 50, 216, 241, 163, 66, 231, 226, 248, 145, 193, 35, 16, 208, 17, 1, 132, 8, 68, 208, 195, 236, 98, 252, 8, 89, 140, 31, 21, 186, 98, 25, 77, 37, 252, 8, 105, 93, 102, 191, 169, 90, 126, 132, 52, 94, 132, 224, 71, 134, 71, 16, 62, 116, 45, 51, 65, 252, 200, 152, 0, 243, 15, 241, 227, 98, 2, 223, 246, 33, 126, 126, 92, 32, 126, 116, 240, 35, 131, 223, 129, 31, 25, 21, 135, 24, 241, 35, 126, 116, 64, 252, 252, 232, 128, 24, 211, 32, 126, 140, 120, 68, 144, 240, 201, 235, 113, 225, 18, 15, 63, 58, 92, 159, 223, 4, 126, 132, 248, 84, 136, 31, 33, 174, 105, 217, 73, 136, 31, 29, 252, 216, 128, 141, 119, 6, 135, 7, 126, 132, 136, 128, 4, 16, 64, 208, 30, 25, 28, 123, 124, 56, 233, 147, 61, 50, 120, 68, 173, 199, 133, 245, 251, 232, 208, 245, 251, 16, 87, 45, 243, 221, 190, 115, 251, 200, 88, 253, 22, 250, 244, 77, 208, 196, 158, 182, 143, 11, 253, 84, 140, 230, 197, 73, 169, 123, 254, 233, 155, 224, 112, 82, 43, 131, 120, 12, 73, 51, 131, 122, 65, 220, 191, 131, 26, 123, 196, 65, 63, 23, 211, 22, 61, 109, 191, 225, 164, 212, 167, 73, 86, 82, 208, 47, 99, 156, 36, 22, 115, 162, 167, 237, 227, 195, 55, 59, 219, 199, 5, 99, 251, 168, 0, 33, 73, 204, 144, 54, 174, 104, 240, 8, 210, 198, 21, 200, 112, 124, 69, 145, 247, 195, 108, 132, 55, 67, 171, 36, 173, 67, 7, 143, 86, 167, 42, 241, 8, 4, 110, 210, 161, 141, 43, 32, 149, 101, 30, 24, 102, 21, 82, 182, 143, 141, 135, 89, 181, 246, 113, 241, 72, 210, 62, 46, 60, 46, 105, 207, 121, 100, 144, 164, 92, 40, 220, 206, 99, 195, 37, 131, 60, 124, 211, 238, 151, 26, 39, 52, 17, 193, 105, 30, 183, 243, 200, 208, 245, 31, 209, 180, 79, 110, 231, 145, 129, 210, 140, 103, 182, 157, 71, 6, 136, 101, 151, 122, 135, 56, 133, 51, 89, 144, 227, 202, 144, 131, 106, 59, 143, 11, 190, 80, 169, 237, 60, 54, 48, 229, 209, 243, 189, 206, 163, 163, 173, 243, 8, 73, 172, 180, 213, 249, 135, 217, 166, 206, 227, 227, 89, 154, 58, 143, 12, 206, 160, 166, 206, 227, 162, 105, 203, 212, 121, 92, 236, 67, 202, 212, 121, 100, 72, 218, 99, 30, 23, 214, 254, 107, 160, 235, 53, 162, 248, 182, 235, 43, 250, 200, 120, 237, 76, 232, 208, 120, 63, 35, 38, 128, 152, 127, 19, 12, 26, 24, 102, 21, 250, 138, 254, 87, 244, 209, 209, 234, 188, 62, 50, 172, 75, 180, 54, 219, 127, 219, 139, 52, 88, 236, 29, 228, 139, 249, 25, 32, 67, 31, 29, 30, 186, 216, 245, 17, 242, 174, 143, 10, 218, 156, 80, 132, 71, 32, 32, 100, 65, 171, 183, 62, 50, 72, 40, 136, 65, 118, 235, 227, 163, 249, 179, 109, 147, 78, 226, 87, 2, 105, 109, 45, 23, 180, 240, 65, 43, 214, 17, 107, 125, 108, 120, 68, 21, 55, 247, 239, 32, 119, 93, 77, 83, 211, 199, 6, 143, 99, 250, 184, 16, 1, 122, 109, 25, 43, 127, 142, 233, 227, 131, 167, 179, 185, 161, 244, 201, 181, 250, 65, 28, 211, 71, 134, 254, 54, 197, 23, 76, 31, 27, 142, 233, 163, 194, 107, 91, 250, 216, 240, 205, 110, 162, 177, 71, 152, 236, 70, 151, 62, 50, 92, 126, 227, 93, 155, 234, 99, 67, 5, 154, 234, 35, 196, 241, 129, 82, 127, 46, 61, 54, 60, 50, 26, 239, 194, 56, 61, 66, 188, 239, 90, 107, 37, 18, 207, 71, 70, 119, 62, 42, 56, 131, 58, 31, 25, 212, 229, 187, 124, 92, 36, 117, 142, 92, 62, 50, 254, 49, 114, 249, 184, 144, 172, 124, 149, 228, 35, 195, 61, 169, 182, 148, 181, 249, 248, 88, 155, 143, 10, 139, 122, 24, 38, 31, 23, 222, 248, 113, 82, 62, 50, 80, 243, 231, 122, 75, 62, 66, 44, 249, 75, 62, 50, 124, 179, 55, 180, 98, 31, 32, 186, 150, 124, 92, 208, 181, 228, 178, 228, 35, 195, 113, 235, 183, 117, 208, 10, 225, 17, 166, 239, 143, 35, 227, 87, 146, 218, 227, 184, 72, 142, 1, 113, 210, 43, 227, 72, 90, 81, 148, 218, 227, 216, 120, 28, 39, 212, 140, 240, 65, 181, 255, 17, 129, 12, 173, 110, 41, 142, 12, 232, 72, 20, 71, 199, 147, 20, 71, 5, 143, 32, 214, 73, 113, 151, 20, 199, 70, 4, 8, 137, 247, 85, 232, 97, 159, 195, 23, 243, 251, 231, 55, 172, 220, 180, 12, 195, 13, 18, 43, 143, 188, 197, 232, 164, 113, 196, 55, 117, 104, 146, 226, 248, 160, 56, 58, 22, 80, 39, 101, 210, 118, 136, 226, 248, 80, 127, 149, 102, 226, 184, 64, 70, 99, 111, 38, 142, 12, 220, 76, 28, 21, 16, 226, 81, 188, 60, 173, 19, 141, 160, 153, 56, 54, 48, 255, 17, 22, 30, 129, 240, 73, 151, 186, 227, 154, 153, 243, 233, 32, 52, 19, 199, 9, 143, 64, 104, 38, 173, 191, 150, 129, 208, 76, 154, 182, 158, 10, 161, 153, 56, 54, 56, 80, 232, 155, 32, 126, 111, 242, 81, 51, 113, 100, 52, 192, 40, 135, 56, 63, 1, 225, 205, 196, 145, 129, 55, 185, 24, 140, 104, 149, 228, 130, 154, 137, 99, 163, 117, 43, 116, 65, 105, 151, 151, 16, 63, 74, 157, 168, 153, 56, 54, 248, 214, 137, 227, 163, 153, 227, 152, 168, 138, 144, 36, 133, 56, 232, 47, 157, 56, 50, 60, 58, 233, 231, 8, 89, 185, 221, 207, 113, 225, 175, 13, 105, 74, 166, 159, 35, 196, 45, 74, 105, 117, 143, 51, 225, 223, 236, 28, 154, 125, 39, 239, 218, 112, 249, 140, 79, 175, 211, 126, 254, 227, 43, 250, 8, 242, 84, 32, 36, 36, 137, 25, 106, 117, 207, 209, 161, 207, 173, 149, 177, 231, 232, 104, 149, 36, 117, 18, 123, 139, 15, 247, 69, 103, 243, 28, 23, 42, 203, 48, 207, 145, 225, 29, 227, 118, 15, 86, 207, 209, 161, 158, 157, 158, 227, 194, 93, 83, 122, 142, 14, 95, 209, 207, 95, 158, 35, 131, 174, 231, 125, 121, 142, 12, 73, 91, 95, 158, 227, 194, 41, 200, 27, 239, 187, 5, 246, 33, 148, 152, 240, 229, 57, 62, 26, 133, 21, 4, 45, 157, 232, 90, 158, 35, 132, 247, 170, 229, 57, 46, 154, 206, 229, 57, 50, 184, 39, 225, 231, 79, 215, 235, 245, 141, 124, 25, 190, 237, 162, 113, 255, 167, 76, 203, 248, 19, 53, 238, 111, 224, 192, 61, 185, 67, 51, 2, 84, 243, 131, 107, 191, 79, 101, 144, 210, 246, 16, 55, 6, 180, 190, 211, 172, 115, 0, 245, 167, 180, 185, 53, 139, 184, 161, 92, 73, 21, 4, 205, 206, 128, 47, 148, 47, 128, 123, 114, 244, 192, 3, 215, 182, 75, 213, 190, 6, 185, 167, 15, 192, 61, 57, 34, 128, 187, 38, 117, 160, 85, 53, 183, 0, 220, 83, 50, 71, 173, 170, 25, 57, 96, 177, 119, 208, 130, 7, 2, 8, 18, 53, 92, 146, 210, 209, 94, 166, 81, 129, 134, 149, 138, 217, 35, 81, 241, 8, 82, 14, 111, 156, 22, 169, 183, 114, 162, 235, 249, 199, 39, 141, 180, 237, 255, 68, 135, 194, 8, 9, 18, 254, 126, 199, 133, 63, 203, 129, 166, 237, 51, 211, 126, 104, 101, 205, 12, 47, 6, 72, 161, 12, 206, 191, 68, 171, 159, 254, 99, 230, 145, 9, 255, 166, 158, 144, 115, 44, 181, 223, 25, 215, 192, 120, 65, 110, 189, 37, 114, 21, 11, 150, 218, 15, 121, 117, 151, 172, 225, 159, 188, 152, 135, 89, 9, 92, 209, 195, 172, 235, 62, 204, 62, 204, 110, 211, 86, 113, 82, 85, 1, 135, 239, 124, 119, 154, 109, 182, 253, 11, 60, 163, 139, 109, 191, 131, 181, 146, 129, 239, 124, 127, 160, 154, 170, 116, 16, 32, 168, 165, 60, 171, 49, 98, 219, 207, 191, 216, 59, 200, 109, 255, 179, 60, 60, 191, 157, 107, 217, 186, 3, 11, 52, 229, 114, 74, 65, 105, 72, 231, 34, 161, 157, 253, 62, 27, 131, 6, 207, 232, 138, 96, 2, 228, 120, 58, 14, 142, 167, 19, 89, 24, 69, 52, 40, 125, 104, 188, 14, 11, 21, 64, 63, 27, 238, 126, 142, 86, 246, 123, 34, 95, 116, 128, 73, 211, 137, 30, 200, 240, 191, 76, 63, 109, 191, 227, 2, 146, 182, 222, 186, 22, 55, 68, 159, 190, 9, 1, 19, 108, 200, 196, 19, 84, 72, 60, 65, 5, 157, 17, 244, 218, 4, 23, 254, 142, 219, 4, 25, 38, 172, 9, 42, 104, 188, 21, 59, 65, 6, 247, 180, 170, 45, 133, 34, 130, 190, 73, 55, 19, 135, 72, 138, 171, 40, 182, 19, 132, 208, 223, 9, 42, 52, 94, 223, 9, 50, 120, 4, 33, 234, 59, 65, 133, 181, 255, 144, 239, 4, 25, 218, 118, 41, 219, 71, 190, 19, 132, 32, 223, 9, 62, 24, 184, 100, 15, 19, 238, 124, 58, 165, 44, 219, 131, 233, 175, 59, 36, 90, 179, 238, 137, 32, 235, 105, 59, 193, 133, 230, 207, 212, 202, 240, 129, 71, 144, 225, 17, 8, 255, 19, 7, 134, 226, 200, 35, 143, 9, 232, 34, 143, 60, 56, 158, 139, 105, 240, 165, 19, 93, 232, 249, 93, 249, 38, 60, 224, 154, 250, 177, 59, 224, 203, 65, 203, 246, 79, 120, 4, 2, 227, 83, 106, 63, 84, 237, 4, 33, 24, 115, 5, 131, 7, 15, 146, 148, 239, 218, 233, 248, 2, 6, 90, 255, 51, 249, 131, 111, 37, 81, 231, 98, 39, 161, 235, 116, 178, 159, 205, 65, 219, 46, 213, 180, 209, 197, 239, 235, 68, 184, 199, 221, 116, 46, 205, 221, 10, 209, 218, 54, 181, 147, 3, 109, 78, 223, 233, 52, 120, 78, 28, 36, 105, 223, 117, 169, 150, 105, 66, 219, 46, 137, 215, 13, 158, 151, 67, 21, 134, 232, 92, 30, 190, 21, 4, 121, 154, 63, 237, 4, 23, 239, 236, 76, 112, 1, 226, 155, 221, 209, 234, 224, 30, 82, 109, 25, 164, 107, 153, 201, 4, 23, 154, 187, 117, 130, 12, 138, 226, 158, 238, 29, 137, 95, 245, 18, 61, 240, 166, 148, 170, 117, 130, 141, 165, 169, 117, 130, 12, 30, 129, 208, 154, 85, 211, 9, 46, 60, 226, 128, 158, 223, 196, 75, 39, 8, 161, 30, 175, 164, 154, 41, 14, 203, 141, 155, 39, 206, 154, 25, 101, 219, 240, 198, 139, 146, 169, 195, 192, 113, 217, 141, 54, 77, 254, 160, 43, 147, 43, 219, 111, 175, 33, 141, 118, 227, 93, 186, 228, 114, 180, 190, 182, 107, 253, 182, 143, 147, 58, 91, 215, 113, 96, 109, 220, 65, 83, 51, 227, 104, 188, 15, 147, 137, 135, 59, 55, 196, 174, 132, 178, 209, 9, 50, 178, 209, 9, 42, 168, 78, 16, 50, 65, 134, 87, 192, 101, 154, 96, 195, 211, 57, 65, 133, 206, 9, 54, 190, 109, 231, 4, 25, 24, 102, 21, 194, 134, 111, 57, 65, 133, 136, 86, 137, 39, 115, 80, 153, 107, 109, 203, 9, 66, 40, 4, 71, 172, 124, 19, 60, 242, 88, 8, 42, 217, 229, 64, 37, 187, 80, 3, 7, 30, 76, 80, 180, 50, 204, 91, 36, 84, 178, 11, 49, 88, 8, 17, 173, 234, 22, 96, 174, 53, 160, 159, 171, 31, 82, 16, 171, 159, 218, 149, 19, 116, 208, 79, 133, 118, 229, 4, 27, 57, 153, 192, 4, 23, 19, 152, 32, 196, 4, 25, 18, 79, 134, 38, 200, 160, 58, 121, 113, 143, 10, 82, 181, 190, 43, 161, 9, 70, 76, 208, 225, 182, 226, 161, 66, 4, 19, 181, 239, 33, 3, 4, 106, 223, 195, 133, 134, 8, 38, 11, 245, 78, 231, 120, 28, 246, 61, 132, 232, 123, 168, 64, 183, 255, 225, 66, 69, 27, 237, 6, 77, 255, 115, 49, 200, 149, 99, 195, 195, 44, 132, 181, 15, 81, 77, 255, 81, 81, 180, 246, 31, 46, 214, 254, 67, 5, 85, 156, 154, 62, 220, 161, 255, 44, 104, 2, 204, 63, 132, 152, 0, 243, 15, 21, 36, 192, 252, 67, 5, 157, 0, 98, 254, 161, 67, 106, 143, 163, 6, 101, 217, 24, 223, 180, 201, 124, 101, 168, 25, 59, 13, 127, 52, 185, 32, 116, 104, 245, 135, 10, 219, 239, 104, 247, 133, 106, 143, 189, 51, 169, 90, 71, 234, 15, 31, 173, 16, 74, 25, 115, 5, 82, 45, 81, 75, 7, 161, 141, 17, 51, 101, 234, 91, 82, 228, 42, 101, 141, 125, 253, 225, 4, 164, 149, 177, 69, 154, 154, 153, 164, 12, 163, 72, 219, 169, 42, 164, 254, 176, 65, 243, 39, 93, 20, 144, 199, 113, 114, 187, 36, 24, 109, 36, 73, 185, 60, 132, 112, 222, 74, 196, 171, 123, 34, 245, 135, 13, 245, 135, 10, 22, 127, 168, 96, 101, 122, 63, 108, 240, 126, 168, 96, 77, 232, 135, 10, 17, 76, 160, 158, 139, 101, 215, 234, 135, 12, 109, 57, 178, 250, 225, 194, 241, 116, 86, 63, 92, 96, 131, 29, 32, 205, 91, 254, 180, 190, 9, 232, 213, 27, 22, 112, 150, 157, 46, 194, 85, 180, 209, 94, 253, 176, 1, 105, 173, 255, 15, 79, 212, 15, 41, 208, 209, 150, 35, 104, 245, 67, 198, 234, 135, 10, 42, 219, 15, 21, 182, 31, 62, 60, 178, 253, 112, 193, 27, 244, 119, 109, 63, 140, 240, 8, 218, 126, 200, 128, 90, 157, 107, 154, 123, 184, 120, 94, 238, 225, 194, 107, 163, 150, 130, 180, 51, 97, 132, 67, 235, 131, 243, 106, 41, 232, 159, 107, 43, 193, 48, 171, 30, 146, 164, 78, 66, 16, 253, 84, 238, 33, 67, 195, 11, 41, 247, 30, 46, 180, 58, 6, 68, 29, 36, 160, 74, 39, 244, 112, 91, 209, 30, 46, 168, 165, 251, 180, 135, 11, 124, 104, 15, 27, 95, 209, 134, 148, 126, 190, 183, 135, 13, 175, 222, 30, 62, 40, 217, 237, 225, 66, 123, 200, 80, 183, 174, 61, 100, 96, 205, 237, 225, 130, 227, 169, 171, 61, 116, 120, 152, 173, 108, 123, 184, 112, 44, 81, 101, 187, 81, 14, 143, 32, 245, 168, 178, 237, 33, 196, 195, 44, 100, 81, 202, 2, 171, 95, 195, 83, 34, 200, 185, 68, 201, 18, 10, 7, 43, 189, 117, 178, 237, 33, 132, 71, 32, 252, 182, 135, 11, 119, 176, 190, 147, 7, 15, 179, 14, 44, 32, 0, 151, 204, 225, 147, 58, 111, 43, 177, 214, 131, 214, 103, 18, 169, 182, 192, 183, 61, 140, 120, 215, 222, 246, 112, 209, 171, 144, 99, 250, 15, 19, 140, 85, 203, 110, 64, 6, 62, 97, 219, 195, 5, 181, 19, 182, 61, 100, 152, 176, 237, 161, 66, 235, 183, 101, 183, 237, 161, 67, 223, 202, 9, 106, 188, 237, 225, 67, 233, 55, 59, 71, 3, 3, 80, 201, 4, 208, 148, 76, 227, 7, 72, 215, 14, 64, 83, 50, 156, 146, 41, 128, 166, 100, 190, 229, 123, 227, 7, 24, 208, 148, 204, 1, 92, 34, 223, 246, 112, 65, 132, 182, 109, 154, 58, 120, 211, 137, 148, 46, 179, 237, 33, 132, 97, 86, 109, 123, 170, 182, 61, 108, 232, 246, 67, 150, 231, 17, 143, 1, 92, 87, 66, 1, 79, 250, 100, 4, 72, 150, 20, 185, 178, 108, 232, 249, 214, 212, 160, 46, 147, 107, 123, 200, 104, 149, 228, 79, 180, 74, 242, 33, 68, 180, 170, 228, 5, 252, 45, 247, 224, 124, 186, 71, 37, 203, 74, 104, 115, 114, 135, 246, 115, 215, 118, 168, 85, 181, 135, 14, 202, 164, 51, 170, 218, 195, 70, 123, 200, 192, 61, 181, 135, 11, 21, 109, 180, 145, 243, 233, 80, 106, 15, 29, 34, 184, 173, 88, 218, 67, 7, 157, 236, 47, 219, 118, 168, 194, 75, 123, 248, 208, 30, 50, 86, 78, 20, 181, 135, 139, 230, 85, 176, 135, 11, 203, 30, 62, 150, 61, 84, 160, 216, 67, 5, 18, 79, 246, 112, 161, 113, 255, 122, 200, 160, 118, 61, 84, 88, 15, 3, 48, 217, 135, 10, 126, 37, 251, 112, 33, 130, 218, 135, 10, 202, 164, 35, 181, 15, 25, 15, 179, 13, 247, 196, 79, 161, 147, 244, 9, 143, 184, 34, 108, 188, 247, 50, 233, 225, 130, 159, 219, 181, 46, 15, 27, 30, 65, 249, 42, 30, 25, 94, 157, 97, 24, 85, 60, 54, 30, 231, 158, 199, 5, 143, 32, 118, 207, 227, 2, 53, 51, 15, 52, 13, 226, 77, 123, 152, 117, 207, 99, 195, 202, 180, 238, 121, 92, 52, 88, 251, 143, 226, 129, 55, 102, 140, 19, 90, 192, 85, 194, 19, 121, 164, 177, 227, 158, 199, 137, 214, 223, 166, 168, 123, 30, 29, 234, 75, 209, 245, 124, 163, 177, 67, 52, 118, 247, 32, 244, 33, 164, 51, 239, 186, 0, 114, 165, 18, 102, 7, 249, 74, 104, 37, 107, 30, 64, 211, 86, 169, 58, 98, 205, 186, 13, 177, 126, 192, 154, 17, 195, 19, 152, 45, 52, 53, 51, 220, 14, 121, 75, 71, 154, 146, 113, 224, 45, 29, 53, 117, 140, 52, 37, 147, 221, 234, 223, 152, 33, 77, 201, 168, 123, 30, 39, 84, 161, 196, 12, 150, 225, 193, 95, 161, 39, 187, 83, 121, 4, 2, 195, 145, 122, 215, 86, 17, 223, 234, 158, 8, 121, 180, 77, 39, 49, 188, 80, 150, 205, 61, 76, 67, 221, 243, 18, 13, 223, 180, 177, 123, 30, 29, 212, 61, 143, 10, 139, 85, 30, 21, 34, 84, 30, 21, 176, 231, 136, 41, 143, 139, 103, 202, 227, 227, 151, 242, 168, 160, 109, 41, 143, 11, 220, 41, 25, 132, 182, 148, 71, 7, 171, 218, 9, 132, 34, 177, 136, 6, 222, 181, 148, 71, 6, 95, 233, 94, 43, 212, 44, 229, 113, 194, 97, 35, 204, 148, 242, 184, 240, 8, 132, 214, 10, 85, 202, 163, 227, 177, 246, 31, 114, 88, 41, 219, 171, 82, 30, 27, 222, 84, 41, 143, 15, 173, 171, 223, 35, 3, 254, 30, 65, 76, 191, 199, 134, 75, 218, 46, 135, 55, 47, 253, 30, 25, 56, 238, 200, 177, 180, 181, 247, 15, 237, 123, 132, 120, 254, 177, 241, 252, 163, 130, 8, 13, 134, 97, 10, 227, 89, 35, 48, 255, 184, 208, 166, 109, 63, 254, 200, 72, 175, 200, 31, 23, 238, 249, 163, 130, 235, 74, 251, 157, 206, 31, 31, 201, 254, 168, 176, 152, 63, 42, 52, 188, 224, 223, 217, 216, 83, 106, 67, 26, 210, 171, 131, 193, 210, 150, 222, 164, 112, 64, 134, 101, 151, 63, 46, 232, 146, 164, 245, 199, 69, 69, 249, 163, 130, 242, 71, 5, 238, 124, 186, 228, 143, 12, 7, 220, 249, 116, 200, 193, 159, 226, 186, 150, 65, 201, 31, 27, 201, 31, 21, 40, 75, 127, 92, 104, 236, 17, 8, 249, 169, 32, 248, 35, 164, 185, 130, 252, 145, 193, 191, 217, 85, 20, 41, 245, 215, 30, 242, 199, 8, 117, 207, 47, 245, 199, 7, 242, 199, 136, 198, 141, 161, 238, 121, 135, 247, 68, 234, 143, 13, 254, 8, 209, 2, 109, 153, 164, 74, 5, 50, 84, 42, 48, 0, 170, 229, 251, 171, 192, 69, 107, 5, 54, 90, 85, 211, 174, 192, 5, 99, 174, 64, 135, 71, 32, 104, 227, 10, 92, 84, 224, 194, 35, 203, 174, 10, 100, 72, 237, 241, 198, 195, 236, 178, 171, 2, 31, 150, 93, 21, 168, 224, 254, 29, 180, 128, 189, 126, 111, 251, 128, 175, 132, 36, 218, 74, 220, 86, 32, 131, 171, 226, 228, 182, 2, 25, 110, 43, 208, 209, 171, 144, 219, 10, 92, 76, 96, 220, 90, 129, 12, 222, 180, 229, 214, 10, 116, 224, 119, 90, 129, 11, 90, 129, 140, 181, 184, 147, 55, 173, 192, 134, 227, 207, 161, 166, 21, 200, 240, 71, 77, 43, 208, 193, 149, 101, 5, 46, 168, 111, 179, 178, 2, 27, 222, 119, 101, 235, 247, 96, 195, 189, 7, 21, 120, 36, 177, 218, 247, 32, 99, 223, 131, 10, 84, 115, 242, 85, 40, 66, 155, 19, 90, 234, 159, 127, 176, 209, 238, 104, 125, 114, 57, 132, 14, 78, 122, 252, 224, 194, 147, 206, 15, 46, 240, 131, 1, 104, 15, 6, 224, 65, 199, 235, 245, 160, 130, 71, 30, 84, 208, 158, 132, 171, 165, 251, 32, 132, 155, 235, 131, 11, 239, 250, 15, 136, 230, 79, 172, 80, 75, 198, 250, 96, 195, 123, 234, 131, 11, 157, 250, 160, 66, 91, 230, 158, 30, 92, 172, 138, 124, 80, 97, 85, 188, 124, 112, 65, 194, 236, 180, 206, 7, 25, 204, 53, 212, 252, 208, 207, 180, 203, 61, 165, 10, 162, 117, 62, 248, 160, 61, 7, 136, 47, 252, 203, 198, 77, 231, 131, 141, 197, 236, 242, 65, 6, 143, 160, 202, 99, 249, 32, 163, 85, 37, 63, 190, 237, 106, 120, 100, 209, 152, 132, 22, 203, 135, 241, 251, 75, 136, 129, 126, 79, 180, 88, 62, 248, 192, 242, 65, 5, 15, 46, 210, 202, 7, 21, 158, 36, 31, 84, 216, 215, 124, 112, 161, 241, 230, 131, 143, 54, 1, 8, 30, 84, 64, 15, 62, 252, 193, 199, 162, 176, 225, 17, 199, 211, 169, 84, 144, 177, 48, 147, 10, 42, 32, 164, 130, 13, 137, 95, 6, 177, 214, 175, 224, 3, 107, 253, 10, 46, 184, 123, 5, 31, 238, 21, 84, 224, 17, 8, 206, 167, 67, 206, 167, 171, 84, 112, 33, 185, 94, 172, 130, 12, 203, 29, 185, 127, 103, 177, 10, 74, 104, 59, 114, 176, 196, 106, 177, 10, 50, 44, 86, 193, 134, 119, 58, 105, 177, 10, 50, 22, 171, 68, 88, 172, 194, 82, 251, 181, 185, 130, 42, 184, 192, 85, 113, 163, 153, 85, 80, 194, 35, 104, 177, 10, 50, 176, 10, 54, 240, 187, 167, 19, 90, 172, 130, 142, 183, 160, 197, 42, 8, 177, 88, 5, 21, 248, 170, 60, 199, 14, 85, 124, 85, 176, 161, 226, 171, 130, 10, 30, 241, 85, 193, 5, 134, 217, 85, 193, 133, 8, 237, 84, 80, 161, 157, 10, 62, 36, 137, 25, 106, 167, 130, 140, 118, 42, 168, 64, 21, 55, 196, 173, 21, 108, 44, 85, 65, 5, 189, 202, 241, 236, 71, 141, 170, 32, 164, 87, 169, 231, 130, 26, 85, 193, 135, 126, 170, 74, 165, 130, 11, 30, 137, 80, 65, 133, 9, 36, 136, 80, 65, 133, 231, 118, 200, 189, 130, 42, 157, 28, 61, 217, 168, 130, 13, 141, 247, 83, 123, 76, 131, 47, 170, 160, 195, 35, 13, 91, 84, 193, 6, 93, 75, 254, 42, 69, 21, 116, 60, 21, 21, 143, 130, 11, 19, 64, 204, 83, 112, 193, 41, 24, 128, 197, 242, 89, 44, 31, 72, 35, 113, 232, 161, 177, 71, 28, 107, 25, 244, 64, 127, 155, 130, 11, 78, 122, 109, 10, 50, 56, 169, 105, 83, 144, 65, 215, 190, 203, 166, 32, 131, 129, 194, 197, 226, 160, 39, 101, 163, 107, 0, 217, 20, 108, 180, 174, 166, 101, 83, 144, 177, 46, 29, 133, 130, 12, 201, 53, 106, 117, 52, 176, 78, 6, 181, 82, 88, 181, 117, 160, 56, 156, 165, 74, 52, 109, 255, 177, 186, 77, 250, 224, 12, 154, 182, 78, 202, 164, 237, 156, 3, 9, 109, 134, 52, 181, 228, 2, 235, 42, 170, 214, 190, 6, 7, 239, 153, 84, 114, 63, 144, 218, 227, 72, 181, 199, 221, 72, 82, 46, 168, 194, 139, 164, 153, 130, 13, 60, 226, 178, 41, 46, 155, 162, 154, 41, 200, 112, 217, 148, 134, 106, 166, 160, 35, 37, 141, 41, 184, 32, 129, 9, 60, 204, 98, 10, 82, 44, 236, 53, 10, 46, 84, 36, 20, 84, 192, 40, 199, 191, 216, 59, 18, 74, 83, 199, 14, 206, 47, 5, 27, 36, 212, 73, 153, 212, 45, 5, 31, 34, 26, 94, 254, 248, 55, 59, 1, 172, 205, 254, 86, 151, 110, 81, 220, 52, 102, 15, 188, 21, 14, 142, 231, 59, 132, 100, 189, 5, 61, 171, 105, 120, 77, 164, 125, 207, 165, 11, 116, 45, 131, 208, 179, 54, 213, 3, 39, 125, 82, 212, 227, 149, 144, 68, 227, 247, 7, 95, 204, 143, 212, 196, 83, 225, 118, 200, 217, 61, 88, 201, 16, 188, 16, 133, 85, 91, 10, 50, 104, 233, 164, 182, 20, 92, 244, 127, 182, 165, 224, 66, 61, 117, 105, 163, 182, 20, 124, 72, 154, 25, 212, 150, 130, 12, 181, 150, 130, 14, 181, 150, 130, 15, 102, 41, 168, 64, 155, 90, 10, 62, 190, 181, 45, 106, 210, 82, 208, 209, 180, 109, 237, 53, 90, 244, 56, 20, 156, 120, 178, 59, 35, 188, 189, 70, 13, 204, 49, 116, 61, 197, 12, 162, 238, 121, 212, 246, 215, 62, 9, 165, 21, 94, 208, 2, 39, 173, 67, 193, 133, 87, 135, 130, 143, 71, 165, 54, 98, 172, 80, 83, 135, 130, 14, 77, 29, 10, 42, 44, 85, 135, 130, 11, 104, 129, 213, 207, 161, 238, 121, 101, 203, 156, 244, 202, 64, 26, 202, 167, 67, 193, 7, 231, 27, 210, 161, 160, 35, 130, 9, 120, 67, 193, 5, 165, 19, 110, 199, 22, 189, 54, 20, 108, 120, 109, 40, 168, 128, 13, 71, 107, 181, 85, 10, 50, 124, 231, 187, 68, 149, 130, 13, 137, 230, 135, 89, 73, 74, 202, 162, 20, 116, 172, 9, 190, 40, 5, 25, 36, 64, 240, 80, 202, 178, 25, 4, 129, 141, 244, 173, 77, 107, 231, 226, 120, 248, 138, 182, 7, 232, 233, 215, 22, 128, 196, 87, 177, 108, 212, 252, 153, 252, 49, 11, 175, 108, 173, 175, 77, 43, 115, 60, 29, 36, 129, 98, 16, 13, 175, 199, 194, 171, 65, 223, 236, 216, 46, 240, 236, 176, 227, 159, 172, 185, 129, 75, 218, 115, 18, 114, 252, 45, 6, 73, 82, 186, 237, 111, 138, 158, 213, 184, 178, 204, 3, 18, 19, 101, 128, 156, 234, 131, 136, 207, 212, 120, 193, 62, 218, 166, 147, 26, 90, 151, 106, 90, 177, 222, 64, 171, 90, 219, 100, 243, 230, 45, 239, 202, 108, 75, 134, 252, 213, 189, 129, 59, 224, 194, 27, 175, 47, 181, 139, 82, 80, 98, 53, 139, 82, 36, 190, 49, 179, 40, 5, 27, 22, 165, 224, 2, 222, 71, 196, 162, 20, 92, 96, 146, 106, 81, 10, 50, 104, 115, 66, 252, 238, 233, 180, 40, 101, 81, 10, 46, 180, 109, 211, 36, 44, 74, 65, 10, 239, 69, 41, 72, 225, 154, 210, 45, 74, 65, 135, 175, 44, 22, 165, 32, 100, 81, 10, 50, 240, 8, 242, 198, 187, 40, 5, 35, 42, 234, 82, 41, 144, 100, 146, 84, 10, 66, 188, 94, 72, 146, 74, 65, 135, 212, 158, 198, 0, 210, 73, 204, 34, 18, 154, 214, 41, 3, 7, 90, 63, 98, 162, 1, 175, 162, 32, 133, 162, 96, 0, 222, 179, 201, 68, 193, 6, 255, 182, 236, 158, 164, 96, 163, 105, 249, 36, 133, 233, 231, 58, 73, 10, 54, 168, 199, 188, 116, 162, 10, 53, 246, 79, 10, 50, 240, 181, 255, 30, 146, 169, 147, 28, 34, 183, 245, 183, 19, 146, 208, 182, 171, 245, 147, 130, 141, 8, 19, 146, 148, 174, 241, 48, 235, 164, 79, 10, 46, 160, 131, 118, 82, 80, 161, 105, 73, 65, 135, 171, 100, 37, 5, 25, 122, 149, 100, 37, 5, 23, 206, 167, 67, 238, 65, 36, 41, 23, 36, 89, 73, 193, 134, 100, 37, 5, 21, 26, 163, 223, 164, 224, 98, 177, 10, 74, 18, 40, 24, 161, 44, 219, 163, 18, 148, 36, 80, 240, 177, 240, 90, 80, 146, 64, 65, 70, 99, 143, 32, 10, 50, 84, 42, 19, 84, 224, 21, 125, 19, 84, 209, 55, 153, 112, 181, 116, 25, 228, 146, 61, 184, 231, 74, 168, 162, 111, 130, 14, 7, 92, 100, 235, 155, 224, 66, 3, 238, 218, 78, 223, 4, 25, 250, 38, 216, 80, 7, 143, 56, 233, 113, 4, 3, 119, 201, 32, 28, 18, 65, 146, 214, 233, 167, 66, 17, 52, 37, 138, 160, 111, 130, 15, 173, 43, 223, 247, 78, 146, 255, 162, 31, 255, 42, 125, 79, 254, 199, 227, 220, 190, 3, 145, 0, 130, 8, 68, 112, 109, 160, 23, 44, 253, 8, 105, 155, 137, 67, 107, 235, 210, 113, 180, 114, 19, 75, 60, 42, 249, 102, 167, 181, 85, 53, 109, 254, 181, 184, 147, 35, 125, 147, 201, 126, 210, 94, 69, 241, 248, 54, 243, 109, 55, 225, 34, 160, 198, 187, 191, 94, 190, 50, 164, 47, 45, 122, 186, 177, 39, 115, 60, 21, 47, 71, 171, 199, 65, 79, 69, 174, 198, 255, 111, 65, 30, 161, 88, 169, 152, 33, 143, 52, 19, 215, 223, 182, 76, 91, 138, 79, 217, 95, 81, 212, 38, 0, 193, 182, 9, 64, 176, 140, 38, 191, 209, 213, 48, 55, 13, 116, 45, 249, 72, 49, 55, 218, 180, 178, 149, 15, 190, 41, 107, 178, 25, 214, 204, 60, 154, 54, 137, 213, 50, 85, 250, 169, 60, 2, 193, 143, 190, 61, 214, 149, 48, 59, 154, 23, 55, 20, 51, 85, 172, 56, 130, 195, 179, 26, 163, 135, 39, 41, 41, 73, 187, 82, 68, 2, 30, 102, 95, 223, 132, 129, 54, 210, 245, 32, 192, 193, 174, 5, 30, 249, 78, 231, 241, 38, 8, 225, 127, 15, 74, 255, 57, 198, 9, 165, 246, 184, 4, 175, 197, 206, 225, 105, 255, 89, 217, 18, 233, 155, 96, 3, 179, 56, 244, 19, 100, 208, 55, 217, 126, 14, 2, 232, 39, 251, 138, 254, 67, 243, 156, 175, 230, 248, 138, 126, 1, 22, 63, 240, 77, 119, 165, 5, 201, 117, 99, 143, 56, 48, 192, 222, 97, 224, 233, 87, 166, 75, 31, 185, 39, 164, 138, 147, 79, 112, 1, 77, 62, 65, 5, 215, 245, 186, 39, 184, 192, 41, 60, 65, 5, 125, 250, 38, 32, 10, 79, 176, 225, 12, 162, 240, 4, 25, 86, 186, 230, 9, 50, 168, 229, 137, 145, 168, 100, 171, 73, 227, 131, 196, 233, 68, 30, 6, 57, 144, 67, 202, 49, 165, 142, 202, 6, 147, 17, 40, 210, 3, 97, 44, 20, 137, 2, 73, 21, 133, 15, 20, 0, 3, 14, 64, 173, 25, 205, 76, 19, 164, 76, 169, 170, 13, 64, 16, 0, 4, 109, 75, 111, 237, 120, 170, 176, 201, 1, 78, 65, 242, 207, 98, 231, 248, 155, 37, 98, 142, 118, 116, 122, 6, 69, 240, 26, 157, 196, 61, 207, 229, 171, 211, 118, 68, 198, 142, 40, 103, 168, 102, 48, 188, 43, 26, 45, 249, 235, 140, 168, 165, 124, 54, 255, 142, 34, 25, 28, 15, 15, 7, 51, 179, 7, 109, 171, 165, 175, 67, 121, 9, 25, 190, 128, 198, 47, 71, 166, 61, 171, 12, 194, 125, 81, 62, 133, 61, 176, 25, 172, 66, 207, 46, 240, 250, 136, 21, 95, 93, 21, 109, 2, 45, 170, 136, 127, 78, 167, 63, 71, 118, 198, 110, 67, 167, 243, 24, 31, 119, 14, 61, 110, 109, 68, 17, 154, 243, 229, 149, 199, 135, 120, 58, 46, 81, 50, 71, 174, 122, 85, 31, 36, 158, 218, 166, 121, 26, 120, 230, 52, 172, 117, 155, 193, 237, 43, 141, 84, 148, 247, 191, 123, 49, 197, 218, 15, 73, 29, 124, 250, 198, 47, 7, 129, 50, 172, 194, 193, 55, 97, 35, 146, 73, 103, 73, 25, 137, 248, 242, 119, 10, 222, 11, 114, 8, 161, 29, 217, 2, 31, 195, 156, 139, 31, 144, 19, 49, 77, 243, 250, 250, 158, 29, 91, 131, 133, 11, 173, 87, 119, 15, 209, 216, 4, 111, 201, 119, 204, 170, 12, 229, 220, 185, 218, 97, 208, 149, 132, 246, 107, 162, 130, 91, 222, 97, 123, 201, 73, 22, 157, 3, 139, 213, 122, 136, 16, 211, 171, 145, 253, 126, 175, 213, 63, 36, 80, 40, 74, 46, 229, 152, 185, 30, 29, 213, 127, 236, 167, 160, 71, 141, 178, 173, 45, 2, 4, 65, 100, 96, 16, 109, 18, 223, 179, 37, 88, 62, 97, 198, 128, 89, 31, 28, 171, 155, 67, 234, 24, 166, 229, 210, 1, 36, 125, 123, 33, 32, 159, 235, 21, 154, 114, 49, 161, 209, 38, 248, 131, 160, 239, 52, 206, 165, 78, 153, 191, 179, 16, 42, 160, 128, 112, 38, 251, 192, 90, 206, 130, 88, 119, 70, 252, 18, 11, 179, 240, 5, 100, 198, 75, 115, 52, 66, 150, 128, 138, 172, 98, 221, 8, 158, 17, 246, 14, 141, 120, 235, 229, 96, 229, 38, 166, 254, 35, 123, 81, 186, 64, 22, 66, 16, 101, 234, 75, 141, 194, 154, 204, 160, 33, 197, 1, 164, 244, 196, 56, 52, 1, 230, 17, 165, 50, 203, 106, 231, 107, 255, 71, 126, 255, 83, 70, 32, 14, 208, 139, 229, 226, 138, 222, 163, 27, 134, 240, 219, 246, 188, 154, 62, 151, 167, 106, 0, 111, 96, 182, 220, 50, 223, 221, 34, 135, 240, 83, 156, 114, 29, 53, 107, 46, 148, 169, 111, 250, 153, 57, 135, 197, 216, 102, 163, 127, 53, 245, 203, 58, 142, 97, 151, 166, 77, 26, 90, 165, 113, 133, 3, 211, 169, 168, 233, 135, 37, 226, 23, 139, 175, 179, 198, 136, 20, 22, 109, 224, 185, 222, 51, 2, 77, 1, 21, 91, 58, 141, 1, 254, 39, 222, 220, 161, 150, 232, 214, 206, 133, 116, 175, 101, 131, 104, 229, 86, 114, 173, 94, 26, 84, 77, 121, 235, 211, 159, 120, 165, 227, 125, 45, 11, 6, 120, 215, 203, 97, 132, 167, 107, 114, 2, 63, 167, 80, 100, 118, 8, 168, 20, 10, 88, 130, 247, 36, 104, 167, 86, 49, 242, 147, 141, 55, 121, 206, 224, 73, 188, 54, 218, 224, 30, 234, 52, 66, 117, 125, 196, 8, 206, 95, 111, 5, 137, 155, 199, 14, 204, 128, 209, 175, 40, 9, 170, 39, 57, 63, 34, 25, 41, 144, 20, 52, 191, 143, 140, 47, 200, 15, 254, 180, 209, 74, 88, 18, 237, 88, 104, 188, 136, 146, 188, 32, 113, 74, 111, 82, 169, 247, 76, 73, 222, 208, 129, 181, 51, 131, 210, 3, 142, 9, 254, 221, 46, 51, 186, 85, 24, 193, 137, 43, 2, 177, 133, 141, 182, 235, 30, 173, 240, 78, 104, 184, 120, 239, 75, 106, 178, 243, 105, 169, 57, 11, 252, 172, 139, 247, 36, 4, 3, 60, 142, 188, 214, 138, 149, 137, 212, 43, 30, 208, 251, 181, 41, 81, 153, 107, 139, 70, 60, 202, 192, 178, 31, 69, 153, 26, 178, 170, 5, 27, 159, 164, 135, 6, 75, 231, 231, 210, 179, 22, 92, 107, 192, 110, 86, 174, 53, 125, 52, 210, 243, 11, 243, 206, 53, 185, 58, 34, 50, 117, 222, 30, 26, 97, 122, 209, 129, 141, 246, 76, 101, 208, 79, 111, 243, 217, 105, 178, 227, 88, 219, 40, 54, 211, 46, 12, 238, 22, 201, 176, 24, 246, 117, 145, 177, 7, 158, 173, 6, 203, 30, 67, 205, 203, 18, 44, 171, 177, 238, 84, 167, 123, 168, 52, 65, 199, 170, 77, 117, 50, 201, 0, 42, 105, 27, 193, 91, 60, 152, 238, 83, 218, 246, 151, 33, 138, 16, 172, 65, 228, 30, 38, 200, 137, 214, 31, 140, 12, 227, 197, 164, 80, 251, 215, 153, 59, 87, 118, 248, 74, 117, 152, 44, 112, 169, 155, 66, 63, 219, 82, 190, 113, 213, 217, 15, 80, 28, 133, 75, 234, 156, 56, 109, 240, 28, 229, 19, 244, 25, 106, 11, 28, 210, 191, 115, 178, 226, 128, 7, 130, 213, 90, 188, 33, 63, 184, 31, 99, 153, 36, 128, 28, 123, 36, 197, 40, 166, 51, 83, 234, 195, 42, 92, 172, 162, 110, 231, 8, 171, 250, 65, 99, 198, 137, 235, 224, 73, 81, 207, 4, 250, 204, 78, 72, 102, 82, 141, 85, 202, 92, 226, 36, 230, 22, 137, 67, 234, 142, 136, 96, 14, 83, 162, 53, 9, 7, 165, 66, 241, 199, 74, 141, 188, 63, 253, 107, 148, 2, 248, 65, 138, 123, 227, 220, 48, 249, 213, 32, 2, 252, 42, 190, 107, 99, 205, 110, 239, 3, 119, 218, 246, 52, 167, 46, 50, 232, 66, 164, 80, 68, 64, 194, 41, 8, 0, 25, 216, 162, 206, 222, 137, 107, 149, 114, 205, 198, 16, 67, 146, 212, 141, 181, 149, 247, 252, 14, 66, 173, 223, 125, 254, 126, 152, 34, 75, 107, 91, 204, 195, 185, 206, 199, 232, 6, 226, 128, 104, 142, 209, 160, 21, 238, 81, 44, 113, 3, 230, 250, 236, 161, 142, 124, 40, 106, 132, 206, 233, 89, 99, 100, 226, 246, 177, 31, 127, 158, 221, 200, 67, 35, 143, 140, 9, 22, 99, 102, 143, 127, 120, 255, 225, 234, 103, 88, 205, 128, 128, 156, 166, 127, 60, 20, 180, 231, 246, 237, 66, 13, 97, 121, 166, 188, 236, 4, 62, 227, 174, 89, 64, 34, 176, 95, 159, 49, 41, 137, 69, 199, 48, 188, 93, 219, 103, 140, 33, 11, 199, 65, 241, 100, 133, 160, 3, 18, 26, 119, 136, 229, 38, 129, 136, 121, 34, 168, 144, 85, 241, 96, 72, 29, 93, 16, 4, 136, 97, 53, 59, 183, 36, 44, 141, 140, 136, 131, 91, 74, 19, 4, 207, 189, 0, 227, 93, 81, 151, 91, 67, 216, 122, 118, 153, 22, 246, 242, 231, 69, 102, 95, 173, 97, 72, 66, 136, 12, 217, 206, 79, 140, 24, 11, 79, 251, 209, 203, 35, 198, 121, 231, 229, 6, 214, 88, 132, 224, 126, 255, 176, 129, 36, 204, 94, 130, 235, 86, 226, 14, 197, 149, 44, 136, 165, 139, 195, 229, 180, 195, 241, 164, 112, 219, 37, 62, 195, 245, 100, 77, 180, 229, 144, 60, 222, 135, 160, 63, 106, 78, 34, 17, 216, 152, 173, 81, 27, 1, 44, 232, 36, 81, 104, 58, 47, 32, 100, 164, 211, 188, 125, 238, 219, 179, 131, 97, 199, 137, 25, 205, 162, 200, 145, 197, 38, 220, 24, 102, 152, 150, 158, 43, 234, 238, 66, 49, 90, 131, 174, 97, 219, 26, 117, 38, 36, 82, 247, 130, 156, 205, 161, 248, 80, 56, 181, 70, 137, 146, 17, 103, 30, 168, 35, 99, 3, 7, 215, 81, 169, 118, 55, 162, 131, 132, 124, 156, 193, 241, 85, 147, 187, 47, 54, 51, 125, 20, 241, 20, 2, 41, 229, 62, 1, 73, 240, 126, 190, 178, 71, 69, 141, 94, 180, 131, 67, 102, 8, 233, 80, 73, 0, 137, 161, 142, 175, 0, 181, 86, 206, 144, 205, 103, 78, 53, 100, 139, 158, 99, 187, 111, 238, 109, 201, 241, 130, 246, 174, 163, 51, 123, 115, 225, 33, 255, 12, 41, 84, 69, 209, 109, 151, 96, 244, 151, 3, 201, 255, 96, 125, 221, 123, 239, 163, 182, 138, 138, 211, 200, 82, 228, 110, 239, 131, 44, 191, 123, 159, 156, 94, 133, 218, 142, 212, 20, 204, 53, 39, 71, 138, 197, 147, 130, 27, 240, 124, 116, 113, 175, 215, 58, 106, 133, 224, 9, 122, 175, 33, 23, 20, 105, 244, 166, 1, 167, 118, 19, 156, 50, 192, 195, 128, 104, 11, 14, 245, 88, 3, 174, 184, 169, 6, 74, 156, 128, 16, 68, 121, 198, 229, 50, 42, 176, 176, 144, 44, 60, 112, 243, 55, 105, 196, 184, 102, 91, 98, 202, 57, 77, 55, 3, 38, 102, 130, 51, 111, 14, 71, 16, 118, 208, 180, 36, 59, 37, 237, 59, 13, 253, 193, 65, 175, 92, 79, 64, 11, 31, 18, 22, 69, 86, 156, 188, 165, 63, 50, 105, 49, 18, 243, 114, 12, 222, 78, 3, 228, 175, 206, 231, 72, 59, 227, 42, 144, 198, 225, 19, 67, 27, 120, 192, 164, 5, 65, 42, 224, 33, 69, 218, 64, 176, 6, 217, 104, 169, 68, 229, 218, 167, 153, 63, 26, 41, 17, 202, 243, 12, 158, 44, 126, 84, 25, 123, 196, 72, 197, 135, 197, 101, 122, 191, 150, 226, 170, 135, 18, 107, 234, 63, 237, 94, 236, 227, 111, 120, 82, 193, 182, 52, 206, 104, 46, 234, 81, 23, 88, 116, 248, 108, 48, 1, 48, 224, 78, 162, 208, 197, 208, 223, 130, 202, 206, 60, 16, 56, 168, 240, 8, 236, 142, 216, 107, 200, 76, 111, 113, 208, 32, 13, 125, 137, 223, 163, 172, 14, 38, 32, 22, 177, 74, 204, 99, 133, 115, 241, 136, 232, 253, 159, 254, 10, 251, 114, 134, 179, 0, 161, 120, 211, 89, 35, 171, 183, 203, 244, 93, 1, 68, 226, 185, 162, 79, 90, 158, 189, 50, 138, 140, 213, 157, 193, 44, 153, 98, 228, 165, 31, 125, 231, 218, 227, 247, 27, 144, 177, 87, 202, 76, 177, 177, 53, 109, 142, 205, 233, 240, 33, 1, 99, 37, 93, 6, 131, 91, 90, 96, 193, 79, 93, 148, 73, 192, 197, 20, 52, 223, 108, 236, 179, 19, 132, 66, 186, 56, 102, 179, 253, 89, 73, 2, 235, 83, 198, 40, 96, 44, 102, 146, 46, 169, 83, 199, 47, 246, 150, 46, 109, 108, 22, 254, 126, 150, 9, 178, 41, 89, 64, 250, 213, 59, 79, 1, 244, 241, 234, 115, 98, 254, 65, 255, 57, 170, 52, 107, 66, 220, 186, 201, 89, 168, 10, 172, 179, 35, 64, 249, 77, 10, 247, 2, 18, 172, 205, 249, 222, 139, 12, 100, 170, 19, 227, 128, 16, 6, 114, 119, 238, 186, 239, 137, 248, 167, 92, 234, 55, 185, 107, 53, 153, 93, 155, 192, 110, 179, 205, 8, 153, 194, 237, 243, 203, 164, 98, 16, 217, 19, 56, 31, 248, 92, 68, 233, 200, 21, 182, 81, 250, 9, 20, 50, 144, 187, 251, 15, 112, 203, 42, 187, 23, 72, 60, 64, 191, 61, 86, 64, 158, 58, 196, 8, 154, 174, 30, 134, 63, 47, 75, 34, 37, 64, 70, 28, 71, 45, 126, 101, 5, 53, 224, 55, 131, 48, 193, 101, 47, 134, 186, 42, 33, 139, 111, 155, 224, 118, 149, 39, 113, 5, 115, 233, 10, 234, 171, 166, 229, 119, 156, 46, 142, 251, 136, 104, 141, 89, 204, 70, 186, 163, 201, 194, 100, 91, 202, 104, 186, 138, 59, 146, 178, 205, 30, 65, 180, 84, 252, 209, 3, 104, 240, 87, 70, 186, 159, 42, 177, 146, 202, 224, 12, 212, 201, 213, 153, 210, 57, 210, 248, 98, 254, 29, 32, 97, 185, 161, 108, 163, 129, 30, 7, 194, 181, 208, 198, 166, 212, 199, 224, 41, 38, 39, 135, 165, 0, 170, 159, 11, 89, 254, 21, 62, 205, 234, 106, 0, 34, 211, 99, 251, 21, 19, 96, 2, 87, 230, 112, 58, 22, 118, 90, 88, 169, 121, 193, 135, 88, 231, 199, 126, 92, 130, 166, 96, 54, 94, 15, 242, 32, 154, 89, 104, 68, 205, 96, 62, 26, 208, 50, 54, 157, 233, 33, 81, 119, 9, 160, 106, 227, 212, 41, 212, 67, 184, 103, 48, 192, 238, 84, 165, 216, 147, 210, 115, 111, 204, 27, 228, 166, 65, 203, 22, 59, 95, 190, 99, 11, 75, 78, 247, 225, 101, 151, 132, 170, 49, 180, 158, 246, 37, 201, 39, 123, 135, 220, 27, 11, 167, 112, 80, 230, 106, 222, 6, 247, 225, 31, 194, 71, 200, 131, 231, 45, 90, 156, 154, 232, 167, 170, 177, 237, 227, 119, 28, 55, 228, 236, 238, 39, 217, 50, 119, 196, 118, 58, 251, 215, 242, 158, 99, 185, 144, 92, 100, 54, 70, 46, 55, 75, 34, 7, 229, 14, 230, 142, 197, 187, 70, 205, 184, 84, 165, 174, 106, 88, 14, 34, 61, 31, 182, 23, 253, 12, 162, 15, 75, 97, 250, 12, 121, 46, 20, 228, 134, 253, 99, 234, 77, 215, 60, 79, 136, 31, 237, 138, 29, 140, 41, 23, 161, 248, 114, 31, 204, 57, 68, 251, 57, 129, 254, 238, 80, 121, 3, 36, 131, 95, 224, 238, 82, 171, 251, 120, 36, 54, 132, 51, 252, 54, 51, 224, 92, 147, 71, 59, 163, 0, 220, 235, 240, 63, 9, 64, 53, 216, 243, 45, 197, 172, 8, 128, 90, 142, 111, 253, 211, 246, 132, 135, 69, 238, 108, 176, 0, 27, 170, 29, 128, 185, 79, 0, 28, 20, 203, 187, 210, 42, 103, 117, 37, 146, 173, 238, 50, 71, 89, 168, 56, 153, 195, 240, 73, 243, 54, 132, 77, 86, 4, 67, 144, 18, 43, 22, 201, 42, 47, 112, 148, 26, 36, 248, 106, 102, 149, 109, 22, 239, 49, 125, 40, 207, 63, 170, 109, 250, 137, 124, 138, 162, 59, 181, 59, 104, 92, 84, 204, 41, 243, 11, 238, 140, 251, 124, 96, 34, 103, 205, 15, 103, 28, 31, 135, 135, 169, 109, 156, 15, 146, 88, 56, 32, 145, 202, 98, 26, 220, 183, 103, 206, 155, 153, 12, 229, 242, 159, 2, 27, 76, 236, 62, 111, 155, 67, 193, 137, 153, 4, 113, 139, 114, 34, 3, 174, 131, 14, 248, 85, 206, 93, 53, 27, 60, 145, 134, 206, 139, 234, 95, 197, 100, 141, 251, 244, 126, 224, 138, 66, 147, 145, 126, 144, 176, 161, 253, 52, 211, 112, 130, 203, 246, 230, 28, 196, 111, 224, 187, 29, 169, 176, 54, 64, 148, 77, 105, 80, 11, 172, 27, 133, 66, 74, 239, 14, 248, 40, 15, 40, 51, 180, 174, 93, 198, 216, 116, 169, 66, 249, 86, 118, 41, 141, 203, 30, 46, 196, 104, 50, 116, 140, 148, 22, 236, 95, 123, 212, 133, 132, 226, 136, 121, 83, 160, 218, 8, 155, 241, 141, 216, 16, 103, 212, 72, 246, 184, 233, 174, 42, 10, 148, 249, 214, 70, 76, 108, 133, 117, 170, 234, 183, 183, 58, 174, 67, 204, 100, 227, 57, 44, 236, 152, 74, 15, 225, 72, 92, 196, 93, 40, 1, 68, 53, 254, 128, 78, 178, 93, 193, 234, 133, 86, 160, 31, 139, 64, 123, 190, 94, 76, 221, 66, 83, 115, 217, 144, 195, 72, 109, 213, 158, 3, 33, 247, 113, 166, 29, 144, 125, 218, 141, 165, 149, 54, 227, 59, 230, 115, 153, 148, 226, 141, 61, 180, 247, 171, 103, 219, 88, 37, 1, 74, 64, 37, 55, 162, 27, 236, 34, 45, 24, 136, 71, 228, 211, 55, 5, 134, 137, 162, 166, 175, 75, 13, 230, 120, 212, 54, 133, 213, 13, 212, 4, 75, 141, 17, 248, 142, 201, 250, 5, 221, 163, 237, 12, 161, 28, 238, 54, 158, 171, 228, 241, 92, 6, 0, 81, 232, 157, 213, 166, 240, 149, 3, 113, 11, 68, 217, 104, 163, 44, 113, 158, 213, 129, 142, 169, 83, 128, 174, 159, 118, 192, 38, 166, 163, 1, 198, 235, 155, 12, 16, 156, 12, 21, 244, 216, 229, 30, 161, 210, 22, 35, 22, 117, 126, 237, 94, 7, 217, 143, 145, 188, 52, 104, 98, 103, 53, 225, 105, 49, 246, 72, 3, 53, 240, 210, 195, 27, 186, 43, 247, 24, 204, 81, 229, 242, 32, 97, 84, 239, 144, 247, 4, 84, 158, 212, 187, 14, 18, 4, 12, 88, 248, 37, 10, 225, 196, 28, 170, 41, 138, 32, 149, 30, 134, 240, 43, 63, 144, 55, 220, 192, 49, 179, 137, 88, 163, 118, 187, 115, 167, 230, 99, 71, 225, 136, 190, 250, 55, 29, 186, 209, 106, 249, 128, 137, 153, 173, 182, 206, 68, 108, 38, 17, 165, 211, 69, 183, 74, 75, 43, 189, 59, 81, 189, 108, 108, 161, 183, 4, 24, 213, 237, 145, 162, 209, 80, 110, 35, 125, 172, 242, 209, 135, 3, 47, 212, 183, 137, 131, 95, 148, 95, 62, 211, 138, 17, 206, 113, 108, 150, 15, 132, 147, 227, 65, 39, 108, 224, 222, 148, 167, 68, 47, 10, 35, 104, 77, 79, 57, 240, 199, 184, 236, 76, 184, 130, 167, 150, 221, 17, 116, 132, 135, 128, 90, 63, 149, 158, 32, 27, 228, 82, 235, 61, 29, 137, 135, 245, 134, 183, 172, 78, 150, 234, 243, 196, 68, 162, 80, 79, 63, 108, 251, 114, 40, 250, 180, 84, 215, 162, 255, 38, 126, 85, 181, 5, 122, 4, 46, 93, 4, 68, 237, 84, 160, 191, 255, 46, 160, 103, 118, 242, 126, 40, 214, 157, 129, 245, 101, 13, 236, 36, 243, 11, 0, 91, 229, 253, 187, 217, 117, 133, 3, 22, 84, 25, 68, 237, 53, 127, 36, 59, 0, 69, 6, 33, 119, 202, 100, 131, 170, 240, 138, 178, 10, 104, 63, 129, 237, 145, 53, 80, 160, 152, 191, 62, 87, 0, 46, 14, 44, 15, 181, 64, 114, 89, 156, 238, 183, 153, 199, 9, 4, 31, 41, 91, 240, 109, 188, 209, 54, 117, 214, 86, 210, 150, 231, 193, 192, 70, 103, 109, 220, 148, 144, 50, 100, 184, 197, 35, 4, 22, 39, 246, 65, 168, 134, 144, 151, 125, 65, 42, 9, 167, 46, 35, 220, 208, 188, 211, 115, 84, 28, 221, 254, 21, 54, 67, 63, 235, 214, 42, 108, 118, 91, 172, 249, 252, 172, 208, 154, 238, 152, 19, 3, 16, 227, 124, 68, 72, 176, 240, 36, 48, 13, 194, 216, 227, 147, 231, 16, 242, 32, 42, 23, 93, 204, 3, 206, 10, 141, 255, 94, 43, 37, 107, 174, 61, 165, 221, 27, 52, 144, 8, 138, 50, 46, 64, 184, 168, 144, 13, 240, 20, 72, 174, 105, 84, 5, 79, 112, 55, 230, 170, 37, 229, 197, 61, 209, 24, 171, 3, 35, 170, 168, 96, 254, 84, 149, 170, 114, 252, 101, 78, 60, 21, 88, 69, 214, 79, 140, 244, 150, 181, 197, 17, 69, 184, 194, 144, 32, 18, 202, 36, 146, 124, 28, 46, 218, 237, 137, 139, 169, 242, 0, 122, 218, 44, 162, 77, 23, 221, 129, 111, 172, 145, 215, 86, 43, 197, 176, 242, 197, 38, 224, 189, 169, 229, 0, 20, 96, 50, 139, 4, 13, 213, 152, 45, 231, 24, 122, 11, 106, 2, 244, 114, 179, 184, 10, 12, 244, 131, 160, 22, 145, 48, 136, 195, 101, 65, 8, 210, 237, 182, 111, 4, 42, 50, 190, 43, 134, 121, 52, 197, 165, 89, 188, 30, 226, 161, 50, 182, 104, 200, 166, 254, 251, 178, 9, 14, 69, 204, 74, 147, 182, 204, 18, 97, 247, 255, 10, 191, 221, 122, 72, 106, 173, 224, 247, 239, 23, 93, 79, 108, 207, 58, 202, 143, 217, 194, 55, 99, 147, 192, 171, 139, 19, 49, 204, 51, 137, 63, 238, 115, 140, 41, 12, 27, 194, 16, 50, 168, 155, 208, 27, 33, 229, 87, 219, 56, 37, 100, 62, 97, 215, 183, 41, 134, 54, 211, 199, 33, 109, 83, 184, 155, 13, 156, 140, 180, 220, 142, 220, 57, 232, 80, 151, 241, 250, 170, 52, 224, 59, 38, 10, 214, 33, 219, 21, 82, 10, 227, 243, 215, 241, 165, 244, 248, 115, 103, 1, 28, 111, 6, 135, 178, 161, 167, 193, 5, 39, 62, 100, 216, 217, 155, 211, 203, 128, 81, 161, 77, 44, 82, 85, 255, 30, 80, 161, 236, 128, 216, 9, 229, 56, 174, 224, 68, 69, 25, 119, 169, 240, 7, 229, 5, 149, 141, 47, 195, 102, 190, 163, 179, 195, 64, 207, 61, 154, 71, 100, 111, 192, 98, 205, 22, 243, 108, 217, 14, 228, 118, 44, 87, 247, 34, 171, 180, 164, 124, 187, 194, 161, 39, 140, 22, 63, 147, 114, 190, 241, 248, 33, 44, 226, 29, 195, 99, 36, 213, 180, 66, 3, 7, 91, 49, 150, 140, 233, 99, 57, 0, 197, 106, 6, 93, 147, 230, 140, 51, 124, 154, 97, 181, 225, 247, 163, 35, 64, 5, 127, 110, 225, 62, 121, 23, 180, 214, 110, 230, 61, 127, 57, 36, 180, 102, 130, 75, 102, 155, 195, 154, 204, 254, 189, 198, 20, 142, 55, 155, 172, 181, 221, 78, 98, 177, 117, 165, 40, 52, 57, 72, 1, 246, 213, 159, 72, 190, 31, 1, 130, 136, 177, 107, 25, 127, 211, 228, 27, 115, 158, 59, 21, 83, 96, 82, 83, 78, 151, 73, 224, 226, 200, 79, 24, 11, 139, 201, 166, 188, 99, 228, 10, 203, 185, 161, 36, 167, 119, 158, 107, 165, 221, 161, 174, 87, 61, 239, 20, 255, 96, 122, 181, 239, 138, 8, 155, 82, 37, 24, 168, 227, 21, 177, 28, 252, 190, 236, 89, 243, 60, 232, 103, 12, 126, 129, 246, 143, 27, 220, 252, 141, 96, 57, 123, 250, 121, 43, 212, 247, 125, 148, 33, 204, 137, 190, 145, 57, 101, 52, 101, 78, 219, 199, 194, 126, 106, 250, 86, 44, 141, 40, 54, 67, 131, 80, 228, 105, 117, 39, 240, 128, 208, 17, 215, 11, 32, 205, 2, 75, 200, 89, 219, 28, 205, 141, 117, 3, 36, 58, 156, 18, 95, 7, 220, 252, 7, 146, 100, 221, 69, 120, 42, 233, 247, 2, 143, 214, 188, 58, 214, 99, 212, 91, 176, 9, 117, 105, 22, 0, 54, 26, 131, 171, 61, 54, 73, 51, 100, 178, 32, 183, 148, 180, 44, 211, 42, 251, 138, 157, 218, 244, 165, 0, 136, 40, 235, 192, 96, 65, 41, 8, 116, 114, 238, 41, 69, 200, 36, 38, 75, 46, 49, 233, 130, 9, 192, 57, 3, 132, 31, 129, 229, 96, 211, 88, 150, 88, 135, 115, 51, 242, 53, 239, 34, 181, 206, 166, 191, 126, 161, 78, 134, 189, 234, 187, 73, 54, 177, 160, 242, 183, 54, 231, 36, 57, 127, 88, 252, 167, 112, 141, 34, 51, 11, 9, 242, 221, 44, 252, 147, 250, 150, 130, 253, 149, 211, 14, 128, 75, 230, 68, 63, 2, 101, 233, 1, 58, 32, 24, 141, 146, 26, 21, 234, 83, 111, 16, 230, 187, 229, 152, 84, 156, 173, 80, 81, 249, 76, 162, 41, 213, 27, 116, 151, 13, 3, 101, 21, 10, 86, 12, 80, 192, 118, 104, 133, 14, 0, 19, 94, 45, 238, 229, 92, 229, 32, 159, 80, 84, 178, 110, 14, 102, 97, 127, 136, 172, 5, 180, 38, 114, 82, 196, 67, 140, 218, 180, 253, 26, 217, 160, 0, 125, 2, 211, 3, 173, 198, 92, 217, 167, 195, 177, 114, 214, 11, 169, 243, 69, 112, 238, 2, 121, 54, 163, 138, 43, 144, 39, 96, 145, 201, 251, 165, 166, 228, 248, 51, 55, 230, 24, 194, 83, 112, 125, 245, 213, 36, 79, 51, 79, 168, 198, 164, 236, 143, 176, 131, 243, 161, 201, 46, 54, 132, 9, 14, 154, 182, 31, 122, 35, 238, 233, 115, 224, 83, 44, 176, 26, 15, 31, 1, 160, 104, 18, 235, 103, 107, 1, 35, 221, 74, 206, 8, 207, 168, 166, 147, 51, 189, 213, 6, 244, 172, 145, 114, 56, 83, 121, 231, 215, 136, 174, 58, 174, 7, 7, 197, 1, 1, 125, 219, 115, 221, 25, 96, 85, 3, 84, 218, 47, 191, 148, 134, 97, 114, 195, 228, 121, 5, 246, 10, 236, 83, 85, 149, 179, 42, 154, 148, 51, 43, 192, 175, 226, 7, 128, 38, 31, 224, 253, 76, 199, 37, 214, 163, 56, 83, 74, 238, 47, 117, 139, 224, 68, 75, 114, 0, 161, 88, 29, 134, 54, 0, 209, 128, 171, 150, 147, 177, 37, 136, 69, 253, 89, 179, 182, 182, 129, 43, 66, 66, 166, 122, 229, 14, 203, 70, 224, 38, 57, 147, 253, 178, 93, 201, 209, 3, 61, 29, 201, 12, 224, 69, 215, 123, 221, 204, 40, 198, 0, 60, 131, 98, 92, 63, 215, 92, 84, 230, 186, 64, 76, 239, 206, 243, 182, 224, 248, 52, 68, 151, 193, 126, 238, 86, 66, 89, 164, 231, 3, 68, 92, 5, 133, 241, 173, 96, 244, 149, 127, 102, 188, 225, 225, 199, 181, 57, 58, 236, 245, 151, 65, 26, 41, 47, 84, 34, 18, 220, 240, 249, 129, 83, 195, 163, 216, 167, 229, 159, 139, 254, 230, 24, 95, 17, 3, 212, 112, 22, 132, 55, 235, 139, 43, 52, 5, 180, 64, 156, 237, 225, 44, 76, 230, 113, 77, 39, 249, 183, 75, 245, 23, 229, 33, 3, 255, 236, 41, 64, 197, 104, 98, 86, 113, 10, 97, 25, 232, 124, 28, 28, 13, 28, 5, 0, 76, 223, 89, 151, 78, 120, 139, 143, 23, 80, 70, 17, 185, 14, 76, 220, 4, 140, 132, 111, 71, 40, 67, 166, 146, 48, 10, 199, 51, 72, 10, 207, 66, 236, 30, 131, 16, 199, 104, 159, 95, 112, 223, 199, 155, 158, 231, 212, 162, 86, 80, 72, 203, 7, 71, 69, 143, 120, 84, 39, 69, 20, 19, 129, 61, 83, 135, 140, 137, 135, 203, 237, 204, 128, 97, 253, 214, 98, 104, 214, 57, 104, 31, 185, 67, 108, 147, 133, 178, 191, 153, 253, 17, 91, 149, 88, 215, 128, 103, 204, 95, 44, 137, 163, 117, 134, 129, 225, 185, 62, 180, 16, 71, 75, 123, 94, 10, 140, 37, 137, 217, 1, 204, 195, 70, 85, 57, 15, 47, 16, 22, 62, 22, 152, 207, 75, 135, 103, 142, 1, 10, 166, 177, 174, 152, 62, 125, 202, 98, 92, 153, 103, 19, 164, 53, 181, 76, 113, 146, 65, 17, 185, 94, 193, 156, 254, 185, 59, 100, 173, 227, 33, 17, 202, 189, 127, 255, 246, 97, 167, 94, 48, 168, 119, 119, 141, 122, 205, 213, 26, 16, 231, 11, 86, 94, 38, 116, 105, 177, 52, 147, 41, 211, 150, 137, 95, 237, 18, 245, 10, 209, 100, 209, 3, 84, 180, 213, 47, 251, 48, 51, 81, 101, 188, 67, 111, 243, 231, 65, 95, 163, 138, 2, 156, 129, 245, 98, 146, 246, 212, 166, 160, 147, 75, 176, 2, 193, 65, 230, 199, 117, 21, 56, 134, 163, 186, 115, 148, 207, 251, 145, 153, 232, 227, 97, 195, 93, 243, 90, 112, 35, 168, 151, 232, 225, 196, 156, 207, 188, 208, 79, 109, 82, 148, 83, 159, 63, 96, 211, 132, 178, 248, 83, 106, 231, 202, 1, 7, 57, 62, 177, 220, 133, 160, 136, 150, 242, 53, 20, 186, 201, 19, 90, 9, 216, 62, 193, 83, 199, 46, 14, 248, 154, 58, 3, 168, 45, 5, 40, 209, 223, 233, 69, 232, 67, 167, 163, 56, 59, 160, 53, 125, 231, 88, 116, 243, 171, 250, 109, 195, 85, 109, 125, 29, 163, 168, 124, 240, 24, 154, 38, 51, 221, 131, 223, 34, 172, 147, 3, 222, 255, 25, 202, 143, 78, 171, 22, 185, 198, 161, 51, 41, 108, 112, 84, 23, 98, 76, 54, 251, 149, 141, 211, 163, 249, 138, 135, 107, 206, 114, 177, 202, 1, 181, 2, 200, 131, 83, 148, 69, 170, 248, 81, 208, 38, 194, 73, 128, 147, 121, 166, 212, 43, 71, 243, 66, 197, 248, 75, 128, 23, 175, 106, 130, 202, 207, 162, 252, 11, 28, 152, 130, 64, 238, 200, 95, 112, 141, 48, 51, 201, 198, 145, 66, 173, 213, 142, 28, 159, 241, 183, 190, 244, 33, 236, 73, 234, 210, 67, 128, 185, 62, 249, 26, 192, 136, 142, 49, 17, 23, 71, 95, 254, 136, 134, 169, 83, 138, 250, 134, 239, 52, 180, 27, 199, 12, 33, 45, 121, 247, 201, 26, 151, 111, 26, 185, 154, 195, 200, 32, 233, 88, 215, 70, 140, 137, 124, 98, 40, 137, 70, 94, 2, 129, 6, 69, 219, 11, 11, 233, 157, 3, 191, 98, 89, 118, 17, 185, 8, 218, 170, 105, 36, 64, 202, 56, 13, 248, 35, 219, 17, 234, 34, 182, 212, 127, 153, 2, 20, 139, 136, 15, 160, 250, 152, 212, 24, 100, 193, 202, 238, 233, 111, 141, 233, 246, 127, 82, 31, 77, 32, 129, 81, 34, 227, 203, 50, 1, 179, 148, 50, 159, 28, 148, 197, 236, 248, 181, 16, 232, 45, 6, 212, 121, 53, 231, 179, 97, 176, 66, 68, 178, 176, 64, 206, 122, 146, 46, 86, 100, 43, 125, 98, 238, 201, 108, 167, 87, 246, 20, 70, 167, 9, 98, 115, 253, 11, 122, 70, 219, 71, 20, 11, 184, 196, 181, 104, 159, 124, 33, 228, 107, 190, 30, 77, 220, 233, 77, 37, 8, 32, 61, 168, 19, 112, 200, 59, 212, 26, 93, 215, 190, 221, 58, 10, 159, 81, 98, 31, 5, 64, 55, 137, 23, 19, 47, 105, 61, 92, 73, 37, 192, 86, 225, 7, 69, 208, 234, 164, 138, 196, 241, 187, 83, 240, 59, 239, 135, 10, 9, 157, 63, 26, 207, 125, 54, 146, 102, 164, 92, 105, 98, 234, 147, 100, 146, 131, 164, 153, 222, 32, 242, 137, 137, 6, 93, 194, 25, 4, 85, 69, 116, 155, 46, 107, 181, 14, 170, 101, 166, 210, 11, 124, 190, 214, 186, 48, 124, 38, 153, 128, 95, 244, 227, 65, 191, 230, 171, 15, 192, 252, 21, 253, 26, 222, 25, 201, 58, 59, 2, 65, 191, 108, 219, 99, 75, 201, 251, 137, 57, 123, 47, 114, 85, 163, 249, 196, 216, 235, 49, 27, 141, 95, 18, 62, 102, 174, 81, 173, 56, 102, 34, 47, 156, 77, 3, 232, 149, 155, 227, 226, 254, 41, 105, 252, 134, 212, 44, 64, 9, 34, 166, 234, 46, 3, 50, 132, 105, 178, 110, 38, 86, 139, 8, 239, 218, 122, 32, 241, 79, 43, 149, 192, 90, 108, 28, 35, 47, 26, 227, 169, 92, 150, 131, 155, 226, 250, 239, 73, 67, 151, 84, 92, 173, 115, 7, 36, 103, 184, 10, 160, 237, 247, 189, 188, 145, 114, 181, 151, 28, 71, 251, 238, 90, 0, 26, 208, 123, 104, 136, 144, 214, 242, 137, 178, 119, 23, 84, 98, 7, 239, 17, 195, 130, 185, 135, 27, 23, 111, 205, 19, 52, 140, 121, 134, 18, 50, 32, 141, 79, 134, 177, 59, 5, 190, 232, 112, 128, 96, 165, 99, 88, 167, 240, 186, 170, 216, 176, 130, 24, 214, 56, 223, 20, 188, 0, 30, 31, 66, 71, 110, 3, 233, 80, 220, 147, 135, 90, 24, 160, 137, 158, 58, 134, 240, 221, 75, 243, 151, 214, 28, 4, 150, 8, 15, 202, 178, 240, 122, 231, 219, 197, 46, 240, 70, 92, 232, 184, 178, 56, 64, 249, 10, 207, 230, 172, 181, 0, 23, 112, 50, 205, 183, 16, 58, 140, 50, 242, 197, 108, 158, 39, 225, 184, 211, 246, 21, 255, 56, 232, 67, 5, 130, 161, 104, 6, 176, 142, 184, 21, 42, 246, 172, 246, 236, 28, 255, 231, 35, 19, 126, 17, 176, 37, 121, 72, 202, 113, 71, 188, 184, 196, 105, 45, 64, 221, 191, 53, 81, 32, 160, 112, 0, 36, 243, 56, 127, 157, 117, 150, 212, 134, 150, 112, 210, 162, 214, 122, 87, 222, 74, 153, 116, 238, 170, 81, 103, 63, 230, 46, 69, 31, 223, 12, 32, 81, 157, 2, 65, 40, 142, 77, 92, 190, 214, 70, 94, 248, 87, 30, 148, 92, 243, 200, 146, 220, 185, 135, 174, 232, 81, 8, 126, 130, 15, 250, 76, 19, 112, 155, 218, 8, 166, 137, 248, 134, 156, 22, 173, 131, 44, 96, 115, 211, 148, 140, 93, 14, 189, 54, 32, 240, 150, 75, 99, 191, 74, 189, 29, 52, 209, 168, 229, 100, 80, 228, 100, 220, 176, 104, 115, 202, 29, 34, 136, 103, 39, 79, 14, 221, 51, 130, 152, 229, 68, 132, 22, 33, 21 }; -const uncompressed_size: usize = 162205; +const uncompressed_size: usize = 162204; pub const IndexEntry = struct { offset: usize, From d4c0432a5f437c1d0f2db54f3070734df4dc1bdd Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 25 Dec 2024 23:02:05 -0800 Subject: [PATCH 096/125] Refactor JS parser visitor step into individual functions to reduce stack space usage (#15993) --- src/bundler/bundle_v2.zig | 2 +- src/js_ast.zig | 12 +- src/js_parser.zig | 2829 +++++++++++++++++++------------------ src/js_printer.zig | 4 +- 4 files changed, 1483 insertions(+), 1364 deletions(-) diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index de8fa8ebe5..a9d2345bf1 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -6978,7 +6978,7 @@ pub const LinkerContext = struct { } const expr = Expr{ - .data = stmt.data.s_lazy_export, + .data = stmt.data.s_lazy_export.*, .loc = stmt.loc, }; const module_ref = this.graph.ast.items(.module_ref)[source_index]; diff --git a/src/js_ast.zig b/src/js_ast.zig index 02bdd61094..3216d457a1 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -3044,7 +3044,7 @@ pub const Stmt = struct { return Stmt.allocate(allocator, S.SExpr, S.SExpr{ .value = expr }, expr.loc); } - pub const Tag = enum(u6) { + pub const Tag = enum { s_block, s_break, s_class, @@ -3126,7 +3126,13 @@ pub const Stmt = struct { s_empty: S.Empty, // special case, its a zero value type s_debugger: S.Debugger, - s_lazy_export: Expr.Data, + s_lazy_export: *Expr.Data, + + comptime { + if (@sizeOf(Stmt) > 24) { + @compileLog("Expected Stmt to be <= 24 bytes, but it is", @sizeOf(Stmt), " bytes"); + } + } pub const Store = struct { const StoreType = NewStore(&.{ @@ -4564,7 +4570,7 @@ pub const Expr = struct { }; } - pub const Tag = enum(u6) { + pub const Tag = enum { e_array, e_unary, e_binary, diff --git a/src/js_parser.zig b/src/js_parser.zig index cc8fec29c6..db61971b20 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -1601,40 +1601,51 @@ pub const SideEffects = enum(u1) { pub fn simplifyBoolean(p: anytype, expr: Expr) Expr { if (!p.options.features.dead_code_elimination) return expr; - switch (expr.data) { - .e_unary => |e| { - if (e.op == .un_not) { - // "!!a" => "a" - if (e.value.data == .e_unary and e.value.data.e_unary.op == .un_not) { - return simplifyBoolean(p, e.value.data.e_unary.value); + + var result: Expr = expr; + _simplifyBoolean(p, &result); + return result; + } + + fn _simplifyBoolean(p: anytype, expr: *Expr) void { + while (true) { + switch (expr.data) { + .e_unary => |e| { + if (e.op == .un_not) { + // "!!a" => "a" + if (e.value.data == .e_unary and e.value.data.e_unary.op == .un_not) { + expr.* = e.value.data.e_unary.value; + continue; + } + + _simplifyBoolean(p, &e.value); } - - e.value = simplifyBoolean(p, e.value); - } - }, - .e_binary => |e| { - switch (e.op) { - .bin_logical_and => { - const effects = SideEffects.toBoolean(p, e.right.data); - if (effects.ok and effects.value and effects.side_effects == .no_side_effects) { - // "if (anything && truthyNoSideEffects)" => "if (anything)" - return e.left; - } - }, - .bin_logical_or => { - const effects = SideEffects.toBoolean(p, e.right.data); - if (effects.ok and !effects.value and effects.side_effects == .no_side_effects) { - // "if (anything || falsyNoSideEffects)" => "if (anything)" - return e.left; - } - }, - else => {}, - } - }, - else => {}, + }, + .e_binary => |e| { + switch (e.op) { + .bin_logical_and => { + const effects = SideEffects.toBoolean(p, e.right.data); + if (effects.ok and effects.value and effects.side_effects == .no_side_effects) { + // "if (anything && truthyNoSideEffects)" => "if (anything)" + expr.* = e.left; + continue; + } + }, + .bin_logical_or => { + const effects = SideEffects.toBoolean(p, e.right.data); + if (effects.ok and !effects.value and effects.side_effects == .no_side_effects) { + // "if (anything || falsyNoSideEffects)" => "if (anything)" + expr.* = e.left; + continue; + } + }, + else => {}, + } + }, + else => {}, + } + break; } - - return expr; } pub const toNumber = Expr.Data.toNumber; @@ -2263,10 +2274,18 @@ pub const SideEffects = enum(u1) { } pub fn toBoolean(p: anytype, exp: Expr.Data) Result { + // Only do this check once. if (!p.options.features.dead_code_elimination) { // value should not be read if ok is false, all existing calls to this function already adhere to this return Result{ .ok = false, .value = undefined, .side_effects = .could_have_side_effects }; } + + return toBooleanWithoutDCECheck(exp); + } + + // Avoid passing through *P + // This is a very recursive function. + fn toBooleanWithoutDCECheck(exp: Expr.Data) Result { switch (exp) { .e_null, .e_undefined => { return Result{ .ok = true, .value = false, .side_effects = .no_side_effects }; @@ -2300,10 +2319,9 @@ pub const SideEffects = enum(u1) { return Result{ .ok = true, .value = true, .side_effects = .could_have_side_effects }; }, .un_not => { - var result = toBoolean(p, e_.value.data); + const result = toBooleanWithoutDCECheck(e_.value.data); if (result.ok) { - result.value = !result.value; - return result; + return .{ .ok = true, .value = !result.value, .side_effects = result.side_effects }; } }, else => {}, @@ -2313,21 +2331,21 @@ pub const SideEffects = enum(u1) { switch (e_.op) { .bin_logical_or => { // "anything || truthy" is truthy - const result = toBoolean(p, e_.right.data); + const result = toBooleanWithoutDCECheck(e_.right.data); if (result.value and result.ok) { return Result{ .ok = true, .value = true, .side_effects = .could_have_side_effects }; } }, .bin_logical_and => { // "anything && falsy" is falsy - const result = toBoolean(p, e_.right.data); + const result = toBooleanWithoutDCECheck(e_.right.data); if (!result.value and result.ok) { return Result{ .ok = true, .value = false, .side_effects = .could_have_side_effects }; } }, .bin_comma => { // "anything, truthy/falsy" is truthy/falsy - var result = toBoolean(p, e_.right.data); + var result = toBooleanWithoutDCECheck(e_.right.data); if (result.ok) { result.side_effects = .could_have_side_effects; return result; @@ -2365,7 +2383,7 @@ pub const SideEffects = enum(u1) { } }, .e_inlined_enum => |inlined| { - return toBoolean(p, inlined.value.data); + return toBooleanWithoutDCECheck(inlined.value.data); }, else => {}, } @@ -3057,7 +3075,11 @@ pub const Parser = struct { var stmts = try p.allocator.alloc(js_ast.Stmt, 1); stmts[0] = Stmt{ .data = .{ - .s_lazy_export = expr.data, + .s_lazy_export = brk: { + const data = try p.allocator.create(Expr.Data); + data.* = expr.data; + break :brk data; + }, }, .loc = expr.loc, }; @@ -10017,28 +10039,60 @@ fn NewParser_( return p.s(S.Local{ .kind = .k_const, .decls = Decl.List.fromList(decls), .is_export = opts.is_export }, loc); }, .t_if => { - try p.lexer.next(); - try p.lexer.expect(.t_open_paren); - const test_ = try p.parseExpr(.lowest); - try p.lexer.expect(.t_close_paren); - var stmtOpts = ParseStatementOptions{ - .lexical_decl = .allow_fn_inside_if, - }; - const yes = try p.parseStmt(&stmtOpts); - var no: ?Stmt = null; - if (p.lexer.token == .t_else) { + var current_loc = loc; + var root_if: ?Stmt = null; + var current_if: ?*S.If = null; + + while (true) { try p.lexer.next(); - stmtOpts = ParseStatementOptions{ + try p.lexer.expect(.t_open_paren); + const test_ = try p.parseExpr(.lowest); + try p.lexer.expect(.t_close_paren); + var stmtOpts = ParseStatementOptions{ .lexical_decl = .allow_fn_inside_if, }; - no = try p.parseStmt(&stmtOpts); + const yes = try p.parseStmt(&stmtOpts); + + // Create the if node + const if_stmt = p.s(S.If{ + .test_ = test_, + .yes = yes, + .no = null, + }, current_loc); + + // First if statement becomes root + if (root_if == null) { + root_if = if_stmt; + } + + // Link to previous if statement's else branch + if (current_if) |prev_if| { + prev_if.no = if_stmt; + } + + // Set current if for next iteration + current_if = if_stmt.data.s_if; + + if (p.lexer.token != .t_else) { + return root_if.?; + } + + try p.lexer.next(); + + // Handle final else + if (p.lexer.token != .t_if) { + stmtOpts = ParseStatementOptions{ + .lexical_decl = .allow_fn_inside_if, + }; + current_if.?.no = try p.parseStmt(&stmtOpts); + return root_if.?; + } + + // Continue with else if + current_loc = p.lexer.loc(); } - return p.s(S.If{ - .test_ = test_, - .yes = yes, - .no = no, - }, loc); + unreachable; }, .t_do => { try p.lexer.next(); @@ -10158,7 +10212,6 @@ fn NewParser_( var binding: ?js_ast.Binding = null; // The catch binding is optional, and can be omitted - // jarred: TIL! if (p.lexer.token != .t_open_brace) { try p.lexer.expect(.t_open_paren); var value = try p.parseBinding(.{}); @@ -15894,15 +15947,19 @@ fn NewParser_( fn bindingCanBeRemovedIfUnused(p: *P, binding: Binding) bool { if (!p.options.features.dead_code_elimination) return false; + return bindingCanBeRemovedIfUnusedWithoutDCECheck(p, binding); + } + + fn bindingCanBeRemovedIfUnusedWithoutDCECheck(p: *P, binding: Binding) bool { switch (binding.data) { .b_array => |bi| { for (bi.items) |*item| { - if (!p.bindingCanBeRemovedIfUnused(item.binding)) { + if (!p.bindingCanBeRemovedIfUnusedWithoutDCECheck(item.binding)) { return false; } if (item.default_value) |*default| { - if (!p.exprCanBeRemovedIfUnused(default)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(default)) { return false; } } @@ -15910,16 +15967,16 @@ fn NewParser_( }, .b_object => |bi| { for (bi.properties) |*property| { - if (!property.flags.contains(.is_spread) and !p.exprCanBeRemovedIfUnused(&property.key)) { + if (!property.flags.contains(.is_spread) and !p.exprCanBeRemovedIfUnusedWithoutDCECheck(&property.key)) { return false; } - if (!p.bindingCanBeRemovedIfUnused(property.value)) { + if (!p.bindingCanBeRemovedIfUnusedWithoutDCECheck(property.value)) { return false; } if (property.default_value) |*default| { - if (!p.exprCanBeRemovedIfUnused(default)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(default)) { return false; } } @@ -15933,6 +15990,10 @@ fn NewParser_( fn stmtsCanBeRemovedIfUnused(p: *P, stmts: []Stmt) bool { if (!p.options.features.dead_code_elimination) return false; + return stmtsCanBeRemovedifUnusedWithoutDCECheck(p, stmts); + } + + fn stmtsCanBeRemovedifUnusedWithoutDCECheck(p: *P, stmts: []Stmt) bool { for (stmts) |stmt| { switch (stmt.data) { // These never have side effects @@ -15957,7 +16018,7 @@ fn NewParser_( continue; } - if (!p.exprCanBeRemovedIfUnused(&st.value)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(&st.value)) { return false; } }, @@ -15967,12 +16028,12 @@ fn NewParser_( if (st.kind == .k_await_using) return false; for (st.decls.slice()) |*decl| { - if (!p.bindingCanBeRemovedIfUnused(decl.binding)) { + if (!p.bindingCanBeRemovedIfUnusedWithoutDCECheck(decl.binding)) { return false; } if (decl.value) |*decl_value| { - if (!p.exprCanBeRemovedIfUnused(decl_value)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(decl_value)) { return false; } else if (st.kind == .k_using) { // "using" declarations are only side-effect free if they are initialized to null or undefined @@ -15985,7 +16046,7 @@ fn NewParser_( }, .s_try => |try_| { - if (!p.stmtsCanBeRemovedIfUnused(try_.body) or (try_.finally != null and !p.stmtsCanBeRemovedIfUnused(try_.finally.?.stmts))) { + if (!p.stmtsCanBeRemovedifUnusedWithoutDCECheck(try_.body) or (try_.finally != null and !p.stmtsCanBeRemovedifUnusedWithoutDCECheck(try_.finally.?.stmts))) { return false; } }, @@ -15998,7 +16059,7 @@ fn NewParser_( .stmt => |s2| { switch (s2.data) { .s_expr => |s_expr| { - if (!p.exprCanBeRemovedIfUnused(&s_expr.value)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(&s_expr.value)) { return false; } }, @@ -16017,7 +16078,7 @@ fn NewParser_( } }, .expr => |*exp| { - if (!p.exprCanBeRemovedIfUnused(exp)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(exp)) { return false; } }, @@ -16067,7 +16128,7 @@ fn NewParser_( } // public for JSNode.JSXWriter usage - pub fn visitExpr(p: *P, expr: Expr) Expr { + pub inline fn visitExpr(p: *P, expr: Expr) Expr { if (only_scan_imports_and_do_not_visit) { @compileError("only_scan_imports_and_do_not_visit must not run this."); } @@ -17828,34 +17889,34 @@ fn NewParser_( return true; } + // This one is never called in places that haven't already checked if DCE is enabled. pub fn classCanBeRemovedIfUnused(p: *P, class: *G.Class) bool { - if (!p.options.features.dead_code_elimination) return false; if (class.extends) |*extends| { - if (!p.exprCanBeRemovedIfUnused(extends)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(extends)) { return false; } } for (class.properties) |*property| { if (property.kind == .class_static_block) { - if (!p.stmtsCanBeRemovedIfUnused(property.class_static_block.?.stmts.slice())) { + if (!p.stmtsCanBeRemovedifUnusedWithoutDCECheck(property.class_static_block.?.stmts.slice())) { return false; } continue; } - if (!p.exprCanBeRemovedIfUnused(&(property.key orelse unreachable))) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(&(property.key orelse unreachable))) { return false; } if (property.value) |*val| { - if (!p.exprCanBeRemovedIfUnused(val)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(val)) { return false; } } if (property.initializer) |*val| { - if (!p.exprCanBeRemovedIfUnused(val)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(val)) { return false; } } @@ -17869,6 +17930,11 @@ fn NewParser_( // This is to improve the reliability of fast refresh between page loads. pub fn exprCanBeRemovedIfUnused(p: *P, expr: *const Expr) bool { if (!p.options.features.dead_code_elimination) return false; + + return exprCanBeRemovedIfUnusedWithoutDCECheck(p, expr); + } + + fn exprCanBeRemovedIfUnusedWithoutDCECheck(p: *P, expr: *const Expr) bool { switch (expr.data) { .e_null, .e_undefined, @@ -17886,7 +17952,7 @@ fn NewParser_( return true; }, - .e_inlined_enum => |e| return p.exprCanBeRemovedIfUnused(&e.value), + .e_inlined_enum => |e| return p.exprCanBeRemovedIfUnusedWithoutDCECheck(&e.value), .e_dot => |ex| { return ex.can_be_removed_if_unused; @@ -17945,24 +18011,24 @@ fn NewParser_( return true; }, .e_if => |ex| { - return p.exprCanBeRemovedIfUnused(&ex.test_) and + return p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.test_) and (p.isSideEffectFreeUnboundIdentifierRef( ex.yes, ex.test_, true, ) or - p.exprCanBeRemovedIfUnused(&ex.yes)) and + p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.yes)) and (p.isSideEffectFreeUnboundIdentifierRef( ex.no, ex.test_, false, - ) or p.exprCanBeRemovedIfUnused( + ) or p.exprCanBeRemovedIfUnusedWithoutDCECheck( &ex.no, )); }, .e_array => |ex| { for (ex.items.slice()) |*item| { - if (!p.exprCanBeRemovedIfUnused(item)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(item)) { return false; } } @@ -17978,7 +18044,7 @@ fn NewParser_( } if (property.value) |*val| { - if (!p.exprCanBeRemovedIfUnused(val)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(val)) { return false; } } @@ -17990,7 +18056,7 @@ fn NewParser_( // can be removed. The annotation causes us to ignore the target. if (ex.can_be_unwrapped_if_unused) { for (ex.args.slice()) |*arg| { - if (!p.exprCanBeRemovedIfUnused(arg)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(arg)) { return false; } } @@ -18003,7 +18069,7 @@ fn NewParser_( // can be removed. The annotation causes us to ignore the target. if (ex.can_be_unwrapped_if_unused) { for (ex.args.slice()) |*arg| { - if (!p.exprCanBeRemovedIfUnused(arg)) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(arg)) { return false; } } @@ -18016,7 +18082,7 @@ fn NewParser_( // These operators must not have any type conversions that can execute code // such as "toString" or "valueOf". They must also never throw any exceptions. .un_void, .un_not => { - return p.exprCanBeRemovedIfUnused(&ex.value); + return p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.value); }, // The "typeof" operator doesn't do any type conversions so it can be removed @@ -18034,7 +18100,7 @@ fn NewParser_( return true; } - return p.exprCanBeRemovedIfUnused(&ex.value); + return p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.value); }, else => {}, @@ -18048,15 +18114,15 @@ fn NewParser_( .bin_strict_ne, .bin_comma, .bin_nullish_coalescing, - => return p.exprCanBeRemovedIfUnused(&ex.left) and p.exprCanBeRemovedIfUnused(&ex.right), + => return p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.left) and p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.right), // Special-case "||" to make sure "typeof x === 'undefined' || x" can be removed - .bin_logical_or => return p.exprCanBeRemovedIfUnused(&ex.left) and - (p.isSideEffectFreeUnboundIdentifierRef(ex.right, ex.left, false) or p.exprCanBeRemovedIfUnused(&ex.right)), + .bin_logical_or => return p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.left) and + (p.isSideEffectFreeUnboundIdentifierRef(ex.right, ex.left, false) or p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.right)), // Special-case "&&" to make sure "typeof x !== 'undefined' && x" can be removed - .bin_logical_and => return p.exprCanBeRemovedIfUnused(&ex.left) and - (p.isSideEffectFreeUnboundIdentifierRef(ex.right, ex.left, true) or p.exprCanBeRemovedIfUnused(&ex.right)), + .bin_logical_and => return p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.left) and + (p.isSideEffectFreeUnboundIdentifierRef(ex.right, ex.left, true) or p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.right)), // For "==" and "!=", pretend the operator was actually "===" or "!==". If // we know that we can convert it to "==" or "!=", then we can consider the @@ -18068,14 +18134,14 @@ fn NewParser_( ex.left.data, ex.right.data, ) and - p.exprCanBeRemovedIfUnused(&ex.left) and p.exprCanBeRemovedIfUnused(&ex.right), + p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.left) and p.exprCanBeRemovedIfUnusedWithoutDCECheck(&ex.right), else => {}, } }, .e_template => |templ| { if (templ.tag == null) { for (templ.parts) |part| { - if (!p.exprCanBeRemovedIfUnused(&part.value) or part.value.knownPrimitive() == .unknown) { + if (!p.exprCanBeRemovedIfUnusedWithoutDCECheck(&part.value) or part.value.knownPrimitive() == .unknown) { return false; } } @@ -18089,7 +18155,7 @@ fn NewParser_( return false; } - // // This is based on exprCanBeRemovedIfUnused. + // // This is based on exprCanBeRemoved // // The main difference: identifiers, functions, arrow functions cause it to return false // pub fn exprCanBeHoistedForJSX(p: *P, expr: *const Expr) bool { // if (comptime jsx_transform_type != .react) { @@ -19001,809 +19067,985 @@ fn NewParser_( const was_after_after_const_local_prefix = p.current_scope.is_after_const_local_prefix; p.current_scope.is_after_const_local_prefix = true; - switch (stmt.data) { - // These don't contain anything to traverse + switch (@as(Stmt.Tag, stmt.data)) { + .s_directive, .s_comment, .s_empty => { + p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; + try stmts.append(stmt.*); + }, + .s_type_script => { + p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; + return; + }, .s_debugger => { p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; if (p.define.drop_debugger) { return; } + try stmts.append(stmt.*); }, - .s_empty, .s_comment => { - p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; - }, - .s_type_script => { - p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; - // Erase TypeScript constructs from the output completely + + inline .s_enum, .s_local => |tag| return @field(visitors, @tagName(tag))(p, stmts, stmt, @field(stmt.data, @tagName(tag)), was_after_after_const_local_prefix), + inline else => |tag| return @field(visitors, @tagName(tag))(p, stmts, stmt, @field(stmt.data, @tagName(tag))), + + // Only used by the bundler for lazy export ASTs. + .s_lazy_export => unreachable, + } + } + + const visitors = struct { + pub fn s_import(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Import) !void { + try p.recordDeclaredSymbol(data.namespace_ref); + + if (data.default_name) |default_name| { + try p.recordDeclaredSymbol(default_name.ref.?); + } + + if (data.items.len > 0) { + for (data.items) |*item| { + try p.recordDeclaredSymbol(item.name.ref.?); + } + } + + try stmts.append(stmt.*); + } + pub fn s_export_clause(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.ExportClause) !void { + // "export {foo}" + var end: usize = 0; + var any_replaced = false; + if (p.options.features.replace_exports.count() > 0) { + for (data.items) |*item| { + const name = p.loadNameFromRef(item.name.ref.?); + + const symbol = try p.findSymbol(item.alias_loc, name); + const ref = symbol.ref; + + if (p.options.features.replace_exports.getPtr(name)) |entry| { + if (entry.* != .replace) p.ignoreUsage(symbol.ref); + _ = p.injectReplacementExport(stmts, symbol.ref, stmt.loc, entry); + any_replaced = true; + continue; + } + + if (p.symbols.items[ref.innerIndex()].kind == .unbound) { + // Silently strip exports of non-local symbols in TypeScript, since + // those likely correspond to type-only exports. But report exports of + // non-local symbols as errors in JavaScript. + if (!is_typescript_enabled) { + const r = js_lexer.rangeOfIdentifier(p.source, item.name.loc); + try p.log.addRangeErrorFmt(p.source, r, p.allocator, "\"{s}\" is not declared in this file", .{name}); + } + continue; + } + + item.name.ref = ref; + data.items[end] = item.*; + end += 1; + } + } else { + for (data.items) |*item| { + const name = p.loadNameFromRef(item.name.ref.?); + const symbol = try p.findSymbol(item.alias_loc, name); + const ref = symbol.ref; + + if (p.symbols.items[ref.innerIndex()].kind == .unbound) { + // Silently strip exports of non-local symbols in TypeScript, since + // those likely correspond to type-only exports. But report exports of + // non-local symbols as errors in JavaScript. + if (!is_typescript_enabled) { + const r = js_lexer.rangeOfIdentifier(p.source, item.name.loc); + try p.log.addRangeErrorFmt(p.source, r, p.allocator, "\"{s}\" is not declared in this file", .{name}); + continue; + } + continue; + } + + item.name.ref = ref; + data.items[end] = item.*; + end += 1; + } + } + + const remove_for_tree_shaking = any_replaced and end == 0 and data.items.len > 0 and p.options.tree_shaking; + data.items.len = end; + + if (remove_for_tree_shaking) { return; - }, - .s_directive => { - p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; - }, - .s_import => |data| { - try p.recordDeclaredSymbol(data.namespace_ref); + } - if (data.default_name) |default_name| { - try p.recordDeclaredSymbol(default_name.ref.?); - } + try stmts.append(stmt.*); + } + pub fn s_export_from(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.ExportFrom) !void { - if (data.items.len > 0) { - for (data.items) |*item| { - try p.recordDeclaredSymbol(item.name.ref.?); - } - } - }, - .s_export_clause => |data| { - // "export {foo}" - var end: usize = 0; - var any_replaced = false; - if (p.options.features.replace_exports.count() > 0) { - for (data.items) |*item| { - const name = p.loadNameFromRef(item.name.ref.?); + // "export {foo} from 'path'" + const name = p.loadNameFromRef(data.namespace_ref); - const symbol = try p.findSymbol(item.alias_loc, name); - const ref = symbol.ref; + data.namespace_ref = try p.newSymbol(.other, name); + try p.current_scope.generated.push(p.allocator, data.namespace_ref); + try p.recordDeclaredSymbol(data.namespace_ref); + + if (p.options.features.replace_exports.count() > 0) { + var j: usize = 0; + // This is a re-export and the symbols created here are used to reference + for (data.items) |item| { + const old_ref = item.name.ref.?; + + if (p.options.features.replace_exports.count() > 0) { + if (p.options.features.replace_exports.getPtr(item.alias)) |entry| { + _ = p.injectReplacementExport(stmts, old_ref, logger.Loc.Empty, entry); - if (p.options.features.replace_exports.getPtr(name)) |entry| { - if (entry.* != .replace) p.ignoreUsage(symbol.ref); - _ = p.injectReplacementExport(stmts, symbol.ref, stmt.loc, entry); - any_replaced = true; continue; } - - if (p.symbols.items[ref.innerIndex()].kind == .unbound) { - // Silently strip exports of non-local symbols in TypeScript, since - // those likely correspond to type-only exports. But report exports of - // non-local symbols as errors in JavaScript. - if (!is_typescript_enabled) { - const r = js_lexer.rangeOfIdentifier(p.source, item.name.loc); - try p.log.addRangeErrorFmt(p.source, r, p.allocator, "\"{s}\" is not declared in this file", .{name}); - } - continue; - } - - item.name.ref = ref; - data.items[end] = item.*; - end += 1; } - } else { - for (data.items) |*item| { - const name = p.loadNameFromRef(item.name.ref.?); - const symbol = try p.findSymbol(item.alias_loc, name); - const ref = symbol.ref; - if (p.symbols.items[ref.innerIndex()].kind == .unbound) { - // Silently strip exports of non-local symbols in TypeScript, since - // those likely correspond to type-only exports. But report exports of - // non-local symbols as errors in JavaScript. - if (!is_typescript_enabled) { - const r = js_lexer.rangeOfIdentifier(p.source, item.name.loc); - try p.log.addRangeErrorFmt(p.source, r, p.allocator, "\"{s}\" is not declared in this file", .{name}); - continue; - } - continue; - } + const _name = p.loadNameFromRef(old_ref); - item.name.ref = ref; - data.items[end] = item.*; - end += 1; - } + const ref = try p.newSymbol(.import, _name); + try p.current_scope.generated.push(p.allocator, ref); + try p.recordDeclaredSymbol(ref); + data.items[j] = item; + data.items[j].name.ref = ref; + j += 1; } - const remove_for_tree_shaking = any_replaced and end == 0 and data.items.len > 0 and p.options.tree_shaking; - data.items.len = end; + data.items.len = j; - if (remove_for_tree_shaking) { + if (j == 0 and data.items.len > 0) { return; } - }, - .s_export_from => |data| { - // "export {foo} from 'path'" - const name = p.loadNameFromRef(data.namespace_ref); + } else { + // This is a re-export and the symbols created here are used to reference + for (data.items) |*item| { + const _name = p.loadNameFromRef(item.name.ref.?); + const ref = try p.newSymbol(.import, _name); + try p.current_scope.generated.push(p.allocator, ref); + try p.recordDeclaredSymbol(ref); + item.name.ref = ref; + } + } - data.namespace_ref = try p.newSymbol(.other, name); - try p.current_scope.generated.push(p.allocator, data.namespace_ref); - try p.recordDeclaredSymbol(data.namespace_ref); + try stmts.append(stmt.*); + } + pub fn s_export_star(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.ExportStar) !void { + // "export * from 'path'" + const name = p.loadNameFromRef(data.namespace_ref); + data.namespace_ref = try p.newSymbol(.other, name); + try p.current_scope.generated.push(p.allocator, data.namespace_ref); + try p.recordDeclaredSymbol(data.namespace_ref); + + // "export * as ns from 'path'" + if (data.alias) |alias| { if (p.options.features.replace_exports.count() > 0) { - var j: usize = 0; - // This is a re-export and the symbols created here are used to reference - for (data.items) |item| { - const old_ref = item.name.ref.?; - - if (p.options.features.replace_exports.count() > 0) { - if (p.options.features.replace_exports.getPtr(item.alias)) |entry| { - _ = p.injectReplacementExport(stmts, old_ref, logger.Loc.Empty, entry); - - continue; - } - } - - const _name = p.loadNameFromRef(old_ref); - - const ref = try p.newSymbol(.import, _name); - try p.current_scope.generated.push(p.allocator, ref); - try p.recordDeclaredSymbol(ref); - data.items[j] = item; - data.items[j].name.ref = ref; - j += 1; - } - - data.items.len = j; - - if (j == 0 and data.items.len > 0) { + if (p.options.features.replace_exports.getPtr(alias.original_name)) |entry| { + _ = p.injectReplacementExport(stmts, p.declareSymbol(.other, logger.Loc.Empty, alias.original_name) catch unreachable, logger.Loc.Empty, entry); return; } - } else { - // This is a re-export and the symbols created here are used to reference - for (data.items) |*item| { - const _name = p.loadNameFromRef(item.name.ref.?); - const ref = try p.newSymbol(.import, _name); - try p.current_scope.generated.push(p.allocator, ref); - try p.recordDeclaredSymbol(ref); - item.name.ref = ref; + } + } + + try stmts.append(stmt.*); + } + pub fn s_export_default(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.ExportDefault) !void { + defer { + if (data.default_name.ref) |ref| { + p.recordDeclaredSymbol(ref) catch unreachable; + } + } + + var mark_for_replace: bool = false; + + const orig_dead = p.is_control_flow_dead; + if (p.options.features.replace_exports.count() > 0) { + if (p.options.features.replace_exports.getPtr("default")) |entry| { + p.is_control_flow_dead = p.options.features.dead_code_elimination and (entry.* != .replace); + mark_for_replace = true; + } + } + + defer { + p.is_control_flow_dead = orig_dead; + } + + switch (data.value) { + .expr => |expr| { + const was_anonymous_named_expr = expr.isAnonymousNamed(); + + data.value.expr = p.visitExpr(expr); + + if (p.is_control_flow_dead) { + return; } - } - }, - .s_export_star => |data| { - // "export * from 'path'" - const name = p.loadNameFromRef(data.namespace_ref); - data.namespace_ref = try p.newSymbol(.other, name); - try p.current_scope.generated.push(p.allocator, data.namespace_ref); - try p.recordDeclaredSymbol(data.namespace_ref); - // "export * as ns from 'path'" - if (data.alias) |alias| { - if (p.options.features.replace_exports.count() > 0) { - if (p.options.features.replace_exports.getPtr(alias.original_name)) |entry| { - _ = p.injectReplacementExport(stmts, p.declareSymbol(.other, logger.Loc.Empty, alias.original_name) catch unreachable, logger.Loc.Empty, entry); - return; - } - } - } - }, - .s_export_default => |data| { - defer { - if (data.default_name.ref) |ref| { - p.recordDeclaredSymbol(ref) catch unreachable; - } - } + // Optionally preserve the name - var mark_for_replace: bool = false; + data.value.expr = p.maybeKeepExprSymbolName(data.value.expr, js_ast.ClauseItem.default_alias, was_anonymous_named_expr); - const orig_dead = p.is_control_flow_dead; - if (p.options.features.replace_exports.count() > 0) { - if (p.options.features.replace_exports.getPtr("default")) |entry| { - p.is_control_flow_dead = p.options.features.dead_code_elimination and (entry.* != .replace); - mark_for_replace = true; - } - } - - defer { - p.is_control_flow_dead = orig_dead; - } - - switch (data.value) { - .expr => |expr| { - const was_anonymous_named_expr = expr.isAnonymousNamed(); - - data.value.expr = p.visitExpr(expr); - - if (p.is_control_flow_dead) { - return; - } - - // Optionally preserve the name - - data.value.expr = p.maybeKeepExprSymbolName(data.value.expr, js_ast.ClauseItem.default_alias, was_anonymous_named_expr); - - // Discard type-only export default statements - if (is_typescript_enabled) { - switch (data.value.expr.data) { - .e_identifier => |ident| { - if (!ident.ref.isSourceContentsSlice()) { - const symbol = p.symbols.items[ident.ref.innerIndex()]; - if (symbol.kind == .unbound) { - if (p.local_type_names.get(symbol.original_name)) |local_type| { - if (local_type) { - // the name points to a type - // don't try to declare this symbol - data.default_name.ref = null; - return; - } + // Discard type-only export default statements + if (is_typescript_enabled) { + switch (data.value.expr.data) { + .e_identifier => |ident| { + if (!ident.ref.isSourceContentsSlice()) { + const symbol = p.symbols.items[ident.ref.innerIndex()]; + if (symbol.kind == .unbound) { + if (p.local_type_names.get(symbol.original_name)) |local_type| { + if (local_type) { + // the name points to a type + // don't try to declare this symbol + data.default_name.ref = null; + return; } } } - }, - else => {}, - } - } - - if (data.default_name.ref.?.isSourceContentsSlice()) { - data.default_name = createDefaultName(p, data.value.expr.loc) catch unreachable; - } - - if (p.options.features.server_components.wrapsExports()) { - data.value.expr = p.wrapValueForServerComponentReference(data.value.expr, "default"); - } - - // If there are lowered "using" declarations, change this into a "var" - if (p.current_scope.parent == null and p.will_wrap_module_in_try_catch_for_using) { - try stmts.ensureUnusedCapacity(2); - - const decls = p.allocator.alloc(G.Decl, 1) catch bun.outOfMemory(); - decls[0] = .{ - .binding = p.b(B.Identifier{ .ref = data.default_name.ref.? }, data.default_name.loc), - .value = data.value.expr, - }; - stmts.appendAssumeCapacity(p.s(S.Local{ - .decls = G.Decl.List.init(decls), - }, stmt.loc)); - const items = p.allocator.alloc(js_ast.ClauseItem, 1) catch bun.outOfMemory(); - items[0] = js_ast.ClauseItem{ - .alias = "default", - .alias_loc = data.default_name.loc, - .name = data.default_name, - }; - stmts.appendAssumeCapacity(p.s(S.ExportClause{ - .items = items, - }, stmt.loc)); - } - - if (mark_for_replace) { - const entry = p.options.features.replace_exports.getPtr("default").?; - if (entry.* == .replace) { - data.value.expr = entry.replace; - } else { - _ = p.injectReplacementExport(stmts, Ref.None, logger.Loc.Empty, entry); - return; - } - } - }, - - .stmt => |s2| { - switch (s2.data) { - .s_function => |func| { - var name: string = ""; - if (func.func.name) |func_loc| { - name = p.loadNameFromRef(func_loc.ref.?); - } else { - func.func.name = data.default_name; - name = js_ast.ClauseItem.default_alias; } - - var react_hook_data: ?ReactRefresh.HookContext = null; - const prev = p.react_refresh.hook_ctx_storage; - defer p.react_refresh.hook_ctx_storage = prev; - p.react_refresh.hook_ctx_storage = &react_hook_data; - - func.func = p.visitFunc(func.func, func.func.open_parens_loc); - - if (react_hook_data) |*hook| { - stmts.append(p.getReactRefreshHookSignalDecl(hook.signature_cb)) catch bun.outOfMemory(); - - data.value = .{ - .expr = p.getReactRefreshHookSignalInit(hook, p.newExpr( - E.Function{ .func = func.func }, - stmt.loc, - )), - }; - } - - if (p.is_control_flow_dead) { - return; - } - - if (mark_for_replace) { - const entry = p.options.features.replace_exports.getPtr("default").?; - if (entry.* == .replace) { - data.value = .{ .expr = entry.replace }; - } else { - _ = p.injectReplacementExport(stmts, Ref.None, logger.Loc.Empty, entry); - return; - } - } - - if (data.default_name.ref.?.isSourceContentsSlice()) { - data.default_name = createDefaultName(p, stmt.loc) catch unreachable; - } - - if (p.options.features.server_components.wrapsExports()) { - data.value = .{ .expr = p.wrapValueForServerComponentReference(p.newExpr(E.Function{ .func = func.func }, stmt.loc), "default") }; - } - - stmts.append(stmt.*) catch unreachable; - - // if (func.func.name != null and func.func.name.?.ref != null) { - // stmts.append(p.keepStmtSymbolName(func.func.name.?.loc, func.func.name.?.ref.?, name)) catch unreachable; - // } - // prevent doubling export default function name - return; - }, - .s_class => |class| { - _ = p.visitClass(s2.loc, &class.class, data.default_name.ref.?); - - if (p.is_control_flow_dead) - return; - - if (mark_for_replace) { - const entry = p.options.features.replace_exports.getPtr("default").?; - if (entry.* == .replace) { - data.value = .{ .expr = entry.replace }; - } else { - _ = p.injectReplacementExport(stmts, Ref.None, logger.Loc.Empty, entry); - return; - } - } - - if (data.default_name.ref.?.isSourceContentsSlice()) { - data.default_name = createDefaultName(p, stmt.loc) catch unreachable; - } - - // We only inject a name into classes when there is a decorator - if (class.class.has_decorators) { - if (class.class.class_name == null or - class.class.class_name.?.ref == null) - { - class.class.class_name = data.default_name; - } - } - - // This is to handle TS decorators, mostly. - var class_stmts = p.lowerClass(.{ .stmt = s2 }); - bun.assert(class_stmts[0].data == .s_class); - - if (class_stmts.len > 1) { - data.value.stmt = class_stmts[0]; - stmts.append(stmt.*) catch {}; - stmts.appendSlice(class_stmts[1..]) catch {}; - } else { - data.value.stmt = class_stmts[0]; - stmts.append(stmt.*) catch {}; - } - - if (p.options.features.server_components.wrapsExports()) { - data.value = .{ .expr = p.wrapValueForServerComponentReference(p.newExpr(class.class, stmt.loc), "default") }; - } - - return; }, else => {}, } - }, - } - }, - .s_export_equals => |data| { - // "module.exports = value" - stmts.append( - Stmt.assign( - p.@"module.exports"(stmt.loc), - p.visitExpr(data.value), - ), - ) catch unreachable; - p.recordUsage(p.module_ref); - return; - }, - .s_break => |data| { - if (data.label) |*label| { - const name = p.loadNameFromRef(label.ref orelse p.panicLoc("Expected label to have a ref", .{}, label.loc)); - const res = p.findLabelSymbol(label.loc, name); - if (res.found) { - label.ref = res.ref; - } else { - data.label = null; } - } else if (!p.fn_or_arrow_data_visit.is_inside_loop and !p.fn_or_arrow_data_visit.is_inside_switch) { - const r = js_lexer.rangeOfIdentifier(p.source, stmt.loc); - p.log.addRangeError(p.source, r, "Cannot use \"break\" here") catch unreachable; - } - }, - .s_continue => |data| { - if (data.label) |*label| { - const name = p.loadNameFromRef(label.ref orelse p.panicLoc("Expected continue label to have a ref", .{}, label.loc)); - const res = p.findLabelSymbol(label.loc, name); - label.ref = res.ref; - if (res.found and !res.is_loop) { - const r = js_lexer.rangeOfIdentifier(p.source, stmt.loc); - p.log.addRangeErrorFmt(p.source, r, p.allocator, "Cannot \"continue\" to label {s}", .{name}) catch unreachable; + + if (data.default_name.ref.?.isSourceContentsSlice()) { + data.default_name = createDefaultName(p, data.value.expr.loc) catch unreachable; } - } else if (!p.fn_or_arrow_data_visit.is_inside_loop) { - const r = js_lexer.rangeOfIdentifier(p.source, stmt.loc); - p.log.addRangeError(p.source, r, "Cannot use \"continue\" here") catch unreachable; - } - }, - .s_label => |data| { - p.pushScopeForVisitPass(.label, stmt.loc) catch unreachable; - const name = p.loadNameFromRef(data.name.ref.?); - const ref = p.newSymbol(.label, name) catch unreachable; - data.name.ref = ref; - p.current_scope.label_ref = ref; - switch (data.stmt.data) { - .s_for, .s_for_in, .s_for_of, .s_while, .s_do_while => { - p.current_scope.label_stmt_is_loop = true; - }, - else => {}, - } - data.stmt = p.visitSingleStmt(data.stmt, StmtsKind.none); - p.popScope(); - }, - .s_local => |data| { - // TODO: Silently remove unsupported top-level "await" in dead code branches - // (this was from 'await using' syntax) + if (p.options.features.server_components.wrapsExports()) { + data.value.expr = p.wrapValueForServerComponentReference(data.value.expr, "default"); + } - // Local statements do not end the const local prefix - p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; + // If there are lowered "using" declarations, change this into a "var" + if (p.current_scope.parent == null and p.will_wrap_module_in_try_catch_for_using) { + try stmts.ensureUnusedCapacity(2); - const decls_len = if (!(data.is_export and p.options.features.replace_exports.entries.len > 0)) - p.visitDecls(data.decls.slice(), data.kind == .k_const, false) - else - p.visitDecls(data.decls.slice(), data.kind == .k_const, true); + const decls = p.allocator.alloc(G.Decl, 1) catch bun.outOfMemory(); + decls[0] = .{ + .binding = p.b(B.Identifier{ .ref = data.default_name.ref.? }, data.default_name.loc), + .value = data.value.expr, + }; + stmts.appendAssumeCapacity(p.s(S.Local{ + .decls = G.Decl.List.init(decls), + }, stmt.loc)); + const items = p.allocator.alloc(js_ast.ClauseItem, 1) catch bun.outOfMemory(); + items[0] = js_ast.ClauseItem{ + .alias = "default", + .alias_loc = data.default_name.loc, + .name = data.default_name, + }; + stmts.appendAssumeCapacity(p.s(S.ExportClause{ + .items = items, + }, stmt.loc)); + } - const is_now_dead = data.decls.len > 0 and decls_len == 0; - if (is_now_dead) { - return; - } - - data.decls.len = @as(u32, @truncate(decls_len)); - - // Handle being exported inside a namespace - if (data.is_export and p.enclosing_namespace_arg_ref != null) { - for (data.decls.slice()) |*d| { - if (d.value) |val| { - p.recordUsage((p.enclosing_namespace_arg_ref orelse unreachable)); - // TODO: is it necessary to lowerAssign? why does esbuild do it _most_ of the time? - stmts.append(p.s(S.SExpr{ - .value = Expr.assign(Binding.toExpr(&d.binding, p.to_expr_wrapper_namespace), val), - }, stmt.loc)) catch unreachable; + if (mark_for_replace) { + const entry = p.options.features.replace_exports.getPtr("default").?; + if (entry.* == .replace) { + data.value.expr = entry.replace; + } else { + _ = p.injectReplacementExport(stmts, Ref.None, logger.Loc.Empty, entry); + return; } } + }, - return; - } - - // Optimization: Avoid unnecessary "using" machinery by changing ones - // initialized to "null" or "undefined" into a normal variable. Note that - // "await using" still needs the "await", so we can't do it for those. - if (p.options.features.minify_syntax and data.kind == .k_using) { - data.kind = .k_let; - for (data.decls.slice()) |*d| { - if (d.value) |val| { - if (val.data != .e_null and val.data != .e_undefined) { - data.kind = .k_using; - break; + .stmt => |s2| { + switch (s2.data) { + .s_function => |func| { + var name: string = ""; + if (func.func.name) |func_loc| { + name = p.loadNameFromRef(func_loc.ref.?); + } else { + func.func.name = data.default_name; + name = js_ast.ClauseItem.default_alias; } - } - } - } - // We must relocate vars in order to safely handle removing if/else depending on NODE_ENV. - // Edgecase: - // `export var` is skipped because it's unnecessary. That *should* be a noop, but it loses the `is_export` flag if we're in HMR. - const kind = p.selectLocalKind(data.kind); - if (kind == .k_var and !data.is_export) { - const relocated = p.maybeRelocateVarsToTopLevel(data.decls.slice(), .normal); - if (relocated.ok) { - if (relocated.stmt) |new_stmt| { - stmts.append(new_stmt) catch unreachable; - } + var react_hook_data: ?ReactRefresh.HookContext = null; + const prev = p.react_refresh.hook_ctx_storage; + defer p.react_refresh.hook_ctx_storage = prev; + p.react_refresh.hook_ctx_storage = &react_hook_data; - return; - } - } + func.func = p.visitFunc(func.func, func.func.open_parens_loc); - data.kind = kind; - try stmts.append(stmt.*); + if (react_hook_data) |*hook| { + stmts.append(p.getReactRefreshHookSignalDecl(hook.signature_cb)) catch bun.outOfMemory(); - if (data.is_export and p.options.features.server_components.wrapsExports()) { - for (data.decls.slice()) |*decl| try_annotate: { - const val = decl.value orelse break :try_annotate; - switch (val.data) { - .e_arrow, .e_function => {}, - else => break :try_annotate, - } - const id = switch (decl.binding.data) { - .b_identifier => |id| id.ref, - else => break :try_annotate, - }; - const original_name = p.symbols.items[id.innerIndex()].original_name; - decl.value = p.wrapValueForServerComponentReference(val, original_name); - } - } - - if (p.options.features.react_fast_refresh and p.current_scope == p.module_scope) { - for (data.decls.slice()) |decl| try_register: { - const val = decl.value orelse break :try_register; - switch (val.data) { - .e_arrow, .e_function => {}, - else => break :try_register, - } - const id = switch (decl.binding.data) { - .b_identifier => |id| id.ref, - else => break :try_register, - }; - const original_name = p.symbols.items[id.innerIndex()].original_name; - try p.handleReactRefreshRegister(stmts, original_name, id); - } - } - - return; - }, - .s_expr => |data| { - const should_trim_primitive = p.options.features.dead_code_elimination and - (p.options.features.minify_syntax and data.value.isPrimitiveLiteral()); - p.stmt_expr_value = data.value.data; - defer p.stmt_expr_value = .{ .e_missing = .{} }; - - const is_top_level = p.current_scope == p.module_scope; - if (p.shouldUnwrapCommonJSToESM()) { - p.commonjs_named_exports_needs_conversion = if (is_top_level) - std.math.maxInt(u32) - else - p.commonjs_named_exports_needs_conversion; - } - - data.value = p.visitExpr(data.value); - - if (should_trim_primitive and data.value.isPrimitiveLiteral()) { - return; - } - - // simplify unused - data.value = SideEffects.simplifyUnusedExpr(p, data.value) orelse return; - - if (p.shouldUnwrapCommonJSToESM()) { - if (is_top_level) { - if (data.value.data == .e_binary) { - const to_convert = p.commonjs_named_exports_needs_conversion; - if (to_convert != std.math.maxInt(u32)) { - p.commonjs_named_exports_needs_conversion = std.math.maxInt(u32); - convert: { - const bin: *E.Binary = data.value.data.e_binary; - if (bin.op == .bin_assign and bin.left.data == .e_commonjs_export_identifier) { - var last = &p.commonjs_named_exports.values()[to_convert]; - if (!last.needs_decl) break :convert; - last.needs_decl = false; - - var decls = p.allocator.alloc(Decl, 1) catch unreachable; - const ref = bin.left.data.e_commonjs_export_identifier.ref; - decls[0] = .{ - .binding = p.b(B.Identifier{ .ref = ref }, bin.left.loc), - .value = bin.right, - }; - // we have to ensure these are known to be top-level - p.declared_symbols.append(p.allocator, .{ - .ref = ref, - .is_top_level = true, - }) catch unreachable; - p.esm_export_keyword.loc = stmt.loc; - p.esm_export_keyword.len = 5; - p.had_commonjs_named_exports_this_visit = true; - var clause_items = p.allocator.alloc(js_ast.ClauseItem, 1) catch unreachable; - clause_items[0] = js_ast.ClauseItem{ - // We want the generated name to not conflict - .alias = p.commonjs_named_exports.keys()[to_convert], - .alias_loc = bin.left.loc, - .name = .{ - .ref = ref, - .loc = last.loc_ref.loc, - }, - }; - stmts.appendSlice( - &[_]Stmt{ - p.s( - S.Local{ - .kind = .k_var, - .is_export = false, - .was_commonjs_export = true, - .decls = G.Decl.List.init(decls), - }, - stmt.loc, - ), - p.s( - S.ExportClause{ - .items = clause_items, - .is_single_line = true, - }, - stmt.loc, - ), - }, - ) catch unreachable; - - return; - } - } - } else if (p.commonjs_replacement_stmts.len > 0) { - if (stmts.items.len == 0) { - stmts.items = p.commonjs_replacement_stmts; - stmts.capacity = p.commonjs_replacement_stmts.len; - p.commonjs_replacement_stmts.len = 0; - } else { - stmts.appendSlice(p.commonjs_replacement_stmts) catch unreachable; - p.commonjs_replacement_stmts.len = 0; - } + data.value = .{ + .expr = p.getReactRefreshHookSignalInit(hook, p.newExpr( + E.Function{ .func = func.func }, + stmt.loc, + )), + }; + } + if (p.is_control_flow_dead) { return; } + + if (mark_for_replace) { + const entry = p.options.features.replace_exports.getPtr("default").?; + if (entry.* == .replace) { + data.value = .{ .expr = entry.replace }; + } else { + _ = p.injectReplacementExport(stmts, Ref.None, logger.Loc.Empty, entry); + return; + } + } + + if (data.default_name.ref.?.isSourceContentsSlice()) { + data.default_name = createDefaultName(p, stmt.loc) catch unreachable; + } + + if (p.options.features.server_components.wrapsExports()) { + data.value = .{ .expr = p.wrapValueForServerComponentReference(p.newExpr(E.Function{ .func = func.func }, stmt.loc), "default") }; + } + + stmts.append(stmt.*) catch unreachable; + + // if (func.func.name != null and func.func.name.?.ref != null) { + // stmts.append(p.keepStmtSymbolName(func.func.name.?.loc, func.func.name.?.ref.?, name)) catch unreachable; + // } + // prevent doubling export default function name + return; + }, + .s_class => |class| { + _ = p.visitClass(s2.loc, &class.class, data.default_name.ref.?); + + if (p.is_control_flow_dead) + return; + + if (mark_for_replace) { + const entry = p.options.features.replace_exports.getPtr("default").?; + if (entry.* == .replace) { + data.value = .{ .expr = entry.replace }; + } else { + _ = p.injectReplacementExport(stmts, Ref.None, logger.Loc.Empty, entry); + return; + } + } + + if (data.default_name.ref.?.isSourceContentsSlice()) { + data.default_name = createDefaultName(p, stmt.loc) catch unreachable; + } + + // We only inject a name into classes when there is a decorator + if (class.class.has_decorators) { + if (class.class.class_name == null or + class.class.class_name.?.ref == null) + { + class.class.class_name = data.default_name; + } + } + + // This is to handle TS decorators, mostly. + var class_stmts = p.lowerClass(.{ .stmt = s2 }); + bun.assert(class_stmts[0].data == .s_class); + + if (class_stmts.len > 1) { + data.value.stmt = class_stmts[0]; + stmts.append(stmt.*) catch {}; + stmts.appendSlice(class_stmts[1..]) catch {}; + } else { + data.value.stmt = class_stmts[0]; + stmts.append(stmt.*) catch {}; + } + + if (p.options.features.server_components.wrapsExports()) { + data.value = .{ .expr = p.wrapValueForServerComponentReference(p.newExpr(class.class, stmt.loc), "default") }; + } + + return; + }, + else => {}, + } + }, + } + + try stmts.append(stmt.*); + } + pub fn s_function(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Function) !void { + // We mark it as dead, but the value may not actually be dead + // We just want to be sure to not increment the usage counts for anything in the function + const mark_as_dead = p.options.features.dead_code_elimination and data.func.flags.contains(.is_export) and + p.options.features.replace_exports.count() > 0 and p.isExportToEliminate(data.func.name.?.ref.?); + const original_is_dead = p.is_control_flow_dead; + + if (mark_as_dead) { + p.is_control_flow_dead = true; + } + defer { + if (mark_as_dead) { + p.is_control_flow_dead = original_is_dead; + } + } + + var react_hook_data: ?ReactRefresh.HookContext = null; + const prev = p.react_refresh.hook_ctx_storage; + defer p.react_refresh.hook_ctx_storage = prev; + p.react_refresh.hook_ctx_storage = &react_hook_data; + + data.func = p.visitFunc(data.func, data.func.open_parens_loc); + + const name_ref = data.func.name.?.ref.?; + bun.assert(name_ref.tag == .symbol); + const name_symbol = &p.symbols.items[name_ref.innerIndex()]; + const original_name = name_symbol.original_name; + + // Handle exporting this function from a namespace + if (data.func.flags.contains(.is_export) and p.enclosing_namespace_arg_ref != null) { + data.func.flags.remove(.is_export); + + const enclosing_namespace_arg_ref = p.enclosing_namespace_arg_ref orelse bun.outOfMemory(); + stmts.ensureUnusedCapacity(3) catch bun.outOfMemory(); + stmts.appendAssumeCapacity(stmt.*); + stmts.appendAssumeCapacity(Stmt.assign( + p.newExpr(E.Dot{ + .target = p.newExpr(E.Identifier{ .ref = enclosing_namespace_arg_ref }, stmt.loc), + .name = original_name, + .name_loc = data.func.name.?.loc, + }, stmt.loc), + p.newExpr(E.Identifier{ .ref = data.func.name.?.ref.? }, data.func.name.?.loc), + )); + } else if (!mark_as_dead) { + if (name_symbol.remove_overwritten_function_declaration) { + return; + } + + if (p.options.features.server_components.wrapsExports() and data.func.flags.contains(.is_export)) { + // Convert this into `export var = registerClientReference(, ...);` + const name = data.func.name.?; + // From the inner scope, have code reference the wrapped function. + data.func.name = null; + try stmts.append(p.s(S.Local{ + .kind = .k_var, + .is_export = true, + .decls = try G.Decl.List.fromSlice(p.allocator, &.{.{ + .binding = p.b(B.Identifier{ .ref = name_ref }, name.loc), + .value = p.wrapValueForServerComponentReference( + p.newExpr(E.Function{ .func = data.func }, stmt.loc), + original_name, + ), + }}), + }, stmt.loc)); + } else { + stmts.append(stmt.*) catch bun.outOfMemory(); + } + } else if (mark_as_dead) { + if (p.options.features.replace_exports.getPtr(original_name)) |replacement| { + _ = p.injectReplacementExport(stmts, name_ref, data.func.name.?.loc, replacement); + } + } + + if (p.options.features.react_fast_refresh) { + if (react_hook_data) |*hook| { + try stmts.append(p.getReactRefreshHookSignalDecl(hook.signature_cb)); + try stmts.append(p.s(S.SExpr{ + .value = p.getReactRefreshHookSignalInit(hook, Expr.initIdentifier(name_ref, logger.Loc.Empty)), + }, logger.Loc.Empty)); + } + + if (p.current_scope == p.module_scope) { + try p.handleReactRefreshRegister(stmts, original_name, name_ref); + } + } + + return; + } + + pub fn s_class(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Class) !void { + const mark_as_dead = p.options.features.dead_code_elimination and data.is_export and + p.options.features.replace_exports.count() > 0 and p.isExportToEliminate(data.class.class_name.?.ref.?); + const original_is_dead = p.is_control_flow_dead; + + if (mark_as_dead) { + p.is_control_flow_dead = true; + } + defer { + if (mark_as_dead) { + p.is_control_flow_dead = original_is_dead; + } + } + + _ = p.visitClass(stmt.loc, &data.class, Ref.None); + + // Remove the export flag inside a namespace + const was_export_inside_namespace = data.is_export and p.enclosing_namespace_arg_ref != null; + if (was_export_inside_namespace) { + data.is_export = false; + } + + const lowered = p.lowerClass(js_ast.StmtOrExpr{ .stmt = stmt.* }); + + if (!mark_as_dead or was_export_inside_namespace) + // Lower class field syntax for browsers that don't support it + stmts.appendSlice(lowered) catch unreachable + else { + const ref = data.class.class_name.?.ref.?; + if (p.options.features.replace_exports.getPtr(p.loadNameFromRef(ref))) |replacement| { + if (p.injectReplacementExport(stmts, ref, data.class.class_name.?.loc, replacement)) { + p.is_control_flow_dead = original_is_dead; + } + } + } + + // Handle exporting this class from a namespace + if (was_export_inside_namespace) { + stmts.append( + Stmt.assign( + p.newExpr( + E.Dot{ + .target = p.newExpr( + E.Identifier{ .ref = p.enclosing_namespace_arg_ref.? }, + stmt.loc, + ), + .name = p.symbols.items[data.class.class_name.?.ref.?.innerIndex()].original_name, + .name_loc = data.class.class_name.?.loc, + }, + stmt.loc, + ), + p.newExpr( + E.Identifier{ .ref = data.class.class_name.?.ref.? }, + data.class.class_name.?.loc, + ), + ), + ) catch unreachable; + } + + return; + } + pub fn s_export_equals(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.ExportEquals) !void { + // "module.exports = value" + stmts.append( + Stmt.assign( + p.@"module.exports"(stmt.loc), + p.visitExpr(data.value), + ), + ) catch unreachable; + p.recordUsage(p.module_ref); + return; + } + pub fn s_break(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Break) !void { + if (data.label) |*label| { + const name = p.loadNameFromRef(label.ref orelse p.panicLoc("Expected label to have a ref", .{}, label.loc)); + const res = p.findLabelSymbol(label.loc, name); + if (res.found) { + label.ref = res.ref; + } else { + data.label = null; + } + } else if (!p.fn_or_arrow_data_visit.is_inside_loop and !p.fn_or_arrow_data_visit.is_inside_switch) { + const r = js_lexer.rangeOfIdentifier(p.source, stmt.loc); + p.log.addRangeError(p.source, r, "Cannot use \"break\" here") catch unreachable; + } + + try stmts.append(stmt.*); + } + pub fn s_continue(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Continue) !void { + if (data.label) |*label| { + const name = p.loadNameFromRef(label.ref orelse p.panicLoc("Expected continue label to have a ref", .{}, label.loc)); + const res = p.findLabelSymbol(label.loc, name); + label.ref = res.ref; + if (res.found and !res.is_loop) { + const r = js_lexer.rangeOfIdentifier(p.source, stmt.loc); + p.log.addRangeErrorFmt(p.source, r, p.allocator, "Cannot \"continue\" to label {s}", .{name}) catch unreachable; + } + } else if (!p.fn_or_arrow_data_visit.is_inside_loop) { + const r = js_lexer.rangeOfIdentifier(p.source, stmt.loc); + p.log.addRangeError(p.source, r, "Cannot use \"continue\" here") catch unreachable; + } + + try stmts.append(stmt.*); + } + pub fn s_label(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Label) !void { + p.pushScopeForVisitPass(.label, stmt.loc) catch unreachable; + const name = p.loadNameFromRef(data.name.ref.?); + const ref = p.newSymbol(.label, name) catch unreachable; + data.name.ref = ref; + p.current_scope.label_ref = ref; + switch (data.stmt.data) { + .s_for, .s_for_in, .s_for_of, .s_while, .s_do_while => { + p.current_scope.label_stmt_is_loop = true; + }, + else => {}, + } + + data.stmt = p.visitSingleStmt(data.stmt, StmtsKind.none); + p.popScope(); + + try stmts.append(stmt.*); + } + pub fn s_local(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Local, was_after_after_const_local_prefix: bool) !void { + // TODO: Silently remove unsupported top-level "await" in dead code branches + // (this was from 'await using' syntax) + + // Local statements do not end the const local prefix + p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; + + const decls_len = if (!(data.is_export and p.options.features.replace_exports.entries.len > 0)) + p.visitDecls(data.decls.slice(), data.kind == .k_const, false) + else + p.visitDecls(data.decls.slice(), data.kind == .k_const, true); + + const is_now_dead = data.decls.len > 0 and decls_len == 0; + if (is_now_dead) { + return; + } + + data.decls.len = @as(u32, @truncate(decls_len)); + + // Handle being exported inside a namespace + if (data.is_export and p.enclosing_namespace_arg_ref != null) { + for (data.decls.slice()) |*d| { + if (d.value) |val| { + p.recordUsage((p.enclosing_namespace_arg_ref orelse unreachable)); + // TODO: is it necessary to lowerAssign? why does esbuild do it _most_ of the time? + stmts.append(p.s(S.SExpr{ + .value = Expr.assign(Binding.toExpr(&d.binding, p.to_expr_wrapper_namespace), val), + }, stmt.loc)) catch unreachable; + } + } + + return; + } + + // Optimization: Avoid unnecessary "using" machinery by changing ones + // initialized to "null" or "undefined" into a normal variable. Note that + // "await using" still needs the "await", so we can't do it for those. + if (p.options.features.minify_syntax and data.kind == .k_using) { + data.kind = .k_let; + for (data.decls.slice()) |*d| { + if (d.value) |val| { + if (val.data != .e_null and val.data != .e_undefined) { + data.kind = .k_using; + break; } } } - }, - .s_throw => |data| { - data.value = p.visitExpr(data.value); - }, - .s_return => |data| { - // Forbid top-level return inside modules with ECMAScript-style exports - if (p.fn_or_arrow_data_visit.is_outside_fn_or_arrow) { - const where = where: { - if (p.esm_export_keyword.len > 0) { - break :where p.esm_export_keyword; - } else if (p.top_level_await_keyword.len > 0) { - break :where p.top_level_await_keyword; - } else { - break :where logger.Range.None; - } + } + + // We must relocate vars in order to safely handle removing if/else depending on NODE_ENV. + // Edgecase: + // `export var` is skipped because it's unnecessary. That *should* be a noop, but it loses the `is_export` flag if we're in HMR. + const kind = p.selectLocalKind(data.kind); + if (kind == .k_var and !data.is_export) { + const relocated = p.maybeRelocateVarsToTopLevel(data.decls.slice(), .normal); + if (relocated.ok) { + if (relocated.stmt) |new_stmt| { + stmts.append(new_stmt) catch unreachable; + } + + return; + } + } + + data.kind = kind; + try stmts.append(stmt.*); + + if (data.is_export and p.options.features.server_components.wrapsExports()) { + for (data.decls.slice()) |*decl| try_annotate: { + const val = decl.value orelse break :try_annotate; + switch (val.data) { + .e_arrow, .e_function => {}, + else => break :try_annotate, + } + const id = switch (decl.binding.data) { + .b_identifier => |id| id.ref, + else => break :try_annotate, }; + const original_name = p.symbols.items[id.innerIndex()].original_name; + decl.value = p.wrapValueForServerComponentReference(val, original_name); + } + } - if (where.len > 0) { - p.log.addRangeError(p.source, where, "Top-level return cannot be used inside an ECMAScript module") catch unreachable; + if (p.options.features.react_fast_refresh and p.current_scope == p.module_scope) { + for (data.decls.slice()) |decl| try_register: { + const val = decl.value orelse break :try_register; + switch (val.data) { + .e_arrow, .e_function => {}, + else => break :try_register, + } + const id = switch (decl.binding.data) { + .b_identifier => |id| id.ref, + else => break :try_register, + }; + const original_name = p.symbols.items[id.innerIndex()].original_name; + try p.handleReactRefreshRegister(stmts, original_name, id); + } + } + + return; + } + pub fn s_expr(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.SExpr) !void { + const should_trim_primitive = p.options.features.dead_code_elimination and + (p.options.features.minify_syntax and data.value.isPrimitiveLiteral()); + p.stmt_expr_value = data.value.data; + defer p.stmt_expr_value = .{ .e_missing = .{} }; + + const is_top_level = p.current_scope == p.module_scope; + if (p.shouldUnwrapCommonJSToESM()) { + p.commonjs_named_exports_needs_conversion = if (is_top_level) + std.math.maxInt(u32) + else + p.commonjs_named_exports_needs_conversion; + } + + data.value = p.visitExpr(data.value); + + if (should_trim_primitive and data.value.isPrimitiveLiteral()) { + return; + } + + // simplify unused + data.value = SideEffects.simplifyUnusedExpr(p, data.value) orelse return; + + if (p.shouldUnwrapCommonJSToESM()) { + if (is_top_level) { + if (data.value.data == .e_binary) { + const to_convert = p.commonjs_named_exports_needs_conversion; + if (to_convert != std.math.maxInt(u32)) { + p.commonjs_named_exports_needs_conversion = std.math.maxInt(u32); + convert: { + const bin: *E.Binary = data.value.data.e_binary; + if (bin.op == .bin_assign and bin.left.data == .e_commonjs_export_identifier) { + var last = &p.commonjs_named_exports.values()[to_convert]; + if (!last.needs_decl) break :convert; + last.needs_decl = false; + + var decls = p.allocator.alloc(Decl, 1) catch unreachable; + const ref = bin.left.data.e_commonjs_export_identifier.ref; + decls[0] = .{ + .binding = p.b(B.Identifier{ .ref = ref }, bin.left.loc), + .value = bin.right, + }; + // we have to ensure these are known to be top-level + p.declared_symbols.append(p.allocator, .{ + .ref = ref, + .is_top_level = true, + }) catch unreachable; + p.esm_export_keyword.loc = stmt.loc; + p.esm_export_keyword.len = 5; + p.had_commonjs_named_exports_this_visit = true; + var clause_items = p.allocator.alloc(js_ast.ClauseItem, 1) catch unreachable; + clause_items[0] = js_ast.ClauseItem{ + // We want the generated name to not conflict + .alias = p.commonjs_named_exports.keys()[to_convert], + .alias_loc = bin.left.loc, + .name = .{ + .ref = ref, + .loc = last.loc_ref.loc, + }, + }; + stmts.appendSlice( + &[_]Stmt{ + p.s( + S.Local{ + .kind = .k_var, + .is_export = false, + .was_commonjs_export = true, + .decls = G.Decl.List.init(decls), + }, + stmt.loc, + ), + p.s( + S.ExportClause{ + .items = clause_items, + .is_single_line = true, + }, + stmt.loc, + ), + }, + ) catch unreachable; + + return; + } + } + } else if (p.commonjs_replacement_stmts.len > 0) { + if (stmts.items.len == 0) { + stmts.items = p.commonjs_replacement_stmts; + stmts.capacity = p.commonjs_replacement_stmts.len; + p.commonjs_replacement_stmts.len = 0; + } else { + stmts.appendSlice(p.commonjs_replacement_stmts) catch unreachable; + p.commonjs_replacement_stmts.len = 0; + } + + return; + } } } + } - if (data.value) |val| { - data.value = p.visitExpr(val); - - // "return undefined;" can safely just always be "return;" - if (data.value != null and @as(Expr.Tag, data.value.?.data) == .e_undefined) { - // Returning undefined is implicit - data.value = null; + try stmts.append(stmt.*); + } + pub fn s_throw(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Throw) !void { + data.value = p.visitExpr(data.value); + try stmts.append(stmt.*); + } + pub fn s_return(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Return) !void { + // Forbid top-level return inside modules with ECMAScript-style exports + if (p.fn_or_arrow_data_visit.is_outside_fn_or_arrow) { + const where = where: { + if (p.esm_export_keyword.len > 0) { + break :where p.esm_export_keyword; + } else if (p.top_level_await_keyword.len > 0) { + break :where p.top_level_await_keyword; + } else { + break :where logger.Range.None; } + }; + + if (where.len > 0) { + p.log.addRangeError(p.source, where, "Top-level return cannot be used inside an ECMAScript module") catch unreachable; } - }, - .s_block => |data| { - { - p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; + } - // Pass the "is loop body" status on to the direct children of a block used - // as a loop body. This is used to enable optimizations specific to the - // topmost scope in a loop body block. - const kind = if (std.meta.eql(p.loop_body, stmt.data)) StmtsKind.loop_body else StmtsKind.none; - var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.stmts); - p.visitStmts(&_stmts, kind) catch unreachable; - data.stmts = _stmts.items; - p.popScope(); + if (data.value) |val| { + data.value = p.visitExpr(val); + + // "return undefined;" can safely just always be "return;" + if (data.value != null and @as(Expr.Tag, data.value.?.data) == .e_undefined) { + // Returning undefined is implicit + data.value = null; } + } - if (p.options.features.minify_syntax) { - // // trim empty statements - if (data.stmts.len == 0) { - stmts.append(Stmt{ .data = Prefill.Data.SEmpty, .loc = stmt.loc }) catch unreachable; - return; - } else if (data.stmts.len == 1 and !statementCaresAboutScope(data.stmts[0])) { - // Unwrap blocks containing a single statement - stmts.append(data.stmts[0]) catch unreachable; - return; - } - } - }, - .s_with => |data| { - data.value = p.visitExpr(data.value); - - p.pushScopeForVisitPass(.with, data.body_loc) catch unreachable; - - // This can be many different kinds of statements. - // example code: - // - // with(this.document.defaultView || Object.create(null)) - // with(this.document) - // with(this.form) - // with(this.element) - // - data.body = p.visitSingleStmt(data.body, StmtsKind.none); + try stmts.append(stmt.*); + } + pub fn s_block(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Block) !void { + { + p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; + // Pass the "is loop body" status on to the direct children of a block used + // as a loop body. This is used to enable optimizations specific to the + // topmost scope in a loop body block. + const kind = if (std.meta.eql(p.loop_body, stmt.data)) StmtsKind.loop_body else StmtsKind.none; + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.stmts); + p.visitStmts(&_stmts, kind) catch unreachable; + data.stmts = _stmts.items; p.popScope(); - }, - .s_while => |data| { - data.test_ = p.visitExpr(data.test_); - data.body = p.visitLoopBody(data.body); + } - data.test_ = SideEffects.simplifyBoolean(p, data.test_); - const result = SideEffects.toBoolean(p, data.test_.data); - if (result.ok and result.side_effects == .no_side_effects) { - data.test_ = p.newExpr(E.Boolean{ .value = result.value }, data.test_.loc); + if (p.options.features.minify_syntax) { + // // trim empty statements + if (data.stmts.len == 0) { + stmts.append(Stmt{ .data = Prefill.Data.SEmpty, .loc = stmt.loc }) catch unreachable; + return; + } else if (data.stmts.len == 1 and !statementCaresAboutScope(data.stmts[0])) { + // Unwrap blocks containing a single statement + stmts.append(data.stmts[0]) catch unreachable; + return; } - }, - .s_do_while => |data| { - data.body = p.visitLoopBody(data.body); - data.test_ = p.visitExpr(data.test_); + } + try stmts.append(stmt.*); + } + pub fn s_with(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.With) !void { + data.value = p.visitExpr(data.value); + + p.pushScopeForVisitPass(.with, data.body_loc) catch unreachable; + + // This can be many different kinds of statements. + // example code: + // + // with(this.document.defaultView || Object.create(null)) + // with(this.document) + // with(this.form) + // with(this.element) + // + data.body = p.visitSingleStmt(data.body, StmtsKind.none); + + p.popScope(); + try stmts.append(stmt.*); + } + pub fn s_while(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.While) !void { + data.test_ = p.visitExpr(data.test_); + data.body = p.visitLoopBody(data.body); + + data.test_ = SideEffects.simplifyBoolean(p, data.test_); + const result = SideEffects.toBoolean(p, data.test_.data); + if (result.ok and result.side_effects == .no_side_effects) { + data.test_ = p.newExpr(E.Boolean{ .value = result.value }, data.test_.loc); + } + + try stmts.append(stmt.*); + } + pub fn s_do_while(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.DoWhile) !void { + data.body = p.visitLoopBody(data.body); + data.test_ = p.visitExpr(data.test_); + + data.test_ = SideEffects.simplifyBoolean(p, data.test_); + try stmts.append(stmt.*); + } + pub fn s_if(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.If) !void { + data.test_ = p.visitExpr(data.test_); + + if (p.options.features.minify_syntax) { data.test_ = SideEffects.simplifyBoolean(p, data.test_); - }, - .s_if => |data| { - data.test_ = p.visitExpr(data.test_); + } - if (p.options.features.minify_syntax) { - data.test_ = SideEffects.simplifyBoolean(p, data.test_); - } + const effects = SideEffects.toBoolean(p, data.test_.data); + if (effects.ok and !effects.value) { + const old = p.is_control_flow_dead; + p.is_control_flow_dead = true; + data.yes = p.visitSingleStmt(data.yes, StmtsKind.none); + p.is_control_flow_dead = old; + } else { + data.yes = p.visitSingleStmt(data.yes, StmtsKind.none); + } - const effects = SideEffects.toBoolean(p, data.test_.data); - if (effects.ok and !effects.value) { + // The "else" clause is optional + if (data.no) |no| { + if (effects.ok and effects.value) { const old = p.is_control_flow_dead; p.is_control_flow_dead = true; - data.yes = p.visitSingleStmt(data.yes, StmtsKind.none); - p.is_control_flow_dead = old; + defer p.is_control_flow_dead = old; + data.no = p.visitSingleStmt(no, .none); } else { - data.yes = p.visitSingleStmt(data.yes, StmtsKind.none); - } - - // The "else" clause is optional - if (data.no) |no| { - if (effects.ok and effects.value) { - const old = p.is_control_flow_dead; - p.is_control_flow_dead = true; - defer p.is_control_flow_dead = old; - data.no = p.visitSingleStmt(no, .none); - } else { - data.no = p.visitSingleStmt(no, .none); - } - - // Trim unnecessary "else" clauses - if (p.options.features.minify_syntax) { - if (data.no != null and @as(Stmt.Tag, data.no.?.data) == .s_empty) { - data.no = null; - } - } + data.no = p.visitSingleStmt(no, .none); } + // Trim unnecessary "else" clauses if (p.options.features.minify_syntax) { - if (effects.ok) { - if (effects.value) { - if (data.no == null or !SideEffects.shouldKeepStmtInDeadControlFlow(p, data.no.?, p.allocator)) { - if (effects.side_effects == .could_have_side_effects) { - // Keep the condition if it could have side effects (but is still known to be truthy) - if (SideEffects.simplifyUnusedExpr(p, data.test_)) |test_| { - stmts.append(p.s(S.SExpr{ .value = test_ }, test_.loc)) catch unreachable; - } - } + if (data.no != null and @as(Stmt.Tag, data.no.?.data) == .s_empty) { + data.no = null; + } + } + } - return try p.appendIfBodyPreservingScope(stmts, data.yes); - } else { - // We have to keep the "no" branch + if (p.options.features.minify_syntax) { + if (effects.ok) { + if (effects.value) { + if (data.no == null or !SideEffects.shouldKeepStmtInDeadControlFlow(p, data.no.?, p.allocator)) { + if (effects.side_effects == .could_have_side_effects) { + // Keep the condition if it could have side effects (but is still known to be truthy) + if (SideEffects.simplifyUnusedExpr(p, data.test_)) |test_| { + stmts.append(p.s(S.SExpr{ .value = test_ }, test_.loc)) catch unreachable; + } } + + return try p.appendIfBodyPreservingScope(stmts, data.yes); } else { - // The test is falsy - if (!SideEffects.shouldKeepStmtInDeadControlFlow(p, data.yes, p.allocator)) { - if (effects.side_effects == .could_have_side_effects) { - // Keep the condition if it could have side effects (but is still known to be truthy) - if (SideEffects.simplifyUnusedExpr(p, data.test_)) |test_| { - stmts.append(p.s(S.SExpr{ .value = test_ }, test_.loc)) catch unreachable; - } + // We have to keep the "no" branch + } + } else { + // The test is falsy + if (!SideEffects.shouldKeepStmtInDeadControlFlow(p, data.yes, p.allocator)) { + if (effects.side_effects == .could_have_side_effects) { + // Keep the condition if it could have side effects (but is still known to be truthy) + if (SideEffects.simplifyUnusedExpr(p, data.test_)) |test_| { + stmts.append(p.s(S.SExpr{ .value = test_ }, test_.loc)) catch unreachable; } - - if (data.no == null) { - return; - } - - return try p.appendIfBodyPreservingScope(stmts, data.no.?); } + + if (data.no == null) { + return; + } + + return try p.appendIfBodyPreservingScope(stmts, data.no.?); } } + } - // TODO: more if statement syntax minification - const can_remove_test = p.exprCanBeRemovedIfUnused(&data.test_); - switch (data.yes.data) { - .s_expr => |yes_expr| { - if (yes_expr.value.isMissing()) { - if (data.no == null) { - if (can_remove_test) { - return; - } - } else if (data.no.?.isMissingExpr() and can_remove_test) { - return; - } - } - }, - .s_empty => { + // TODO: more if statement syntax minification + const can_remove_test = p.exprCanBeRemovedIfUnused(&data.test_); + switch (data.yes.data) { + .s_expr => |yes_expr| { + if (yes_expr.value.isMissing()) { if (data.no == null) { if (can_remove_test) { return; @@ -19811,590 +20053,457 @@ fn NewParser_( } else if (data.no.?.isMissingExpr() and can_remove_test) { return; } - }, - else => {}, - } - } - }, - .s_for => |data| { - p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; - - if (data.init) |initst| { - data.init = p.visitForLoopInit(initst, false); - } - - if (data.test_) |test_| { - data.test_ = SideEffects.simplifyBoolean(p, p.visitExpr(test_)); - - const result = SideEffects.toBoolean(p, data.test_.?.data); - if (result.ok and result.value and result.side_effects == .no_side_effects) { - data.test_ = null; - } - } - - if (data.update) |update| { - data.update = p.visitExpr(update); - } - - data.body = p.visitLoopBody(data.body); - - if (data.init) |for_init| { - if (for_init.data == .s_local) { - // Potentially relocate "var" declarations to the top level. Note that this - // must be done inside the scope of the for loop or they won't be relocated. - if (for_init.data.s_local.kind == .k_var) { - const relocate = p.maybeRelocateVarsToTopLevel(for_init.data.s_local.decls.slice(), .normal); - if (relocate.stmt) |relocated| { - data.init = relocated; + } + }, + .s_empty => { + if (data.no == null) { + if (can_remove_test) { + return; } + } else if (data.no.?.isMissingExpr() and can_remove_test) { + return; + } + }, + else => {}, + } + } + + try stmts.append(stmt.*); + } + pub fn s_for(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.For) !void { + p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; + + if (data.init) |initst| { + data.init = p.visitForLoopInit(initst, false); + } + + if (data.test_) |test_| { + data.test_ = SideEffects.simplifyBoolean(p, p.visitExpr(test_)); + + const result = SideEffects.toBoolean(p, data.test_.?.data); + if (result.ok and result.value and result.side_effects == .no_side_effects) { + data.test_ = null; + } + } + + if (data.update) |update| { + data.update = p.visitExpr(update); + } + + data.body = p.visitLoopBody(data.body); + + if (data.init) |for_init| { + if (for_init.data == .s_local) { + // Potentially relocate "var" declarations to the top level. Note that this + // must be done inside the scope of the for loop or they won't be relocated. + if (for_init.data.s_local.kind == .k_var) { + const relocate = p.maybeRelocateVarsToTopLevel(for_init.data.s_local.decls.slice(), .normal); + if (relocate.stmt) |relocated| { + data.init = relocated; } } } + } - p.popScope(); - }, - .s_for_in => |data| { - { - p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; - defer p.popScope(); - _ = p.visitForLoopInit(data.init, true); - data.value = p.visitExpr(data.value); - data.body = p.visitLoopBody(data.body); + p.popScope(); - // Check for a variable initializer - if (data.init.data == .s_local and data.init.data.s_local.kind == .k_var) { - // Lower for-in variable initializers in case the output is used in strict mode - var local = data.init.data.s_local; - if (local.decls.len == 1) { - var decl: *G.Decl = &local.decls.ptr[0]; - if (decl.binding.data == .b_identifier) { - if (decl.value) |val| { - stmts.append( - Stmt.assign( - Expr.initIdentifier(decl.binding.data.b_identifier.ref, decl.binding.loc), - val, - ), - ) catch unreachable; - decl.value = null; - } - } - } - - const relocate = p.maybeRelocateVarsToTopLevel(data.init.data.s_local.decls.slice(), RelocateVars.Mode.for_in_or_for_of); - if (relocate.stmt) |relocated_stmt| { - data.init = relocated_stmt; - } - } - } - }, - .s_for_of => |data| { + try stmts.append(stmt.*); + } + pub fn s_for_in(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.ForIn) !void { + { p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; defer p.popScope(); _ = p.visitForLoopInit(data.init, true); data.value = p.visitExpr(data.value); data.body = p.visitLoopBody(data.body); - if (data.init.data == .s_local) { - if (data.init.data.s_local.kind == .k_var) { - const relocate = p.maybeRelocateVarsToTopLevel(data.init.data.s_local.decls.slice(), RelocateVars.Mode.for_in_or_for_of); - if (relocate.stmt) |relocated_stmt| { - data.init = relocated_stmt; + // Check for a variable initializer + if (data.init.data == .s_local and data.init.data.s_local.kind == .k_var) { + // Lower for-in variable initializers in case the output is used in strict mode + var local = data.init.data.s_local; + if (local.decls.len == 1) { + var decl: *G.Decl = &local.decls.ptr[0]; + if (decl.binding.data == .b_identifier) { + if (decl.value) |val| { + stmts.append( + Stmt.assign( + Expr.initIdentifier(decl.binding.data.b_identifier.ref, decl.binding.loc), + val, + ), + ) catch unreachable; + decl.value = null; + } } } - // Handle "for (using x of y)" and "for (await using x of y)" - if (data.init.data == .s_local and data.init.data.s_local.kind.isUsing() and p.options.features.lower_using) { - // fn lowerUsingDeclarationInForOf() - const loc = data.init.loc; - const init2 = data.init.data.s_local; - const binding = init2.decls.at(0).binding; - var id = binding.data.b_identifier; - const temp_ref = p.generateTempRef(p.symbols.items[id.ref.inner_index].original_name); - - const first = p.s(S.Local{ - .kind = init2.kind, - .decls = bindings: { - const decls = p.allocator.alloc(G.Decl, 1) catch bun.outOfMemory(); - decls[0] = .{ - .binding = p.b(B.Identifier{ .ref = id.ref }, loc), - .value = p.newExpr(E.Identifier{ .ref = temp_ref }, loc), - }; - break :bindings G.Decl.List.init(decls); - }, - }, loc); - - const length = if (data.body.data == .s_block) data.body.data.s_block.stmts.len else 1; - const statements = p.allocator.alloc(Stmt, 1 + length) catch bun.outOfMemory(); - statements[0] = first; - if (data.body.data == .s_block) { - @memcpy(statements[1..], data.body.data.s_block.stmts); - } else { - statements[1] = data.body; - } - - var ctx = try P.LowerUsingDeclarationsContext.init(p); - ctx.scanStmts(p, statements); - const visited_stmts = ctx.finalize(p, statements, p.will_wrap_module_in_try_catch_for_using and p.current_scope.parent == null); - if (data.body.data == .s_block) { - data.body.data.s_block.stmts = visited_stmts.items; - } else { - data.body = p.s(S.Block{ - .stmts = visited_stmts.items, - }, loc); - } - id.ref = temp_ref; - init2.kind = .k_const; + const relocate = p.maybeRelocateVarsToTopLevel(data.init.data.s_local.decls.slice(), RelocateVars.Mode.for_in_or_for_of); + if (relocate.stmt) |relocated_stmt| { + data.init = relocated_stmt; } } - }, - .s_try => |data| { - p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; + } + + try stmts.append(stmt.*); + } + pub fn s_for_of(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.ForOf) !void { + p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; + defer p.popScope(); + _ = p.visitForLoopInit(data.init, true); + data.value = p.visitExpr(data.value); + data.body = p.visitLoopBody(data.body); + + if (data.init.data == .s_local) { + if (data.init.data.s_local.kind == .k_var) { + const relocate = p.maybeRelocateVarsToTopLevel(data.init.data.s_local.decls.slice(), RelocateVars.Mode.for_in_or_for_of); + if (relocate.stmt) |relocated_stmt| { + data.init = relocated_stmt; + } + } + + // Handle "for (using x of y)" and "for (await using x of y)" + if (data.init.data == .s_local and data.init.data.s_local.kind.isUsing() and p.options.features.lower_using) { + // fn lowerUsingDeclarationInForOf() + const loc = data.init.loc; + const init2 = data.init.data.s_local; + const binding = init2.decls.at(0).binding; + var id = binding.data.b_identifier; + const temp_ref = p.generateTempRef(p.symbols.items[id.ref.inner_index].original_name); + + const first = p.s(S.Local{ + .kind = init2.kind, + .decls = bindings: { + const decls = p.allocator.alloc(G.Decl, 1) catch bun.outOfMemory(); + decls[0] = .{ + .binding = p.b(B.Identifier{ .ref = id.ref }, loc), + .value = p.newExpr(E.Identifier{ .ref = temp_ref }, loc), + }; + break :bindings G.Decl.List.init(decls); + }, + }, loc); + + const length = if (data.body.data == .s_block) data.body.data.s_block.stmts.len else 1; + const statements = p.allocator.alloc(Stmt, 1 + length) catch bun.outOfMemory(); + statements[0] = first; + if (data.body.data == .s_block) { + @memcpy(statements[1..], data.body.data.s_block.stmts); + } else { + statements[1] = data.body; + } + + var ctx = try P.LowerUsingDeclarationsContext.init(p); + ctx.scanStmts(p, statements); + const visited_stmts = ctx.finalize(p, statements, p.will_wrap_module_in_try_catch_for_using and p.current_scope.parent == null); + if (data.body.data == .s_block) { + data.body.data.s_block.stmts = visited_stmts.items; + } else { + data.body = p.s(S.Block{ + .stmts = visited_stmts.items, + }, loc); + } + id.ref = temp_ref; + init2.kind = .k_const; + } + } + + try stmts.append(stmt.*); + } + pub fn s_try(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Try) !void { + p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; + { + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.body); + p.fn_or_arrow_data_visit.try_body_count += 1; + p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; + p.fn_or_arrow_data_visit.try_body_count -= 1; + data.body = _stmts.items; + } + p.popScope(); + + if (data.catch_) |*catch_| { + p.pushScopeForVisitPass(.catch_binding, catch_.loc) catch unreachable; { - var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.body); - p.fn_or_arrow_data_visit.try_body_count += 1; + if (catch_.binding) |catch_binding| { + p.visitBinding(catch_binding, null); + } + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, catch_.body); + p.pushScopeForVisitPass(.block, catch_.body_loc) catch unreachable; p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; - p.fn_or_arrow_data_visit.try_body_count -= 1; - data.body = _stmts.items; + p.popScope(); + catch_.body = _stmts.items; } p.popScope(); + } - if (data.catch_) |*catch_| { - p.pushScopeForVisitPass(.catch_binding, catch_.loc) catch unreachable; - { - if (catch_.binding) |catch_binding| { - p.visitBinding(catch_binding, null); - } - var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, catch_.body); - p.pushScopeForVisitPass(.block, catch_.body_loc) catch unreachable; - p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; - p.popScope(); - catch_.body = _stmts.items; - } - p.popScope(); - } - - if (data.finally) |*finally| { - p.pushScopeForVisitPass(.block, finally.loc) catch unreachable; - { - var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, finally.stmts); - p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; - finally.stmts = _stmts.items; - } - p.popScope(); - } - }, - .s_switch => |data| { - data.test_ = p.visitExpr(data.test_); + if (data.finally) |*finally| { + p.pushScopeForVisitPass(.block, finally.loc) catch unreachable; { - p.pushScopeForVisitPass(.block, data.body_loc) catch unreachable; - defer p.popScope(); - const old_is_inside_Swsitch = p.fn_or_arrow_data_visit.is_inside_switch; - p.fn_or_arrow_data_visit.is_inside_switch = true; - defer p.fn_or_arrow_data_visit.is_inside_switch = old_is_inside_Swsitch; - for (data.cases, 0..) |case, i| { - if (case.value) |val| { - data.cases[i].value = p.visitExpr(val); - // TODO: error messages - // Check("case", *c.Value, c.Value.Loc) - // p.warnAboutTypeofAndString(s.Test, *c.Value) - } - var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, case.body); - p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; - data.cases[i].body = _stmts.items; - } + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, finally.stmts); + p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; + finally.stmts = _stmts.items; } - // TODO: duplicate case checker + p.popScope(); + } - }, - .s_function => |data| { - // We mark it as dead, but the value may not actually be dead - // We just want to be sure to not increment the usage counts for anything in the function - const mark_as_dead = p.options.features.dead_code_elimination and data.func.flags.contains(.is_export) and - p.options.features.replace_exports.count() > 0 and p.isExportToEliminate(data.func.name.?.ref.?); - const original_is_dead = p.is_control_flow_dead; - - if (mark_as_dead) { - p.is_control_flow_dead = true; - } - defer { - if (mark_as_dead) { - p.is_control_flow_dead = original_is_dead; - } - } - - var react_hook_data: ?ReactRefresh.HookContext = null; - const prev = p.react_refresh.hook_ctx_storage; - defer p.react_refresh.hook_ctx_storage = prev; - p.react_refresh.hook_ctx_storage = &react_hook_data; - - data.func = p.visitFunc(data.func, data.func.open_parens_loc); - - const name_ref = data.func.name.?.ref.?; - bun.assert(name_ref.tag == .symbol); - const name_symbol = &p.symbols.items[name_ref.innerIndex()]; - const original_name = name_symbol.original_name; - - // Handle exporting this function from a namespace - if (data.func.flags.contains(.is_export) and p.enclosing_namespace_arg_ref != null) { - data.func.flags.remove(.is_export); - - const enclosing_namespace_arg_ref = p.enclosing_namespace_arg_ref orelse bun.outOfMemory(); - stmts.ensureUnusedCapacity(3) catch bun.outOfMemory(); - stmts.appendAssumeCapacity(stmt.*); - stmts.appendAssumeCapacity(Stmt.assign( - p.newExpr(E.Dot{ - .target = p.newExpr(E.Identifier{ .ref = enclosing_namespace_arg_ref }, stmt.loc), - .name = original_name, - .name_loc = data.func.name.?.loc, - }, stmt.loc), - p.newExpr(E.Identifier{ .ref = data.func.name.?.ref.? }, data.func.name.?.loc), - )); - } else if (!mark_as_dead) { - if (name_symbol.remove_overwritten_function_declaration) { - return; - } - - if (p.options.features.server_components.wrapsExports() and data.func.flags.contains(.is_export)) { - // Convert this into `export var = registerClientReference(, ...);` - const name = data.func.name.?; - // From the inner scope, have code reference the wrapped function. - data.func.name = null; - try stmts.append(p.s(S.Local{ - .kind = .k_var, - .is_export = true, - .decls = try G.Decl.List.fromSlice(p.allocator, &.{.{ - .binding = p.b(B.Identifier{ .ref = name_ref }, name.loc), - .value = p.wrapValueForServerComponentReference( - p.newExpr(E.Function{ .func = data.func }, stmt.loc), - original_name, - ), - }}), - }, stmt.loc)); - } else { - stmts.append(stmt.*) catch bun.outOfMemory(); - } - } else if (mark_as_dead) { - if (p.options.features.replace_exports.getPtr(original_name)) |replacement| { - _ = p.injectReplacementExport(stmts, name_ref, data.func.name.?.loc, replacement); - } - } - - if (p.options.features.react_fast_refresh) { - if (react_hook_data) |*hook| { - try stmts.append(p.getReactRefreshHookSignalDecl(hook.signature_cb)); - try stmts.append(p.s(S.SExpr{ - .value = p.getReactRefreshHookSignalInit(hook, Expr.initIdentifier(name_ref, logger.Loc.Empty)), - }, logger.Loc.Empty)); - } - - if (p.current_scope == p.module_scope) { - try p.handleReactRefreshRegister(stmts, original_name, name_ref); - } - } - - return; - }, - .s_class => |data| { - const mark_as_dead = p.options.features.dead_code_elimination and data.is_export and - p.options.features.replace_exports.count() > 0 and p.isExportToEliminate(data.class.class_name.?.ref.?); - const original_is_dead = p.is_control_flow_dead; - - if (mark_as_dead) { - p.is_control_flow_dead = true; - } - defer { - if (mark_as_dead) { - p.is_control_flow_dead = original_is_dead; - } - } - - _ = p.visitClass(stmt.loc, &data.class, Ref.None); - - // Remove the export flag inside a namespace - const was_export_inside_namespace = data.is_export and p.enclosing_namespace_arg_ref != null; - if (was_export_inside_namespace) { - data.is_export = false; - } - - const lowered = p.lowerClass(js_ast.StmtOrExpr{ .stmt = stmt.* }); - - if (!mark_as_dead or was_export_inside_namespace) - // Lower class field syntax for browsers that don't support it - stmts.appendSlice(lowered) catch unreachable - else { - const ref = data.class.class_name.?.ref.?; - if (p.options.features.replace_exports.getPtr(p.loadNameFromRef(ref))) |replacement| { - if (p.injectReplacementExport(stmts, ref, data.class.class_name.?.loc, replacement)) { - p.is_control_flow_dead = original_is_dead; - } - } - } - - // Handle exporting this class from a namespace - if (was_export_inside_namespace) { - stmts.append( - Stmt.assign( - p.newExpr( - E.Dot{ - .target = p.newExpr( - E.Identifier{ .ref = p.enclosing_namespace_arg_ref.? }, - stmt.loc, - ), - .name = p.symbols.items[data.class.class_name.?.ref.?.innerIndex()].original_name, - .name_loc = data.class.class_name.?.loc, - }, - stmt.loc, - ), - p.newExpr( - E.Identifier{ .ref = data.class.class_name.?.ref.? }, - data.class.class_name.?.loc, - ), - ), - ) catch unreachable; - } - - return; - }, - .s_enum => |data| { - // Do not end the const local prefix after TypeScript enums. We process - // them first within their scope so that they are inlined into all code in - // that scope. We don't want that to cause the const local prefix to end. - p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; - - // Track cross-module enum constants during bundling. This - // part of the code is different from esbuilt in that we are - // only storing a list of enum indexes. At the time of - // referencing, `esbuild` builds a separate hash map of hash - // maps. We are avoiding that to reduce memory usage, since - // enum inlining already uses alot of hash maps. - if (p.current_scope == p.module_scope and p.options.bundle) { - try p.top_level_enums.append(p.allocator, data.name.ref.?); - } - - p.recordDeclaredSymbol(data.name.ref.?) catch bun.outOfMemory(); - p.pushScopeForVisitPass(.entry, stmt.loc) catch bun.outOfMemory(); + try stmts.append(stmt.*); + } + pub fn s_switch(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Switch) !void { + data.test_ = p.visitExpr(data.test_); + { + p.pushScopeForVisitPass(.block, data.body_loc) catch unreachable; defer p.popScope(); - p.recordDeclaredSymbol(data.arg) catch bun.outOfMemory(); - - const allocator = p.allocator; - // Scan ahead for any variables inside this namespace. This must be done - // ahead of time before visiting any statements inside the namespace - // because we may end up visiting the uses before the declarations. - // We need to convert the uses into property accesses on the namespace. - for (data.values) |value| { - if (value.ref.isValid()) { - p.is_exported_inside_namespace.put(allocator, value.ref, data.arg) catch bun.outOfMemory(); + const old_is_inside_Swsitch = p.fn_or_arrow_data_visit.is_inside_switch; + p.fn_or_arrow_data_visit.is_inside_switch = true; + defer p.fn_or_arrow_data_visit.is_inside_switch = old_is_inside_Swsitch; + for (data.cases, 0..) |case, i| { + if (case.value) |val| { + data.cases[i].value = p.visitExpr(val); + // TODO: error messages + // Check("case", *c.Value, c.Value.Loc) + // p.warnAboutTypeofAndString(s.Test, *c.Value) } + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, case.body); + p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; + data.cases[i].body = _stmts.items; + } + } + // TODO: duplicate case checker + + try stmts.append(stmt.*); + } + + pub fn s_enum(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Enum, was_after_after_const_local_prefix: bool) !void { + + // Do not end the const local prefix after TypeScript enums. We process + // them first within their scope so that they are inlined into all code in + // that scope. We don't want that to cause the const local prefix to end. + p.current_scope.is_after_const_local_prefix = was_after_after_const_local_prefix; + + // Track cross-module enum constants during bundling. This + // part of the code is different from esbuilt in that we are + // only storing a list of enum indexes. At the time of + // referencing, `esbuild` builds a separate hash map of hash + // maps. We are avoiding that to reduce memory usage, since + // enum inlining already uses alot of hash maps. + if (p.current_scope == p.module_scope and p.options.bundle) { + try p.top_level_enums.append(p.allocator, data.name.ref.?); + } + + p.recordDeclaredSymbol(data.name.ref.?) catch bun.outOfMemory(); + p.pushScopeForVisitPass(.entry, stmt.loc) catch bun.outOfMemory(); + defer p.popScope(); + p.recordDeclaredSymbol(data.arg) catch bun.outOfMemory(); + + const allocator = p.allocator; + // Scan ahead for any variables inside this namespace. This must be done + // ahead of time before visiting any statements inside the namespace + // because we may end up visiting the uses before the declarations. + // We need to convert the uses into property accesses on the namespace. + for (data.values) |value| { + if (value.ref.isValid()) { + p.is_exported_inside_namespace.put(allocator, value.ref, data.arg) catch bun.outOfMemory(); + } + } + + // Values without initializers are initialized to one more than the + // previous value if the previous value is numeric. Otherwise values + // without initializers are initialized to undefined. + var next_numeric_value: ?f64 = 0.0; + + var value_exprs = ListManaged(Expr).initCapacity(allocator, data.values.len) catch bun.outOfMemory(); + + var all_values_are_pure = true; + + const exported_members = p.current_scope.ts_namespace.?.exported_members; + + // We normally don't fold numeric constants because they might increase code + // size, but it's important to fold numeric constants inside enums since + // that's what the TypeScript compiler does. + const old_should_fold_typescript_constant_expressions = p.should_fold_typescript_constant_expressions; + p.should_fold_typescript_constant_expressions = true; + + // Create an assignment for each enum value + for (data.values) |*value| { + const name = value.name; + + var has_string_value = false; + if (value.value) |enum_value| { + next_numeric_value = null; + + const visited = p.visitExpr(enum_value); + + // "See through" any wrapped comments + const underlying_value = if (visited.data == .e_inlined_enum) + visited.data.e_inlined_enum.value + else + visited; + value.value = underlying_value; + + switch (underlying_value.data) { + .e_number => |num| { + exported_members.getPtr(name).?.data = .{ .enum_number = num.value }; + + p.ref_to_ts_namespace_member.put( + p.allocator, + value.ref, + .{ .enum_number = num.value }, + ) catch bun.outOfMemory(); + + next_numeric_value = num.value + 1.0; + }, + .e_string => |str| { + has_string_value = true; + + exported_members.getPtr(name).?.data = .{ .enum_string = str }; + + p.ref_to_ts_namespace_member.put( + p.allocator, + value.ref, + .{ .enum_string = str }, + ) catch bun.outOfMemory(); + }, + else => { + if (visited.knownPrimitive() == .string) { + has_string_value = true; + } + + if (!p.exprCanBeRemovedIfUnused(&visited)) { + all_values_are_pure = false; + } + }, + } + } else if (next_numeric_value) |num| { + value.value = p.newExpr(E.Number{ .value = num }, value.loc); + + next_numeric_value = num + 1; + + exported_members.getPtr(name).?.data = .{ .enum_number = num }; + + p.ref_to_ts_namespace_member.put( + p.allocator, + value.ref, + .{ .enum_number = num }, + ) catch bun.outOfMemory(); + } else { + value.value = p.newExpr(E.Undefined{}, value.loc); } - // Values without initializers are initialized to one more than the - // previous value if the previous value is numeric. Otherwise values - // without initializers are initialized to undefined. - var next_numeric_value: ?f64 = 0.0; + const is_assign_target = p.options.features.minify_syntax and bun.js_lexer.isIdentifier(value.name); - var value_exprs = ListManaged(Expr).initCapacity(allocator, data.values.len) catch bun.outOfMemory(); + const name_as_e_string = if (!is_assign_target or !has_string_value) + p.newExpr(value.nameAsEString(allocator), value.loc) + else + null; - var all_values_are_pure = true; + const assign_target = if (is_assign_target) + // "Enum.Name = value" + Expr.assign( + p.newExpr(E.Dot{ + .target = p.newExpr( + E.Identifier{ .ref = data.arg }, + value.loc, + ), + .name = value.name, + .name_loc = value.loc, + }, value.loc), + value.value.?, + ) + else + // "Enum['Name'] = value" + Expr.assign( + p.newExpr(E.Index{ + .target = p.newExpr( + E.Identifier{ .ref = data.arg }, + value.loc, + ), + .index = name_as_e_string.?, + }, value.loc), + value.value.?, + ); - const exported_members = p.current_scope.ts_namespace.?.exported_members; + p.recordUsage(data.arg); - // We normally don't fold numeric constants because they might increase code - // size, but it's important to fold numeric constants inside enums since - // that's what the TypeScript compiler does. - const old_should_fold_typescript_constant_expressions = p.should_fold_typescript_constant_expressions; - p.should_fold_typescript_constant_expressions = true; - - // Create an assignment for each enum value - for (data.values) |*value| { - const name = value.name; - - var has_string_value = false; - if (value.value) |enum_value| { - next_numeric_value = null; - - const visited = p.visitExpr(enum_value); - - // "See through" any wrapped comments - const underlying_value = if (visited.data == .e_inlined_enum) - visited.data.e_inlined_enum.value - else - visited; - value.value = underlying_value; - - switch (underlying_value.data) { - .e_number => |num| { - exported_members.getPtr(name).?.data = .{ .enum_number = num.value }; - - p.ref_to_ts_namespace_member.put( - p.allocator, - value.ref, - .{ .enum_number = num.value }, - ) catch bun.outOfMemory(); - - next_numeric_value = num.value + 1.0; - }, - .e_string => |str| { - has_string_value = true; - - exported_members.getPtr(name).?.data = .{ .enum_string = str }; - - p.ref_to_ts_namespace_member.put( - p.allocator, - value.ref, - .{ .enum_string = str }, - ) catch bun.outOfMemory(); - }, - else => { - if (visited.knownPrimitive() == .string) { - has_string_value = true; - } - - if (!p.exprCanBeRemovedIfUnused(&visited)) { - all_values_are_pure = false; - } - }, - } - } else if (next_numeric_value) |num| { - value.value = p.newExpr(E.Number{ .value = num }, value.loc); - - next_numeric_value = num + 1; - - exported_members.getPtr(name).?.data = .{ .enum_number = num }; - - p.ref_to_ts_namespace_member.put( - p.allocator, - value.ref, - .{ .enum_number = num }, - ) catch bun.outOfMemory(); - } else { - value.value = p.newExpr(E.Undefined{}, value.loc); - } - - const is_assign_target = p.options.features.minify_syntax and bun.js_lexer.isIdentifier(value.name); - - const name_as_e_string = if (!is_assign_target or !has_string_value) - p.newExpr(value.nameAsEString(allocator), value.loc) - else - null; - - const assign_target = if (is_assign_target) - // "Enum.Name = value" - Expr.assign( - p.newExpr(E.Dot{ - .target = p.newExpr( - E.Identifier{ .ref = data.arg }, - value.loc, - ), - .name = value.name, - .name_loc = value.loc, - }, value.loc), - value.value.?, - ) - else - // "Enum['Name'] = value" + // String-valued enums do not form a two-way map + if (has_string_value) { + value_exprs.append(assign_target) catch bun.outOfMemory(); + } else { + // "Enum[assignTarget] = 'Name'" + value_exprs.append( Expr.assign( p.newExpr(E.Index{ .target = p.newExpr( E.Identifier{ .ref = data.arg }, value.loc, ), - .index = name_as_e_string.?, + .index = assign_target, }, value.loc), - value.value.?, - ); - + name_as_e_string.?, + ), + ) catch bun.outOfMemory(); p.recordUsage(data.arg); - - // String-valued enums do not form a two-way map - if (has_string_value) { - value_exprs.append(assign_target) catch bun.outOfMemory(); - } else { - // "Enum[assignTarget] = 'Name'" - value_exprs.append( - Expr.assign( - p.newExpr(E.Index{ - .target = p.newExpr( - E.Identifier{ .ref = data.arg }, - value.loc, - ), - .index = assign_target, - }, value.loc), - name_as_e_string.?, - ), - ) catch bun.outOfMemory(); - p.recordUsage(data.arg); - } } + } - p.should_fold_typescript_constant_expressions = old_should_fold_typescript_constant_expressions; + p.should_fold_typescript_constant_expressions = old_should_fold_typescript_constant_expressions; - var value_stmts = ListManaged(Stmt).initCapacity(allocator, value_exprs.items.len) catch unreachable; - // Generate statements from expressions - for (value_exprs.items) |expr| { - value_stmts.appendAssumeCapacity(p.s(S.SExpr{ .value = expr }, expr.loc)); - } - value_exprs.deinit(); - try p.generateClosureForTypeScriptNamespaceOrEnum( - stmts, - stmt.loc, - data.is_export, - data.name.loc, - data.name.ref.?, - data.arg, - value_stmts.items, - all_values_are_pure, - ); - return; - }, - .s_namespace => |data| { - p.recordDeclaredSymbol(data.name.ref.?) catch unreachable; - - // Scan ahead for any variables inside this namespace. This must be done - // ahead of time before visiting any statements inside the namespace - // because we may end up visiting the uses before the declarations. - // We need to convert the uses into property accesses on the namespace. - for (data.stmts) |child_stmt| { - switch (child_stmt.data) { - .s_local => |local| { - if (local.is_export) { - p.markExportedDeclsInsideNamespace(data.arg, local.decls.slice()); - } - }, - else => {}, - } - } - - var prepend_temp_refs = PrependTempRefsOpts{ .kind = StmtsKind.fn_body }; - var prepend_list = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.stmts); - - const old_enclosing_namespace_arg_ref = p.enclosing_namespace_arg_ref; - p.enclosing_namespace_arg_ref = data.arg; - p.pushScopeForVisitPass(.entry, stmt.loc) catch unreachable; - p.recordDeclaredSymbol(data.arg) catch unreachable; - try p.visitStmtsAndPrependTempRefs(&prepend_list, &prepend_temp_refs); - p.popScope(); - p.enclosing_namespace_arg_ref = old_enclosing_namespace_arg_ref; - - try p.generateClosureForTypeScriptNamespaceOrEnum( - stmts, - stmt.loc, - data.is_export, - data.name.loc, - data.name.ref.?, - data.arg, - prepend_list.items, - false, - ); - return; - }, - else => { - notimpl(); - }, + var value_stmts = ListManaged(Stmt).initCapacity(allocator, value_exprs.items.len) catch unreachable; + // Generate statements from expressions + for (value_exprs.items) |expr| { + value_stmts.appendAssumeCapacity(p.s(S.SExpr{ .value = expr }, expr.loc)); + } + value_exprs.deinit(); + try p.generateClosureForTypeScriptNamespaceOrEnum( + stmts, + stmt.loc, + data.is_export, + data.name.loc, + data.name.ref.?, + data.arg, + value_stmts.items, + all_values_are_pure, + ); + return; } + pub fn s_namespace(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt, data: *S.Namespace) !void { + p.recordDeclaredSymbol(data.name.ref.?) catch unreachable; - // if we get this far, it stays - try stmts.append(stmt.*); - } + // Scan ahead for any variables inside this namespace. This must be done + // ahead of time before visiting any statements inside the namespace + // because we may end up visiting the uses before the declarations. + // We need to convert the uses into property accesses on the namespace. + for (data.stmts) |child_stmt| { + switch (child_stmt.data) { + .s_local => |local| { + if (local.is_export) { + p.markExportedDeclsInsideNamespace(data.arg, local.decls.slice()); + } + }, + else => {}, + } + } + + var prepend_temp_refs = PrependTempRefsOpts{ .kind = StmtsKind.fn_body }; + var prepend_list = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.stmts); + + const old_enclosing_namespace_arg_ref = p.enclosing_namespace_arg_ref; + p.enclosing_namespace_arg_ref = data.arg; + p.pushScopeForVisitPass(.entry, stmt.loc) catch unreachable; + p.recordDeclaredSymbol(data.arg) catch unreachable; + try p.visitStmtsAndPrependTempRefs(&prepend_list, &prepend_temp_refs); + p.popScope(); + p.enclosing_namespace_arg_ref = old_enclosing_namespace_arg_ref; + + try p.generateClosureForTypeScriptNamespaceOrEnum( + stmts, + stmt.loc, + data.is_export, + data.name.loc, + data.name.ref.?, + data.arg, + prepend_list.items, + false, + ); + return; + } + }; fn isExportToEliminate(p: *P, ref: Ref) bool { const symbol_name = p.loadNameFromRef(ref); @@ -21612,20 +21721,24 @@ fn NewParser_( return res; } + fn visitSingleStmtBlock(p: *P, stmt: Stmt, kind: StmtsKind) Stmt { + var new_stmt = stmt; + p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; + var stmts = ListManaged(Stmt).initCapacity(p.allocator, stmt.data.s_block.stmts.len) catch unreachable; + stmts.appendSlice(stmt.data.s_block.stmts) catch unreachable; + p.visitStmts(&stmts, kind) catch unreachable; + p.popScope(); + new_stmt.data.s_block.stmts = stmts.items; + if (p.options.features.minify_syntax) { + new_stmt = p.stmtsToSingleStmt(stmt.loc, stmts.items); + } + + return new_stmt; + } + fn visitSingleStmt(p: *P, stmt: Stmt, kind: StmtsKind) Stmt { if (stmt.data == .s_block) { - var new_stmt = stmt; - p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; - var stmts = ListManaged(Stmt).initCapacity(p.allocator, stmt.data.s_block.stmts.len) catch unreachable; - stmts.appendSlice(stmt.data.s_block.stmts) catch unreachable; - p.visitStmts(&stmts, kind) catch unreachable; - p.popScope(); - new_stmt.data.s_block.stmts = stmts.items; - if (p.options.features.minify_syntax) { - new_stmt = p.stmtsToSingleStmt(stmt.loc, stmts.items); - } - - return new_stmt; + return p.visitSingleStmtBlock(stmt, kind); } const has_if_scope = switch (stmt.data) { diff --git a/src/js_printer.zig b/src/js_printer.zig index 2963b96e65..3116a92532 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -6003,13 +6003,13 @@ pub fn printWithWriterAndPlatform( printer.printFnArgs(func.open_parens_loc, func.args, func.flags.contains(.has_rest_arg), false); printer.printSpace(); printer.print("{\n"); - if (func.body.stmts[0].data.s_lazy_export != .e_undefined) { + if (func.body.stmts[0].data.s_lazy_export.* != .e_undefined) { printer.indent(); printer.printIndent(); printer.printSymbol(printer.options.commonjs_module_ref); printer.print(".exports = "); printer.printExpr(.{ - .data = func.body.stmts[0].data.s_lazy_export, + .data = func.body.stmts[0].data.s_lazy_export.*, .loc = func.body.stmts[0].loc, }, .comma, .{}); printer.print("; // bun .s_lazy_export\n"); From 145a7fd92ec42762c5586eb81c5fa6b2a7e3a12a Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 25 Dec 2024 23:02:46 -0800 Subject: [PATCH 097/125] Better unicode identifier start / continue check (#15455) --- misctools/gen-unicode-table.js | 172 --- misctools/gen-unicode-table.ts | 108 ++ misctools/package.json | 5 +- misctools/unicode-generator.ts | 138 ++ src/js_lexer.zig | 12 +- src/js_lexer/identifier.zig | 2082 +---------------------------- src/js_lexer/identifier_cache.zig | 22 - src/js_lexer/identifier_data.zig | 178 --- 8 files changed, 320 insertions(+), 2397 deletions(-) delete mode 100644 misctools/gen-unicode-table.js create mode 100644 misctools/gen-unicode-table.ts create mode 100644 misctools/unicode-generator.ts delete mode 100644 src/js_lexer/identifier_cache.zig delete mode 100644 src/js_lexer/identifier_data.zig diff --git a/misctools/gen-unicode-table.js b/misctools/gen-unicode-table.js deleted file mode 100644 index 1696a4b9e8..0000000000 --- a/misctools/gen-unicode-table.js +++ /dev/null @@ -1,172 +0,0 @@ -// Thank you @evanw for this code!!! -const fs = require("fs"); -const path = require("path"); - -// ES5 reference: https://es5.github.io/ -// -// A conforming implementation of this International standard shall interpret -// characters in conformance with the Unicode Standard, Version 3.0 or later -// and ISO/IEC 10646-1 with either UCS-2 or UTF-16 as the adopted encoding -// form, implementation level 3. If the adopted ISO/IEC 10646-1 subset is not -// otherwise specified, it is presumed to be the BMP subset, collection 300. -// -// UnicodeLetter: any character in the Unicode categories “Uppercase letter (Lu)”, -// “Lowercase letter (Ll)”, “Titlecase letter (Lt)”, “Modifier letter (Lm)”, -// “Other letter (Lo)”, or “Letter number (Nl)”. -const idStartES5 = [] - .concat( - require("@unicode/unicode-3.0.0/General_Category/Uppercase_Letter/code-points"), - require("@unicode/unicode-3.0.0/General_Category/Lowercase_Letter/code-points"), - require("@unicode/unicode-3.0.0/General_Category/Titlecase_Letter/code-points"), - require("@unicode/unicode-3.0.0/General_Category/Modifier_Letter/code-points"), - require("@unicode/unicode-3.0.0/General_Category/Other_Letter/code-points"), - - // The "letter number" category is not included because old versions of Safari - // had a bug where they didn't include it. This means it does not match ES5. - // We need to make sure we escape these characters so Safari can read them. - // See https://github.com/evanw/esbuild/issues/1349 for more information. - // require('@unicode/unicode-3.0.0/General_Category/Letter_Number/code-points'), - ) - .sort((a, b) => a - b); - -// UnicodeCombiningMark: any character in the Unicode categories “Non-spacing mark (Mn)” -// or “Combining spacing mark (Mc)” -// UnicodeDigit: any character in the Unicode category “Decimal number (Nd)” -// UnicodeConnectorPunctuation: any character in the Unicode category “Connector punctuation (Pc)” -const idContinueES5 = idStartES5 - .concat( - require("@unicode/unicode-3.0.0/General_Category/Nonspacing_Mark/code-points"), - require("@unicode/unicode-3.0.0/General_Category/Spacing_Mark/code-points"), - require("@unicode/unicode-3.0.0/General_Category/Decimal_Number/code-points"), - require("@unicode/unicode-3.0.0/General_Category/Connector_Punctuation/code-points"), - ) - .sort((a, b) => a - b); - -// ESNext reference: https://tc39.es/ecma262/ -// -// A conforming implementation of ECMAScript must interpret source text input -// in conformance with the Unicode Standard, Version 5.1.0 or later and ISO/IEC -// 10646. If the adopted ISO/IEC 10646-1 subset is not otherwise specified, it -// is presumed to be the Unicode set, collection 10646. -// -// UnicodeIDStart: any Unicode code point with the Unicode property “ID_Start” -const idStartESNext = require("@unicode/unicode-13.0.0/Binary_Property/ID_Start/code-points"); -const idStartESNextSet = new Set(idStartESNext); - -// UnicodeIDContinue: any Unicode code point with the Unicode property “ID_Continue” -const idContinueESNext = require("@unicode/unicode-13.0.0/Binary_Property/ID_Continue/code-points"); -const idContinueESNextSet = new Set(idContinueESNext); - -// These identifiers are valid in both ES5 and ES6+ (i.e. an intersection of both) -const idStartES5AndESNext = idStartES5.filter(n => idStartESNextSet.has(n)); -const idContinueES5AndESNext = idContinueES5.filter(n => idContinueESNextSet.has(n)); - -// These identifiers are valid in either ES5 or ES6+ (i.e. a union of both) -const idStartES5OrESNext = [...new Set(idStartES5.concat(idStartESNext))].sort((a, b) => a - b); -const idContinueES5OrESNext = [...new Set(idContinueES5.concat(idContinueESNext))].sort((a, b) => a - b); - -function generateRangeTable(codePoints) { - let lines = []; - let index = 0; - let latinOffset = 0; - - while (latinOffset < codePoints.length && codePoints[latinOffset] <= 0xff) { - latinOffset++; - } - - lines.push(`RangeTable.init(`, ` ${latinOffset},`, ` &[_]R16Range{`); - - // 16-bit code points - while (index < codePoints.length && codePoints[index] < 0x1000) { - let start = codePoints[index]; - index++; - while (index < codePoints.length && codePoints[index] < 0x1000 && codePoints[index] === codePoints[index - 1] + 1) { - index++; - } - let end = codePoints[index - 1]; - lines.push(` .{0x${start.toString(16)}, 0x${end.toString(16)}},`); - } - - lines.push(` },`, `&[_]R32Range{`); - - // 32-bit code points - while (index < codePoints.length) { - let start = codePoints[index]; - index++; - while (index < codePoints.length && codePoints[index] === codePoints[index - 1] + 1) { - index++; - } - let end = codePoints[index - 1]; - lines.push(` .{0x${start.toString(16)}, 0x${end.toString(16)}},`); - } - - lines.push(` },`, `);`); - return lines.join("\n"); -} - -function generateBigSwitchStatement(codePoints) { - let lines = []; - let index = 0; - let latinOffset = 0; - - while (latinOffset < codePoints.length && codePoints[latinOffset] <= 0xff) { - latinOffset++; - } - - lines.push(`return switch(codepoint) {`); - - // 16-bit code points - while (index < codePoints.length && codePoints[index] < 0x1000) { - let start = codePoints[index]; - index++; - while (index < codePoints.length && codePoints[index] < 0x1000 && codePoints[index] === codePoints[index - 1] + 1) { - index++; - } - let end = codePoints[index - 1]; - lines.push(`0x${start.toString(16)}...0x${end.toString(16)},`); - } - - // 32-bit code points - while (index < codePoints.length) { - let start = codePoints[index]; - index++; - while (index < codePoints.length && codePoints[index] === codePoints[index - 1] + 1) { - index++; - } - let end = codePoints[index - 1]; - lines.push(` 0x${start.toString(16)}...0x${end.toString(16)},`); - } - - lines.push(` => true, - else => false -};`); - return lines.join("\n"); -} - -fs.writeFileSync( - path.join(__dirname, "..", "src", "js_lexer", "unicode.zig"), - `// This file was automatically generated by ${path.basename(__filename)}. Do not edit. - - const RangeTable = @import("./range_table.zig"); - - -// ES5 || ESNext -pub const id_start = ${generateRangeTable(idStartES5OrESNext)} - -// ES5 || ESNext -pub const id_continue = ${generateRangeTable(idContinueES5OrESNext)} - -pub const printable_id_start = ${generateRangeTable(idStartESNext)} -pub const printable_id_continue = ${generateRangeTable(idContinueESNext)} - -pub fn isIdentifierStart(comptime Codepoint: type, codepoint: Codepoint) bool{ - ${generateBigSwitchStatement(idStartES5OrESNext)} -} - -pub fn isIdentifierContinue(comptime Codepoint: type, codepoint: Codepoint) bool{ - ${generateBigSwitchStatement(idContinueES5OrESNext)} -} - - -`, -); diff --git a/misctools/gen-unicode-table.ts b/misctools/gen-unicode-table.ts new file mode 100644 index 0000000000..5bf5d9dead --- /dev/null +++ b/misctools/gen-unicode-table.ts @@ -0,0 +1,108 @@ +import { Generator, Context } from "./unicode-generator"; + +// Create sets for fast lookups +const idStartES5Set = new Set([ + ...require("@unicode/unicode-3.0.0/General_Category/Uppercase_Letter/code-points"), + ...require("@unicode/unicode-3.0.0/General_Category/Lowercase_Letter/code-points"), + ...require("@unicode/unicode-3.0.0/General_Category/Titlecase_Letter/code-points"), + ...require("@unicode/unicode-3.0.0/General_Category/Modifier_Letter/code-points"), + ...require("@unicode/unicode-3.0.0/General_Category/Other_Letter/code-points"), +]); + +const idContinueES5Set = new Set([ + ...idStartES5Set, + ...require("@unicode/unicode-3.0.0/General_Category/Nonspacing_Mark/code-points"), + ...require("@unicode/unicode-3.0.0/General_Category/Spacing_Mark/code-points"), + ...require("@unicode/unicode-3.0.0/General_Category/Decimal_Number/code-points"), + ...require("@unicode/unicode-3.0.0/General_Category/Connector_Punctuation/code-points"), +]); + +const idStartESNextSet = new Set(require("@unicode/unicode-15.1.0/Binary_Property/ID_Start/code-points")); +const idContinueESNextSet = new Set(require("@unicode/unicode-15.1.0/Binary_Property/ID_Continue/code-points")); + +// Exclude known problematic codepoints +const ID_Continue_mistake = new Set([0x30fb, 0xff65]); + +function bitsToU64Array(bits: number[]): bigint[] { + const result: bigint[] = []; + for (let i = 0; i < bits.length; i += 64) { + let value = 0n; + for (let j = 0; j < 64 && i + j < bits.length; j++) { + if (bits[i + j]) { + value |= 1n << BigInt(j); + } + } + result.push(value); + } + return result; +} + +async function generateTable(table: string, name: string, checkFn: (cp: number) => boolean) { + const context: Context = { + get: (cp: number) => checkFn(cp), + eql: (a: boolean, b: boolean) => a === b, + }; + + const generator = new Generator(context); + const tables = await generator.generate(); + + return ` +pub fn ${name}(cp: u21) bool { + if (cp > 0x10FFFF) return false; + const high = cp >> 8; + const low = cp & 0xFF; + const stage2_idx = ${table}.stage1[high]; + const bit_pos = stage2_idx + low; + const u64_idx = bit_pos >> 6; + const bit_idx = @as(u6, @intCast(bit_pos & 63)); + return (${table}.stage2[u64_idx] & (@as(u64, 1) << bit_idx)) != 0; +} +const ${table} = struct { + pub const stage1 = [_]u16{${tables.stage1.join(",")}}; + pub const stage2 = [_]u64{${bitsToU64Array(tables.stage2) + .map(n => n.toString()) + .join(",")}}; +}; + +`; +} + +async function main() { + const functions = [ + { + name: "isIDStartES5", + table: "idStartES5", + check: (cp: number) => idStartES5Set.has(cp), + }, + { + name: "isIDContinueES5", + table: "idContinueES5", + check: (cp: number) => idContinueES5Set.has(cp), + }, + { + name: "isIDStartESNext", + table: "idStartESNext", + check: (cp: number) => idStartESNextSet.has(cp), + }, + { + name: "isIDContinueESNext", + table: "idContinueESNext", + check: (cp: number) => idContinueESNextSet.has(cp) && !ID_Continue_mistake.has(cp), + }, + ]; + + const results = await Promise.all( + functions.map(async ({ name, check, table }) => { + const code = await generateTable(table, name, check); + return ` +/// ${name} checks if a codepoint is valid in the ${name} category +${code}`; + }), + ); + + console.log(`/// This file is auto-generated. Do not edit. + +${results.join("\n\n")}`); +} + +main(); diff --git a/misctools/package.json b/misctools/package.json index 18a85e85e4..725cff6ac3 100644 --- a/misctools/package.json +++ b/misctools/package.json @@ -5,7 +5,10 @@ "license": "MIT", "devDependencies": { "@unicode/unicode-13.0.0": "^1.2.1", - "@unicode/unicode-3.0.0": "^1.2.1", + "@unicode/unicode-3.0.0": "^1.6.5", "semver": "^7.3.7" + }, + "dependencies": { + "@unicode/unicode-15.1.0": "^1.6.5" } } \ No newline at end of file diff --git a/misctools/unicode-generator.ts b/misctools/unicode-generator.ts new file mode 100644 index 0000000000..5d4260e500 --- /dev/null +++ b/misctools/unicode-generator.ts @@ -0,0 +1,138 @@ +import crypto from "crypto"; + +// Types to mirror Zig's structures +interface Context { + get(codepoint: number): Promise | Elem; + eql(a: Elem, b: Elem): boolean; +} + +interface Tables { + stage1: number[]; + stage2: number[]; + stage3: Elem[]; +} + +class Generator { + private static readonly BLOCK_SIZE = 256; + private readonly ctx: Context; + private readonly blockMap = new Map(); + + constructor(ctx: Context) { + this.ctx = ctx; + } + + private hashBlock(block: number[]): string { + const hash = crypto.createHash("sha256"); + hash.update(Buffer.from(new Uint16Array(block).buffer)); + return hash.digest("hex"); + } + + async generate(): Promise> { + const stage1: number[] = []; + const stage2: number[] = []; + const stage3: Elem[] = []; + + let block = new Array(Generator.BLOCK_SIZE).fill(0); + let blockLen = 0; + + // Maximum Unicode codepoint is 0x10FFFF + for (let cp = 0; cp <= 0x10ffff; cp++) { + // Get the mapping for this codepoint + const elem = await this.ctx.get(cp); + + // Find or add the element in stage3 + let blockIdx = stage3.findIndex(item => this.ctx.eql(item, elem)); + if (blockIdx === -1) { + blockIdx = stage3.length; + stage3.push(elem); + } + + if (blockIdx > 0xffff) { + throw new Error("Block index too large"); + } + + // Add to current block + block[blockLen] = blockIdx; + blockLen++; + + // Check if we need to finalize this block + if (blockLen < Generator.BLOCK_SIZE && cp !== 0x10ffff) { + continue; + } + + // Fill remaining block space with zeros if needed + if (blockLen < Generator.BLOCK_SIZE) { + block.fill(0, blockLen); + } + + // Get or create stage2 index for this block + const blockHash = this.hashBlock(block); + let stage2Idx = this.blockMap.get(blockHash); + + if (stage2Idx === undefined) { + stage2Idx = stage2.length; + this.blockMap.set(blockHash, stage2Idx); + stage2.push(...block.slice(0, blockLen)); + } + + if (stage2Idx > 0xffff) { + throw new Error("Stage2 index too large"); + } + + // Add mapping to stage1 + stage1.push(stage2Idx); + + // Reset block + block = new Array(Generator.BLOCK_SIZE).fill(0); + blockLen = 0; + } + + return { stage1, stage2, stage3 }; + } + + // Generates Zig code for the lookup tables + static writeZig(tableName: string, tables: Tables, elemToString: (elem: Elem) => string): string { + let output = `/// Auto-generated. Do not edit.\n`; + output += `fn ${tableName}(comptime Elem: type) type {\n`; + output += " return struct {\n"; + + // Stage 1 + output += `pub const stage1: [${tables.stage1.length}]u16 = .{`; + output += tables.stage1.join(","); + output += "};\n\n"; + + // Stage 2 + output += `pub const stage2: [${tables.stage2.length}]u8 = .{`; + output += tables.stage2.join(","); + output += "};\n\n"; + + // Stage 3 + output += `pub const stage3: [${tables.stage3.length}]Elem = .{`; + output += tables.stage3.map(elemToString).join(","); + output += "};\n"; + + output += " };\n}\n"; + return output; + } +} + +// Example usage: +async function example() { + // Example context that maps codepoints to their category + const ctx: Context = { + get: async (cp: number) => { + // This would normally look up the actual Unicode category + return "Lu"; + }, + eql: (a: string, b: string) => a === b, + }; + + const generator = new Generator(ctx); + const tables = await generator.generate(); + + // Generate Zig code + const zigCode = Generator.writeZig(tables, (elem: string) => `"${elem}"`); + console.log(zigCode); +} + +export { Generator, type Context, type Tables }; diff --git a/src/js_lexer.zig b/src/js_lexer.zig index a052e9ef05..1560f02621 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -3043,18 +3043,10 @@ pub const Lexer = NewLexer(.{}); const JSIdentifier = @import("./js_lexer/identifier.zig"); pub inline fn isIdentifierStart(codepoint: i32) bool { - if (comptime Environment.isWasm) { - return JSIdentifier.JumpTable.isIdentifierStart(codepoint); - } - - return JSIdentifier.Bitset.isIdentifierStart(codepoint); + return JSIdentifier.isIdentifierStart(codepoint); } pub inline fn isIdentifierContinue(codepoint: i32) bool { - if (comptime Environment.isWasm) { - return JSIdentifier.JumpTable.isIdentifierPart(codepoint); - } - - return JSIdentifier.Bitset.isIdentifierPart(codepoint); + return JSIdentifier.isIdentifierPart(codepoint); } pub fn isWhitespace(codepoint: CodePoint) bool { diff --git a/src/js_lexer/identifier.zig b/src/js_lexer/identifier.zig index b8da1da65f..6df764bb72 100644 --- a/src/js_lexer/identifier.zig +++ b/src/js_lexer/identifier.zig @@ -1,2024 +1,78 @@ -// This file benchmarks different approaches for determinig whether or not a unicode codepoint is possibly a JS identifier -// these values are copy-pasted from "typescript/lib/typescriptServices.js" const std = @import("std"); -pub const SerializedBitset = extern struct {}; -pub const Bitset = struct { - const Cache = @import("identifier_cache.zig"); - const id_start_range: [2]i32 = Cache.id_start_meta.range; - const id_end_range: [2]i32 = Cache.id_continue_meta.range; - // this is a pointer because otherwise it may be copied onto the stack - // and it's a huge bitset - const id_start = &Cache.id_start; - // this is a pointer because otherwise it may be copied onto the stack - // and it's a huge bitset - const id_continue = &Cache.id_continue; +pub fn isIdentifierStart(codepoint: i32) bool { + return switch (codepoint) { + 'a'...'z', 'A'...'Z', '_', '$' => true, + std.math.minInt(i32)...0, 0x10FFFF...std.math.maxInt(i32) => false, + else => isIDStartESNext(@intCast(codepoint)), + }; +} - pub fn init() void {} +pub fn isIdentifierPart(codepoint: i32) bool { + return switch (codepoint) { + 'a'...'z', 'A'...'Z', '0'...'9', '_', '$' => true, + std.math.minInt(i32)...0, 0x10FFFF...std.math.maxInt(i32) => false, + else => isIDContinueESNext(@intCast(codepoint)), + }; +} - pub fn isIdentifierStart(codepoint: i32) bool { - return codepoint >= (comptime id_start_range[0]) and - codepoint <= (comptime id_start_range[1]) and - id_start.isSet((comptime @as(usize, @intCast(id_start_range[1]))) - @as( - usize, - @intCast(codepoint), - )); - } - - pub fn isIdentifierPart(codepoint: i32) bool { - return codepoint >= (comptime id_end_range[0]) and - codepoint <= (comptime id_end_range[1]) and - id_continue.isSet( - (comptime @as(usize, @intCast(id_end_range[1]))) - @as( - usize, - @intCast(codepoint), - ), - ); - } +/// This file is auto-generated. Do not edit. +/// isIDStartES5 checks if a codepoint is valid in the isIDStartES5 category +pub fn isIDStartES5(cp: u21) bool { + const high = cp >> 8; + const low = cp & 0xFF; + const stage2_idx = idStartES5.stage1[high]; + const bit_pos = stage2_idx + low; + const u64_idx = bit_pos >> 6; + const bit_idx = @as(u6, @intCast(bit_pos & 63)); + return (idStartES5.stage2[u64_idx] & (@as(u64, 1) << bit_idx)) != 0; +} +const idStartES5 = struct { + pub const stage1 = [_]u16{ 0, 256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, 4096, 4352, 4608, 4864, 5120, 256, 5376, 5632, 5888, 2048, 2048, 2048, 2048, 2048, 6144, 6400, 6656, 6912, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 7168, 7424, 2048, 2048, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 7680, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 7936, 256, 256, 256, 256, 8192, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 8448, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 256, 8704, 8960, 256, 9216, 9472, 9728, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048 }; + pub const stage2 = [_]u64{ 0, 576460743847706622, 297241973452963840, 18410715276682199039, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 4503586742468607, 18446744073709486080, 18014187403249451007, 70501888360451, 0, 288230376151711744, 18446744056529672000, 4503599577006079, 18446744073709551615, 18446744073709551615, 18446744073709547523, 234187180623206815, 18446181123756130304, 18446744065161560063, 255, 1979120929931264, 576460743713488896, 18446181123756132351, 18446744073709551615, 2017613045381988351, 35184371892224, 0, 274877906943, 0, 0, 0, 0, 0, 2594073385365405664, 17163157504, 271902628478820320, 844440767823872, 247132830528276448, 7881300924956672, 2589004636761075680, 4295032832, 2579997437506199520, 15837691904, 270153412153034720, 0, 283724577500946400, 12884901888, 283724577500946400, 13958643712, 288228177128316896, 12884901888, 3457638613854978016, 127, 3940649673949182, 127, 2309762420256548246, 805306463, 1, 8796093021951, 3840, 0, 7679401525247, 4128768, 18446744069414584320, 36028797018898495, 18446744073709551615, 18446744071629176831, 18446743008557662207, 288230376151711743, 18446744073709551487, 18446744070446333311, 9168625153884503423, 18446603336212774717, 18446744071549321215, 134217599, 18446744069414584320, 9007199254740991, 18446744073709551614, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 35923243902697471, 18446744069548802046, 8796093022207, 0, 0, 4503599627370495, 0, 18446744069414584320, 72057594037927935, 2199023255551, 0, 18446744073709551615, 18446744073709551615, 18446744069683019775, 288230376151711743, 18446744070475743231, 4611686017001275199, 6908521828386340863, 2295745090394464220, 0, 9223372036854775808, 0, 0, 287031153606524036, 0, 0, 0, 17451448556060768, 18446744073709551614, 18446744066732326911, 8646911284551352319, 18446216308128219104, 18446744073709551615, 72057589742993407, 0, 18446744073709551615, 18446744073709551615, 18014398509481983, 0, 18446744073709551615, 18446744073709551615, 274877906943, 0, 18446744073709551615, 18446744073709551615, 8191, 0, 18446744073709551615, 18446744073709551615, 68719476735, 0, 70368744177663, 0, 0, 0, 6881498030004502655, 18446744073709551579, 1125899906842623, 18446744073709027328, 4611686018427387903, 18446744073709486080, 18446744073709355007, 1152640029630136575, 0, 18435203599664414720, 18446744073709551615, 2305843009213693951, 576460743713488896, 18446743798965862398, 9223372036854775807, 486341884 }; }; -/// In WASM, we use the JumpTable version -pub const JumpTable = struct { - const minInt = @import("std").math.minInt; - const maxInt = @import("std").math.maxInt; - const max_codepoint = 0x10FFFF; - noinline fn isIdentifierPartSlow(codepoint: i32) bool { - @setCold(true); - return switch (codepoint) { - // explicitly tell LLVM's optimizer about values we know will not be in the range of this switch statement - 0xaa...0xffd7 => isIdentifierPartSlow16(@as(u16, @intCast(codepoint))), - (0xffd7 + 1)...0xe01ef => isIdentifierPartSlow32(codepoint), - - else => false, - }; - } - - fn isIdentifierPartSlow16(codepoint: u16) bool { - return switch (codepoint) { - minInt(u16)...(0xaa - 1) => unreachable, - 0xaa...0xaa, 0xb5...0xb5, 0xb7...0xb7, 0xba...0xba, 0xc0...0xd6, 0xd8...0xf6, 0xf8...0x2c1, 0x2c6...0x2d1, 0x2e0...0x2e4, 0x2ec...0x2ec, 0x2ee...0x2ee, 0x300...0x374, 0x376...0x377, 0x37a...0x37d, 0x37f...0x37f, 0x386...0x38a, 0x38c...0x38c, 0x38e...0x3a1, 0x3a3...0x3f5, 0x3f7...0x481, 0x483...0x487, 0x48a...0x52f, 0x531...0x556, 0x559...0x559, 0x560...0x588, 0x591...0x5bd, 0x5bf...0x5bf, 0x5c1...0x5c2, 0x5c4...0x5c5, 0x5c7...0x5c7, 0x5d0...0x5ea, 0x5ef...0x5f2, 0x610...0x61a, 0x620...0x669, 0x66e...0x6d3, 0x6d5...0x6dc, 0x6df...0x6e8, 0x6ea...0x6fc, 0x6ff...0x6ff, 0x710...0x74a, 0x74d...0x7b1, 0x7c0...0x7f5, 0x7fa...0x7fa, 0x7fd...0x7fd, 0x800...0x82d, 0x840...0x85b, 0x860...0x86a, 0x8a0...0x8b4, 0x8b6...0x8c7, 0x8d3...0x8e1, 0x8e3...0x963, 0x966...0x96f, 0x971...0x983, 0x985...0x98c, 0x98f...0x990, 0x993...0x9a8, 0x9aa...0x9b0, 0x9b2...0x9b2, 0x9b6...0x9b9, 0x9bc...0x9c4, 0x9c7...0x9c8, 0x9cb...0x9ce, 0x9d7...0x9d7, 0x9dc...0x9dd, 0x9df...0x9e3, 0x9e6...0x9f1, 0x9fc...0x9fc, 0x9fe...0x9fe, 0xa01...0xa03, 0xa05...0xa0a, 0xa0f...0xa10, 0xa13...0xa28, 0xa2a...0xa30, 0xa32...0xa33, 0xa35...0xa36, 0xa38...0xa39, 0xa3c...0xa3c, 0xa3e...0xa42, 0xa47...0xa48, 0xa4b...0xa4d, 0xa51...0xa51, 0xa59...0xa5c, 0xa5e...0xa5e, 0xa66...0xa75, 0xa81...0xa83, 0xa85...0xa8d, 0xa8f...0xa91, 0xa93...0xaa8, 0xaaa...0xab0, 0xab2...0xab3, 0xab5...0xab9, 0xabc...0xac5, 0xac7...0xac9, 0xacb...0xacd, 0xad0...0xad0, 0xae0...0xae3, 0xae6...0xaef, 0xaf9...0xaff, 0xb01...0xb03, 0xb05...0xb0c, 0xb0f...0xb10, 0xb13...0xb28, 0xb2a...0xb30, 0xb32...0xb33, 0xb35...0xb39, 0xb3c...0xb44, 0xb47...0xb48, 0xb4b...0xb4d, 0xb55...0xb57, 0xb5c...0xb5d, 0xb5f...0xb63, 0xb66...0xb6f, 0xb71...0xb71, 0xb82...0xb83, 0xb85...0xb8a, 0xb8e...0xb90, 0xb92...0xb95, 0xb99...0xb9a, 0xb9c...0xb9c, 0xb9e...0xb9f, 0xba3...0xba4, 0xba8...0xbaa, 0xbae...0xbb9, 0xbbe...0xbc2, 0xbc6...0xbc8, 0xbca...0xbcd, 0xbd0...0xbd0, 0xbd7...0xbd7, 0xbe6...0xbef, 0xc00...0xc0c, 0xc0e...0xc10, 0xc12...0xc28, 0xc2a...0xc39, 0xc3d...0xc44, 0xc46...0xc48, 0xc4a...0xc4d, 0xc55...0xc56, 0xc58...0xc5a, 0xc60...0xc63, 0xc66...0xc6f, 0xc80...0xc83, 0xc85...0xc8c, 0xc8e...0xc90, 0xc92...0xca8, 0xcaa...0xcb3, 0xcb5...0xcb9, 0xcbc...0xcc4, 0xcc6...0xcc8, 0xcca...0xccd, 0xcd5...0xcd6, 0xcde...0xcde, 0xce0...0xce3, 0xce6...0xcef, 0xcf1...0xcf2, 0xd00...0xd0c, 0xd0e...0xd10, 0xd12...0xd44, 0xd46...0xd48, 0xd4a...0xd4e, 0xd54...0xd57, 0xd5f...0xd63, 0xd66...0xd6f, 0xd7a...0xd7f, 0xd81...0xd83, 0xd85...0xd96, 0xd9a...0xdb1, 0xdb3...0xdbb, 0xdbd...0xdbd, 0xdc0...0xdc6, 0xdca...0xdca, 0xdcf...0xdd4, 0xdd6...0xdd6, 0xdd8...0xddf, 0xde6...0xdef, 0xdf2...0xdf3, 0xe01...0xe3a, 0xe40...0xe4e, 0xe50...0xe59, 0xe81...0xe82, 0xe84...0xe84, 0xe86...0xe8a, 0xe8c...0xea3, 0xea5...0xea5, 0xea7...0xebd, 0xec0...0xec4, 0xec6...0xec6, 0xec8...0xecd, 0xed0...0xed9, 0xedc...0xedf, 0xf00...0xf00, 0xf18...0xf19, 0xf20...0xf29, 0xf35...0xf35, 0xf37...0xf37, 0xf39...0xf39, 0xf3e...0xf47, 0xf49...0xf6c, 0xf71...0xf84, 0xf86...0xf97, 0xf99...0xfbc, 0xfc6...0xfc6, 0x1000...0x1049, 0x1050...0x109d, 0x10a0...0x10c5, 0x10c7...0x10c7, 0x10cd...0x10cd, 0x10d0...0x10fa, 0x10fc...0x1248, 0x124a...0x124d, 0x1250...0x1256, 0x1258...0x1258, 0x125a...0x125d, 0x1260...0x1288, 0x128a...0x128d, 0x1290...0x12b0, 0x12b2...0x12b5, 0x12b8...0x12be, 0x12c0...0x12c0, 0x12c2...0x12c5, 0x12c8...0x12d6, 0x12d8...0x1310, 0x1312...0x1315, 0x1318...0x135a, 0x135d...0x135f, 0x1369...0x1371, 0x1380...0x138f, 0x13a0...0x13f5, 0x13f8...0x13fd, 0x1401...0x166c, 0x166f...0x167f, 0x1681...0x169a, 0x16a0...0x16ea, 0x16ee...0x16f8, 0x1700...0x170c, 0x170e...0x1714, 0x1720...0x1734, 0x1740...0x1753, 0x1760...0x176c, 0x176e...0x1770, 0x1772...0x1773, 0x1780...0x17d3, 0x17d7...0x17d7, 0x17dc...0x17dd, 0x17e0...0x17e9, 0x180b...0x180d, 0x1810...0x1819, 0x1820...0x1878, 0x1880...0x18aa, 0x18b0...0x18f5, 0x1900...0x191e, 0x1920...0x192b, 0x1930...0x193b, 0x1946...0x196d, 0x1970...0x1974, 0x1980...0x19ab, 0x19b0...0x19c9, 0x19d0...0x19da, 0x1a00...0x1a1b, 0x1a20...0x1a5e, 0x1a60...0x1a7c, 0x1a7f...0x1a89, 0x1a90...0x1a99, 0x1aa7...0x1aa7, 0x1ab0...0x1abd, 0x1abf...0x1ac0, 0x1b00...0x1b4b, 0x1b50...0x1b59, 0x1b6b...0x1b73, 0x1b80...0x1bf3, 0x1c00...0x1c37, 0x1c40...0x1c49, 0x1c4d...0x1c7d, 0x1c80...0x1c88, 0x1c90...0x1cba, 0x1cbd...0x1cbf, 0x1cd0...0x1cd2, 0x1cd4...0x1cfa, 0x1d00...0x1df9, 0x1dfb...0x1f15, 0x1f18...0x1f1d, 0x1f20...0x1f45, 0x1f48...0x1f4d, 0x1f50...0x1f57, 0x1f59...0x1f59, 0x1f5b...0x1f5b, 0x1f5d...0x1f5d, 0x1f5f...0x1f7d, 0x1f80...0x1fb4, 0x1fb6...0x1fbc, 0x1fbe...0x1fbe, 0x1fc2...0x1fc4, 0x1fc6...0x1fcc, 0x1fd0...0x1fd3, 0x1fd6...0x1fdb, 0x1fe0...0x1fec, 0x1ff2...0x1ff4, 0x1ff6...0x1ffc, 0x203f...0x2040, 0x2054...0x2054, 0x2071...0x2071, 0x207f...0x207f, 0x2090...0x209c, 0x20d0...0x20dc, 0x20e1...0x20e1, 0x20e5...0x20f0, 0x2102...0x2102, 0x2107...0x2107, 0x210a...0x2113, 0x2115...0x2115, 0x2118...0x211d, 0x2124...0x2124, 0x2126...0x2126, 0x2128...0x2128, 0x212a...0x2139, 0x213c...0x213f, 0x2145...0x2149, 0x214e...0x214e, 0x2160...0x2188, 0x2c00...0x2c2e, 0x2c30...0x2c5e, 0x2c60...0x2ce4, 0x2ceb...0x2cf3, 0x2d00...0x2d25, 0x2d27...0x2d27, 0x2d2d...0x2d2d, 0x2d30...0x2d67, 0x2d6f...0x2d6f, 0x2d7f...0x2d96, 0x2da0...0x2da6, 0x2da8...0x2dae, 0x2db0...0x2db6, 0x2db8...0x2dbe, 0x2dc0...0x2dc6, 0x2dc8...0x2dce, 0x2dd0...0x2dd6, 0x2dd8...0x2dde, 0x2de0...0x2dff, 0x3005...0x3007, 0x3021...0x302f, 0x3031...0x3035, 0x3038...0x303c, 0x3041...0x3096, 0x3099...0x309f, 0x30a1...0x30ff, 0x3105...0x312f, 0x3131...0x318e, 0x31a0...0x31bf, 0x31f0...0x31ff, 0x3400...0x4dbf, 0x4e00...0x9ffc, 0xa000...0xa48c, 0xa4d0...0xa4fd, 0xa500...0xa60c, 0xa610...0xa62b, 0xa640...0xa66f, 0xa674...0xa67d, 0xa67f...0xa6f1, 0xa717...0xa71f, 0xa722...0xa788, 0xa78b...0xa7bf, 0xa7c2...0xa7ca, 0xa7f5...0xa827, 0xa82c...0xa82c, 0xa840...0xa873, 0xa880...0xa8c5, 0xa8d0...0xa8d9, 0xa8e0...0xa8f7, 0xa8fb...0xa8fb, 0xa8fd...0xa92d, 0xa930...0xa953, 0xa960...0xa97c, 0xa980...0xa9c0, 0xa9cf...0xa9d9, 0xa9e0...0xa9fe, 0xaa00...0xaa36, 0xaa40...0xaa4d, 0xaa50...0xaa59, 0xaa60...0xaa76, 0xaa7a...0xaac2, 0xaadb...0xaadd, 0xaae0...0xaaef, 0xaaf2...0xaaf6, 0xab01...0xab06, 0xab09...0xab0e, 0xab11...0xab16, 0xab20...0xab26, 0xab28...0xab2e, 0xab30...0xab5a, 0xab5c...0xab69, 0xab70...0xabea, 0xabec...0xabed, 0xabf0...0xabf9, 0xac00...0xd7a3, 0xd7b0...0xd7c6, 0xd7cb...0xd7fb, 0xf900...0xfa6d, 0xfa70...0xfad9, 0xfb00...0xfb06, 0xfb13...0xfb17, 0xfb1d...0xfb28, 0xfb2a...0xfb36, 0xfb38...0xfb3c, 0xfb3e...0xfb3e, 0xfb40...0xfb41, 0xfb43...0xfb44, 0xfb46...0xfbb1, 0xfbd3...0xfd3d, 0xfd50...0xfd8f, 0xfd92...0xfdc7, 0xfdf0...0xfdfb, 0xfe00...0xfe0f, 0xfe20...0xfe2f, 0xfe33...0xfe34, 0xfe4d...0xfe4f, 0xfe70...0xfe74, 0xfe76...0xfefc, 0xff10...0xff19, 0xff21...0xff3a, 0xff3f...0xff3f, 0xff41...0xff5a, 0xff65...0xffbe, 0xffc2...0xffc7, 0xffca...0xffcf, 0xffd2...0xffd7 => true, - else => false, - }; - } - - fn isIdentifierPartSlow32(codepoint: i32) bool { - return switch (codepoint) { - 0xffda...0xffdc, 0x10000...0x1000b, 0x1000d...0x10026, 0x10028...0x1003a, 0x1003c...0x1003d, 0x1003f...0x1004d, 0x10050...0x1005d, 0x10080...0x100fa, 0x10140...0x10174, 0x101fd...0x101fd, 0x10280...0x1029c, 0x102a0...0x102d0, 0x102e0...0x102e0, 0x10300...0x1031f, 0x1032d...0x1034a, 0x10350...0x1037a, 0x10380...0x1039d, 0x103a0...0x103c3, 0x103c8...0x103cf, 0x103d1...0x103d5, 0x10400...0x1049d, 0x104a0...0x104a9, 0x104b0...0x104d3, 0x104d8...0x104fb, 0x10500...0x10527, 0x10530...0x10563, 0x10600...0x10736, 0x10740...0x10755, 0x10760...0x10767, 0x10800...0x10805, 0x10808...0x10808, 0x1080a...0x10835, 0x10837...0x10838, 0x1083c...0x1083c, 0x1083f...0x10855, 0x10860...0x10876, 0x10880...0x1089e, 0x108e0...0x108f2, 0x108f4...0x108f5, 0x10900...0x10915, 0x10920...0x10939, 0x10980...0x109b7, 0x109be...0x109bf, 0x10a00...0x10a03, 0x10a05...0x10a06, 0x10a0c...0x10a13, 0x10a15...0x10a17, 0x10a19...0x10a35, 0x10a38...0x10a3a, 0x10a3f...0x10a3f, 0x10a60...0x10a7c, 0x10a80...0x10a9c, 0x10ac0...0x10ac7, 0x10ac9...0x10ae6, 0x10b00...0x10b35, 0x10b40...0x10b55, 0x10b60...0x10b72, 0x10b80...0x10b91, 0x10c00...0x10c48, 0x10c80...0x10cb2, 0x10cc0...0x10cf2, 0x10d00...0x10d27, 0x10d30...0x10d39, 0x10e80...0x10ea9, 0x10eab...0x10eac, 0x10eb0...0x10eb1, 0x10f00...0x10f1c, 0x10f27...0x10f27, 0x10f30...0x10f50, 0x10fb0...0x10fc4, 0x10fe0...0x10ff6, 0x11000...0x11046, 0x11066...0x1106f, 0x1107f...0x110ba, 0x110d0...0x110e8, 0x110f0...0x110f9, 0x11100...0x11134, 0x11136...0x1113f, 0x11144...0x11147, 0x11150...0x11173, 0x11176...0x11176, 0x11180...0x111c4, 0x111c9...0x111cc, 0x111ce...0x111da, 0x111dc...0x111dc, 0x11200...0x11211, 0x11213...0x11237, 0x1123e...0x1123e, 0x11280...0x11286, 0x11288...0x11288, 0x1128a...0x1128d, 0x1128f...0x1129d, 0x1129f...0x112a8, 0x112b0...0x112ea, 0x112f0...0x112f9, 0x11300...0x11303, 0x11305...0x1130c, 0x1130f...0x11310, 0x11313...0x11328, 0x1132a...0x11330, 0x11332...0x11333, 0x11335...0x11339, 0x1133b...0x11344, 0x11347...0x11348, 0x1134b...0x1134d, 0x11350...0x11350, 0x11357...0x11357, 0x1135d...0x11363, 0x11366...0x1136c, 0x11370...0x11374, 0x11400...0x1144a, 0x11450...0x11459, 0x1145e...0x11461, 0x11480...0x114c5, 0x114c7...0x114c7, 0x114d0...0x114d9, 0x11580...0x115b5, 0x115b8...0x115c0, 0x115d8...0x115dd, 0x11600...0x11640, 0x11644...0x11644, 0x11650...0x11659, 0x11680...0x116b8, 0x116c0...0x116c9, 0x11700...0x1171a, 0x1171d...0x1172b, 0x11730...0x11739, 0x11800...0x1183a, 0x118a0...0x118e9, 0x118ff...0x11906, 0x11909...0x11909, 0x1190c...0x11913, 0x11915...0x11916, 0x11918...0x11935, 0x11937...0x11938, 0x1193b...0x11943, 0x11950...0x11959, 0x119a0...0x119a7, 0x119aa...0x119d7, 0x119da...0x119e1, 0x119e3...0x119e4, 0x11a00...0x11a3e, 0x11a47...0x11a47, 0x11a50...0x11a99, 0x11a9d...0x11a9d, 0x11ac0...0x11af8, 0x11c00...0x11c08, 0x11c0a...0x11c36, 0x11c38...0x11c40, 0x11c50...0x11c59, 0x11c72...0x11c8f, 0x11c92...0x11ca7, 0x11ca9...0x11cb6, 0x11d00...0x11d06, 0x11d08...0x11d09, 0x11d0b...0x11d36, 0x11d3a...0x11d3a, 0x11d3c...0x11d3d, 0x11d3f...0x11d47, 0x11d50...0x11d59, 0x11d60...0x11d65, 0x11d67...0x11d68, 0x11d6a...0x11d8e, 0x11d90...0x11d91, 0x11d93...0x11d98, 0x11da0...0x11da9, 0x11ee0...0x11ef6, 0x11fb0...0x11fb0, 0x12000...0x12399, 0x12400...0x1246e, 0x12480...0x12543, 0x13000...0x1342e, 0x14400...0x14646, 0x16800...0x16a38, 0x16a40...0x16a5e, 0x16a60...0x16a69, 0x16ad0...0x16aed, 0x16af0...0x16af4, 0x16b00...0x16b36, 0x16b40...0x16b43, 0x16b50...0x16b59, 0x16b63...0x16b77, 0x16b7d...0x16b8f, 0x16e40...0x16e7f, 0x16f00...0x16f4a, 0x16f4f...0x16f87, 0x16f8f...0x16f9f, 0x16fe0...0x16fe1, 0x16fe3...0x16fe4, 0x16ff0...0x16ff1, 0x17000...0x187f7, 0x18800...0x18cd5, 0x18d00...0x18d08, 0x1b000...0x1b11e, 0x1b150...0x1b152, 0x1b164...0x1b167, 0x1b170...0x1b2fb, 0x1bc00...0x1bc6a, 0x1bc70...0x1bc7c, 0x1bc80...0x1bc88, 0x1bc90...0x1bc99, 0x1bc9d...0x1bc9e, 0x1d165...0x1d169, 0x1d16d...0x1d172, 0x1d17b...0x1d182, 0x1d185...0x1d18b, 0x1d1aa...0x1d1ad, 0x1d242...0x1d244, 0x1d400...0x1d454, 0x1d456...0x1d49c, 0x1d49e...0x1d49f, 0x1d4a2...0x1d4a2, 0x1d4a5...0x1d4a6, 0x1d4a9...0x1d4ac, 0x1d4ae...0x1d4b9, 0x1d4bb...0x1d4bb, 0x1d4bd...0x1d4c3, 0x1d4c5...0x1d505, 0x1d507...0x1d50a, 0x1d50d...0x1d514, 0x1d516...0x1d51c, 0x1d51e...0x1d539, 0x1d53b...0x1d53e, 0x1d540...0x1d544, 0x1d546...0x1d546, 0x1d54a...0x1d550, 0x1d552...0x1d6a5, 0x1d6a8...0x1d6c0, 0x1d6c2...0x1d6da, 0x1d6dc...0x1d6fa, 0x1d6fc...0x1d714, 0x1d716...0x1d734, 0x1d736...0x1d74e, 0x1d750...0x1d76e, 0x1d770...0x1d788, 0x1d78a...0x1d7a8, 0x1d7aa...0x1d7c2, 0x1d7c4...0x1d7cb, 0x1d7ce...0x1d7ff, 0x1da00...0x1da36, 0x1da3b...0x1da6c, 0x1da75...0x1da75, 0x1da84...0x1da84, 0x1da9b...0x1da9f, 0x1daa1...0x1daaf, 0x1e000...0x1e006, 0x1e008...0x1e018, 0x1e01b...0x1e021, 0x1e023...0x1e024, 0x1e026...0x1e02a, 0x1e100...0x1e12c, 0x1e130...0x1e13d, 0x1e140...0x1e149, 0x1e14e...0x1e14e, 0x1e2c0...0x1e2f9, 0x1e800...0x1e8c4, 0x1e8d0...0x1e8d6, 0x1e900...0x1e94b, 0x1e950...0x1e959, 0x1ee00...0x1ee03, 0x1ee05...0x1ee1f, 0x1ee21...0x1ee22, 0x1ee24...0x1ee24, 0x1ee27...0x1ee27, 0x1ee29...0x1ee32, 0x1ee34...0x1ee37, 0x1ee39...0x1ee39, 0x1ee3b...0x1ee3b, 0x1ee42...0x1ee42, 0x1ee47...0x1ee47, 0x1ee49...0x1ee49, 0x1ee4b...0x1ee4b, 0x1ee4d...0x1ee4f, 0x1ee51...0x1ee52, 0x1ee54...0x1ee54, 0x1ee57...0x1ee57, 0x1ee59...0x1ee59, 0x1ee5b...0x1ee5b, 0x1ee5d...0x1ee5d, 0x1ee5f...0x1ee5f, 0x1ee61...0x1ee62, 0x1ee64...0x1ee64, 0x1ee67...0x1ee6a, 0x1ee6c...0x1ee72, 0x1ee74...0x1ee77, 0x1ee79...0x1ee7c, 0x1ee7e...0x1ee7e, 0x1ee80...0x1ee89, 0x1ee8b...0x1ee9b, 0x1eea1...0x1eea3, 0x1eea5...0x1eea9, 0x1eeab...0x1eebb, 0x1fbf0...0x1fbf9, 0x20000...0x2a6dd, 0x2a700...0x2b734, 0x2b740...0x2b81d, 0x2b820...0x2cea1, 0x2ceb0...0x2ebe0, 0x2f800...0x2fa1d, 0x30000...0x3134a, 0xe0100...0xe01ef => true, - else => false, - }; - } - - fn isIdentifierStartSlow16(codepoint: u16) bool { - return switch (codepoint) { - 0xaa...0xaa, 0xb5...0xb5, 0xba...0xba, 0xc0...0xd6, 0xd8...0xf6, 0xf8...0x2c1, 0x2c6...0x2d1, 0x2e0...0x2e4, 0x2ec...0x2ec, 0x2ee...0x2ee, 0x370...0x374, 0x376...0x377, 0x37a...0x37d, 0x37f...0x37f, 0x386...0x386, 0x388...0x38a, 0x38c...0x38c, 0x38e...0x3a1, 0x3a3...0x3f5, 0x3f7...0x481, 0x48a...0x52f, 0x531...0x556, 0x559...0x559, 0x560...0x588, 0x5d0...0x5ea, 0x5ef...0x5f2, 0x620...0x64a, 0x66e...0x66f, 0x671...0x6d3, 0x6d5...0x6d5, 0x6e5...0x6e6, 0x6ee...0x6ef, 0x6fa...0x6fc, 0x6ff...0x6ff, 0x710...0x710, 0x712...0x72f, 0x74d...0x7a5, 0x7b1...0x7b1, 0x7ca...0x7ea, 0x7f4...0x7f5, 0x7fa...0x7fa, 0x800...0x815, 0x81a...0x81a, 0x824...0x824, 0x828...0x828, 0x840...0x858, 0x860...0x86a, 0x8a0...0x8b4, 0x8b6...0x8c7, 0x904...0x939, 0x93d...0x93d, 0x950...0x950, 0x958...0x961, 0x971...0x980, 0x985...0x98c, 0x98f...0x990, 0x993...0x9a8, 0x9aa...0x9b0, 0x9b2...0x9b2, 0x9b6...0x9b9, 0x9bd...0x9bd, 0x9ce...0x9ce, 0x9dc...0x9dd, 0x9df...0x9e1, 0x9f0...0x9f1, 0x9fc...0x9fc, 0xa05...0xa0a, 0xa0f...0xa10, 0xa13...0xa28, 0xa2a...0xa30, 0xa32...0xa33, 0xa35...0xa36, 0xa38...0xa39, 0xa59...0xa5c, 0xa5e...0xa5e, 0xa72...0xa74, 0xa85...0xa8d, 0xa8f...0xa91, 0xa93...0xaa8, 0xaaa...0xab0, 0xab2...0xab3, 0xab5...0xab9, 0xabd...0xabd, 0xad0...0xad0, 0xae0...0xae1, 0xaf9...0xaf9, 0xb05...0xb0c, 0xb0f...0xb10, 0xb13...0xb28, 0xb2a...0xb30, 0xb32...0xb33, 0xb35...0xb39, 0xb3d...0xb3d, 0xb5c...0xb5d, 0xb5f...0xb61, 0xb71...0xb71, 0xb83...0xb83, 0xb85...0xb8a, 0xb8e...0xb90, 0xb92...0xb95, 0xb99...0xb9a, 0xb9c...0xb9c, 0xb9e...0xb9f, 0xba3...0xba4, 0xba8...0xbaa, 0xbae...0xbb9, 0xbd0...0xbd0, 0xc05...0xc0c, 0xc0e...0xc10, 0xc12...0xc28, 0xc2a...0xc39, 0xc3d...0xc3d, 0xc58...0xc5a, 0xc60...0xc61, 0xc80...0xc80, 0xc85...0xc8c, 0xc8e...0xc90, 0xc92...0xca8, 0xcaa...0xcb3, 0xcb5...0xcb9, 0xcbd...0xcbd, 0xcde...0xcde, 0xce0...0xce1, 0xcf1...0xcf2, 0xd04...0xd0c, 0xd0e...0xd10, 0xd12...0xd3a, 0xd3d...0xd3d, 0xd4e...0xd4e, 0xd54...0xd56, 0xd5f...0xd61, 0xd7a...0xd7f, 0xd85...0xd96, 0xd9a...0xdb1, 0xdb3...0xdbb, 0xdbd...0xdbd, 0xdc0...0xdc6, 0xe01...0xe30, 0xe32...0xe33, 0xe40...0xe46, 0xe81...0xe82, 0xe84...0xe84, 0xe86...0xe8a, 0xe8c...0xea3, 0xea5...0xea5, 0xea7...0xeb0, 0xeb2...0xeb3, 0xebd...0xebd, 0xec0...0xec4, 0xec6...0xec6, 0xedc...0xedf, 0xf00...0xf00, 0xf40...0xf47, 0xf49...0xf6c, 0xf88...0xf8c, 0x1000...0x102a, 0x103f...0x103f, 0x1050...0x1055, 0x105a...0x105d, 0x1061...0x1061, 0x1065...0x1066, 0x106e...0x1070, 0x1075...0x1081, 0x108e...0x108e, 0x10a0...0x10c5, 0x10c7...0x10c7, 0x10cd...0x10cd, 0x10d0...0x10fa, 0x10fc...0x1248, 0x124a...0x124d, 0x1250...0x1256, 0x1258...0x1258, 0x125a...0x125d, 0x1260...0x1288, 0x128a...0x128d, 0x1290...0x12b0, 0x12b2...0x12b5, 0x12b8...0x12be, 0x12c0...0x12c0, 0x12c2...0x12c5, 0x12c8...0x12d6, 0x12d8...0x1310, 0x1312...0x1315, 0x1318...0x135a, 0x1380...0x138f, 0x13a0...0x13f5, 0x13f8...0x13fd, 0x1401...0x166c, 0x166f...0x167f, 0x1681...0x169a, 0x16a0...0x16ea, 0x16ee...0x16f8, 0x1700...0x170c, 0x170e...0x1711, 0x1720...0x1731, 0x1740...0x1751, 0x1760...0x176c, 0x176e...0x1770, 0x1780...0x17b3, 0x17d7...0x17d7, 0x17dc...0x17dc, 0x1820...0x1878, 0x1880...0x18a8, 0x18aa...0x18aa, 0x18b0...0x18f5, 0x1900...0x191e, 0x1950...0x196d, 0x1970...0x1974, 0x1980...0x19ab, 0x19b0...0x19c9, 0x1a00...0x1a16, 0x1a20...0x1a54, 0x1aa7...0x1aa7, 0x1b05...0x1b33, 0x1b45...0x1b4b, 0x1b83...0x1ba0, 0x1bae...0x1baf, 0x1bba...0x1be5, 0x1c00...0x1c23, 0x1c4d...0x1c4f, 0x1c5a...0x1c7d, 0x1c80...0x1c88, 0x1c90...0x1cba, 0x1cbd...0x1cbf, 0x1ce9...0x1cec, 0x1cee...0x1cf3, 0x1cf5...0x1cf6, 0x1cfa...0x1cfa, 0x1d00...0x1dbf, 0x1e00...0x1f15, 0x1f18...0x1f1d, 0x1f20...0x1f45, 0x1f48...0x1f4d, 0x1f50...0x1f57, 0x1f59...0x1f59, 0x1f5b...0x1f5b, 0x1f5d...0x1f5d, 0x1f5f...0x1f7d, 0x1f80...0x1fb4, 0x1fb6...0x1fbc, 0x1fbe...0x1fbe, 0x1fc2...0x1fc4, 0x1fc6...0x1fcc, 0x1fd0...0x1fd3, 0x1fd6...0x1fdb, 0x1fe0...0x1fec, 0x1ff2...0x1ff4, 0x1ff6...0x1ffc, 0x2071...0x2071, 0x207f...0x207f, 0x2090...0x209c, 0x2102...0x2102, 0x2107...0x2107, 0x210a...0x2113, 0x2115...0x2115, 0x2118...0x211d, 0x2124...0x2124, 0x2126...0x2126, 0x2128...0x2128, 0x212a...0x2139, 0x213c...0x213f, 0x2145...0x2149, 0x214e...0x214e, 0x2160...0x2188, 0x2c00...0x2c2e, 0x2c30...0x2c5e, 0x2c60...0x2ce4, 0x2ceb...0x2cee, 0x2cf2...0x2cf3, 0x2d00...0x2d25, 0x2d27...0x2d27, 0x2d2d...0x2d2d, 0x2d30...0x2d67, 0x2d6f...0x2d6f, 0x2d80...0x2d96, 0x2da0...0x2da6, 0x2da8...0x2dae, 0x2db0...0x2db6, 0x2db8...0x2dbe, 0x2dc0...0x2dc6, 0x2dc8...0x2dce, 0x2dd0...0x2dd6, 0x2dd8...0x2dde, 0x3005...0x3007, 0x3021...0x3029, 0x3031...0x3035, 0x3038...0x303c, 0x3041...0x3096, 0x309b...0x309f, 0x30a1...0x30fa, 0x30fc...0x30ff, 0x3105...0x312f, 0x3131...0x318e, 0x31a0...0x31bf, 0x31f0...0x31ff, 0x3400...0x4dbf, 0x4e00...0x9ffc, 0xa000...0xa48c, 0xa4d0...0xa4fd, 0xa500...0xa60c, 0xa610...0xa61f, 0xa62a...0xa62b, 0xa640...0xa66e, 0xa67f...0xa69d, 0xa6a0...0xa6ef, 0xa717...0xa71f, 0xa722...0xa788, 0xa78b...0xa7bf, 0xa7c2...0xa7ca, 0xa7f5...0xa801, 0xa803...0xa805, 0xa807...0xa80a, 0xa80c...0xa822, 0xa840...0xa873, 0xa882...0xa8b3, 0xa8f2...0xa8f7, 0xa8fb...0xa8fb, 0xa8fd...0xa8fe, 0xa90a...0xa925, 0xa930...0xa946, 0xa960...0xa97c, 0xa984...0xa9b2, 0xa9cf...0xa9cf, 0xa9e0...0xa9e4, 0xa9e6...0xa9ef, 0xa9fa...0xa9fe, 0xaa00...0xaa28, 0xaa40...0xaa42, 0xaa44...0xaa4b, 0xaa60...0xaa76, 0xaa7a...0xaa7a, 0xaa7e...0xaaaf, 0xaab1...0xaab1, 0xaab5...0xaab6, 0xaab9...0xaabd, 0xaac0...0xaac0, 0xaac2...0xaac2, 0xaadb...0xaadd, 0xaae0...0xaaea, 0xaaf2...0xaaf4, 0xab01...0xab06, 0xab09...0xab0e, 0xab11...0xab16, 0xab20...0xab26, 0xab28...0xab2e, 0xab30...0xab5a, 0xab5c...0xab69, 0xab70...0xabe2, 0xac00...0xd7a3, 0xd7b0...0xd7c6, 0xd7cb...0xd7fb, 0xf900...0xfa6d, 0xfa70...0xfad9, 0xfb00...0xfb06, 0xfb13...0xfb17, 0xfb1d...0xfb1d, 0xfb1f...0xfb28, 0xfb2a...0xfb36, 0xfb38...0xfb3c, 0xfb3e...0xfb3e, 0xfb40...0xfb41, 0xfb43...0xfb44, 0xfb46...0xfbb1, 0xfbd3...0xfd3d, 0xfd50...0xfd8f, 0xfd92...0xfdc7 => true, - else => false, - }; - } - - fn isIdentifierStartSlow32(codepoint: i32) bool { - return switch (codepoint) { - 0xfdf0...0xfdfb, 0xfe70...0xfe74, 0xfe76...0xfefc, 0xff21...0xff3a, 0xff41...0xff5a, 0xff66...0xffbe, 0xffc2...0xffc7, 0xffca...0xffcf, 0xffd2...0xffd7, 0xffda...0xffdc, 0x10000...0x1000b, 0x1000d...0x10026, 0x10028...0x1003a, 0x1003c...0x1003d, 0x1003f...0x1004d, 0x10050...0x1005d, 0x10080...0x100fa, 0x10140...0x10174, 0x10280...0x1029c, 0x102a0...0x102d0, 0x10300...0x1031f, 0x1032d...0x1034a, 0x10350...0x10375, 0x10380...0x1039d, 0x103a0...0x103c3, 0x103c8...0x103cf, 0x103d1...0x103d5, 0x10400...0x1049d, 0x104b0...0x104d3, 0x104d8...0x104fb, 0x10500...0x10527, 0x10530...0x10563, 0x10600...0x10736, 0x10740...0x10755, 0x10760...0x10767, 0x10800...0x10805, 0x10808...0x10808, 0x1080a...0x10835, 0x10837...0x10838, 0x1083c...0x1083c, 0x1083f...0x10855, 0x10860...0x10876, 0x10880...0x1089e, 0x108e0...0x108f2, 0x108f4...0x108f5, 0x10900...0x10915, 0x10920...0x10939, 0x10980...0x109b7, 0x109be...0x109bf, 0x10a00...0x10a00, 0x10a10...0x10a13, 0x10a15...0x10a17, 0x10a19...0x10a35, 0x10a60...0x10a7c, 0x10a80...0x10a9c, 0x10ac0...0x10ac7, 0x10ac9...0x10ae4, 0x10b00...0x10b35, 0x10b40...0x10b55, 0x10b60...0x10b72, 0x10b80...0x10b91, 0x10c00...0x10c48, 0x10c80...0x10cb2, 0x10cc0...0x10cf2, 0x10d00...0x10d23, 0x10e80...0x10ea9, 0x10eb0...0x10eb1, 0x10f00...0x10f1c, 0x10f27...0x10f27, 0x10f30...0x10f45, 0x10fb0...0x10fc4, 0x10fe0...0x10ff6, 0x11003...0x11037, 0x11083...0x110af, 0x110d0...0x110e8, 0x11103...0x11126, 0x11144...0x11144, 0x11147...0x11147, 0x11150...0x11172, 0x11176...0x11176, 0x11183...0x111b2, 0x111c1...0x111c4, 0x111da...0x111da, 0x111dc...0x111dc, 0x11200...0x11211, 0x11213...0x1122b, 0x11280...0x11286, 0x11288...0x11288, 0x1128a...0x1128d, 0x1128f...0x1129d, 0x1129f...0x112a8, 0x112b0...0x112de, 0x11305...0x1130c, 0x1130f...0x11310, 0x11313...0x11328, 0x1132a...0x11330, 0x11332...0x11333, 0x11335...0x11339, 0x1133d...0x1133d, 0x11350...0x11350, 0x1135d...0x11361, 0x11400...0x11434, 0x11447...0x1144a, 0x1145f...0x11461, 0x11480...0x114af, 0x114c4...0x114c5, 0x114c7...0x114c7, 0x11580...0x115ae, 0x115d8...0x115db, 0x11600...0x1162f, 0x11644...0x11644, 0x11680...0x116aa, 0x116b8...0x116b8, 0x11700...0x1171a, 0x11800...0x1182b, 0x118a0...0x118df, 0x118ff...0x11906, 0x11909...0x11909, 0x1190c...0x11913, 0x11915...0x11916, 0x11918...0x1192f, 0x1193f...0x1193f, 0x11941...0x11941, 0x119a0...0x119a7, 0x119aa...0x119d0, 0x119e1...0x119e1, 0x119e3...0x119e3, 0x11a00...0x11a00, 0x11a0b...0x11a32, 0x11a3a...0x11a3a, 0x11a50...0x11a50, 0x11a5c...0x11a89, 0x11a9d...0x11a9d, 0x11ac0...0x11af8, 0x11c00...0x11c08, 0x11c0a...0x11c2e, 0x11c40...0x11c40, 0x11c72...0x11c8f, 0x11d00...0x11d06, 0x11d08...0x11d09, 0x11d0b...0x11d30, 0x11d46...0x11d46, 0x11d60...0x11d65, 0x11d67...0x11d68, 0x11d6a...0x11d89, 0x11d98...0x11d98, 0x11ee0...0x11ef2, 0x11fb0...0x11fb0, 0x12000...0x12399, 0x12400...0x1246e, 0x12480...0x12543, 0x13000...0x1342e, 0x14400...0x14646, 0x16800...0x16a38, 0x16a40...0x16a5e, 0x16ad0...0x16aed, 0x16b00...0x16b2f, 0x16b40...0x16b43, 0x16b63...0x16b77, 0x16b7d...0x16b8f, 0x16e40...0x16e7f, 0x16f00...0x16f4a, 0x16f50...0x16f50, 0x16f93...0x16f9f, 0x16fe0...0x16fe1, 0x16fe3...0x16fe3, 0x17000...0x187f7, 0x18800...0x18cd5, 0x18d00...0x18d08, 0x1b000...0x1b11e, 0x1b150...0x1b152, 0x1b164...0x1b167, 0x1b170...0x1b2fb, 0x1bc00...0x1bc6a, 0x1bc70...0x1bc7c, 0x1bc80...0x1bc88, 0x1bc90...0x1bc99, 0x1d400...0x1d454, 0x1d456...0x1d49c, 0x1d49e...0x1d49f, 0x1d4a2...0x1d4a2, 0x1d4a5...0x1d4a6, 0x1d4a9...0x1d4ac, 0x1d4ae...0x1d4b9, 0x1d4bb...0x1d4bb, 0x1d4bd...0x1d4c3, 0x1d4c5...0x1d505, 0x1d507...0x1d50a, 0x1d50d...0x1d514, 0x1d516...0x1d51c, 0x1d51e...0x1d539, 0x1d53b...0x1d53e, 0x1d540...0x1d544, 0x1d546...0x1d546, 0x1d54a...0x1d550, 0x1d552...0x1d6a5, 0x1d6a8...0x1d6c0, 0x1d6c2...0x1d6da, 0x1d6dc...0x1d6fa, 0x1d6fc...0x1d714, 0x1d716...0x1d734, 0x1d736...0x1d74e, 0x1d750...0x1d76e, 0x1d770...0x1d788, 0x1d78a...0x1d7a8, 0x1d7aa...0x1d7c2, 0x1d7c4...0x1d7cb, 0x1e100...0x1e12c, 0x1e137...0x1e13d, 0x1e14e...0x1e14e, 0x1e2c0...0x1e2eb, 0x1e800...0x1e8c4, 0x1e900...0x1e943, 0x1e94b...0x1e94b, 0x1ee00...0x1ee03, 0x1ee05...0x1ee1f, 0x1ee21...0x1ee22, 0x1ee24...0x1ee24, 0x1ee27...0x1ee27, 0x1ee29...0x1ee32, 0x1ee34...0x1ee37, 0x1ee39...0x1ee39, 0x1ee3b...0x1ee3b, 0x1ee42...0x1ee42, 0x1ee47...0x1ee47, 0x1ee49...0x1ee49, 0x1ee4b...0x1ee4b, 0x1ee4d...0x1ee4f, 0x1ee51...0x1ee52, 0x1ee54...0x1ee54, 0x1ee57...0x1ee57, 0x1ee59...0x1ee59, 0x1ee5b...0x1ee5b, 0x1ee5d...0x1ee5d, 0x1ee5f...0x1ee5f, 0x1ee61...0x1ee62, 0x1ee64...0x1ee64, 0x1ee67...0x1ee6a, 0x1ee6c...0x1ee72, 0x1ee74...0x1ee77, 0x1ee79...0x1ee7c, 0x1ee7e...0x1ee7e, 0x1ee80...0x1ee89, 0x1ee8b...0x1ee9b, 0x1eea1...0x1eea3, 0x1eea5...0x1eea9, 0x1eeab...0x1eebb, 0x20000...0x2a6dd, 0x2a700...0x2b734, 0x2b740...0x2b81d, 0x2b820...0x2cea1, 0x2ceb0...0x2ebe0, 0x2f800...0x2fa1d, 0x30000...0x3134a => true, - else => false, - }; - } - - noinline fn isIdentifierStartSlow(codepoint: i32) bool { - @setCold(true); - return switch (codepoint) { - // explicitly tell LLVM's optimizer about values we know will not be in the range of this switch statement - - (max_codepoint + 1)...maxInt(i32), minInt(i32)...127 => unreachable, - 128...0xfdc7 => isIdentifierStartSlow16(@as(u16, @intCast(codepoint))), - 0xfdf0...0x3134a => isIdentifierStartSlow32(codepoint), - else => false, - }; - } - - pub inline fn isIdentifierStart(codepoint: i32) bool { - return switch (codepoint) { - 'A'...'Z', 'a'...'z', '$', '_' => true, - else => if (codepoint < 128) - return false - else - return isIdentifierStartSlow(codepoint), - }; - } - - pub inline fn isIdentifierPart(codepoint: i32) bool { - return switch (codepoint) { - 'A'...'Z', 'a'...'z', '0'...'9', '$', '_' => true, - else => if (codepoint < 128) - return false - else if (codepoint == 0x200C or codepoint == 0x200D) - return true - else - return isIdentifierPartSlow(codepoint), - }; - } +/// isIDContinueES5 checks if a codepoint is valid in the isIDContinueES5 category +pub fn isIDContinueES5(cp: u21) bool { + const high = cp >> 8; + const low = cp & 0xFF; + const stage2_idx = idContinueES5.stage1[high]; + const bit_pos = stage2_idx + low; + const u64_idx = bit_pos >> 6; + const bit_idx = @as(u6, @intCast(bit_pos & 63)); + return (idContinueES5.stage2[u64_idx] & (@as(u64, 1) << bit_idx)) != 0; +} +const idContinueES5 = struct { + pub const stage1 = [_]u16{ 0, 256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, 4096, 4352, 4608, 4864, 5120, 256, 5376, 5632, 5888, 2048, 2048, 2048, 2048, 2048, 6144, 6400, 6656, 6912, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 7168, 7424, 2048, 2048, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 7680, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 7936, 256, 256, 256, 256, 8192, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 8448, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 256, 8704, 8960, 256, 9216, 9472, 9728, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048 }; + pub const stage2 = [_]u64{ 287948901175001088, 576460745995190270, 297241973452963840, 18410715276682199039, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 4503586742468607, 18446744073709486080, 18014187403249451007, 70501888360451, 18446744073709551615, 288230406216515583, 18446744056529672000, 4503599577006079, 18446744073709551615, 18446744073709551615, 18446744073709547643, 234187180623206815, 18446181123756130304, 18446744065161560063, 13546827661950451967, 1979120929931286, 576460743713488896, 18446466992488579071, 18446744073709551615, 2305629702346244095, 18446497783104864256, 2047, 562949953421311, 0, 0, 0, 0, 0, 17582052945254416366, 281268803551231, 15259882188367831022, 1125692414638495, 15235112390417287140, 9006925953907079, 17576984196650086382, 281204393851839, 17567976997395210222, 281215949093263, 14105211467435198444, 280925229301191, 14118782632783110126, 281212990012895, 14118782632783110124, 281214063754719, 14123286232410480620, 281212992110031, 3457638613854978028, 3377704004977791, 576460752303423486, 67076095, 4323434403644581270, 872365919, 14024213633433600001, 18446189919849152255, 2305843009196855263, 64, 272457864671395839, 67044351, 18446744069414584320, 36028797018898495, 18446744073709551615, 18446744071629176831, 18446743008557662207, 288230376151711743, 18446744073709551487, 18446744070446333311, 9168625153884503423, 18446603336212774717, 18446744071549321215, 1123701017804671, 18446744069414584320, 9007199254740991, 18446744073709551614, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 35923243902697471, 18446744069548802046, 8796093022207, 0, 0, 18446744073709551615, 4393752592383, 18446744069481627648, 72057594037927935, 4398046511103, 0, 18446744073709551615, 18446744073709551615, 18446744069683019775, 288230376151711743, 18446744070475743231, 4611686017001275199, 6908521828386340863, 2295745090394464220, 9223372036854775808, 9223372036854775809, 0, 9126739968, 287031153606524036, 0, 0, 0, 17728525486260320, 18446744073709551614, 18446744066832990207, 9223372036854775807, 18446216308128219104, 18446744073709551615, 72057589742993407, 0, 18446744073709551615, 18446744073709551615, 18014398509481983, 0, 18446744073709551615, 18446744073709551615, 274877906943, 0, 18446744073709551615, 18446744073709551615, 8191, 0, 18446744073709551615, 18446744073709551615, 68719476735, 0, 70368744177663, 0, 0, 0, 6881498031078244479, 18446744073709551579, 1125899906842623, 18446744073709027328, 4611686018427387903, 18446744073709486080, 18446744073709355007, 1152640029630136575, 6755463865565184, 18435203599664472064, 18446744073709551615, 2305843009213693951, 9799832780635308032, 18446743936404815870, 9223372036854775807, 486341884 }; }; -pub const JumpTableInline = struct { - pub inline fn isIdentifierStart(codepoint: i32) bool { - return switch (codepoint) { - 'A'...'Z', 'a'...'z', '$', '_' => true, - - else => switch (codepoint) { - 0x41...0x5a, 0x61...0x7a, 0xaa...0xaa, 0xb5...0xb5, 0xba...0xba, 0xc0...0xd6, 0xd8...0xf6, 0xf8...0x2c1, 0x2c6...0x2d1, 0x2e0...0x2e4, 0x2ec...0x2ec, 0x2ee...0x2ee, 0x370...0x374, 0x376...0x377, 0x37a...0x37d, 0x37f...0x37f, 0x386...0x386, 0x388...0x38a, 0x38c...0x38c, 0x38e...0x3a1, 0x3a3...0x3f5, 0x3f7...0x481, 0x48a...0x52f, 0x531...0x556, 0x559...0x559, 0x560...0x588, 0x5d0...0x5ea, 0x5ef...0x5f2, 0x620...0x64a, 0x66e...0x66f, 0x671...0x6d3, 0x6d5...0x6d5, 0x6e5...0x6e6, 0x6ee...0x6ef, 0x6fa...0x6fc, 0x6ff...0x6ff, 0x710...0x710, 0x712...0x72f, 0x74d...0x7a5, 0x7b1...0x7b1, 0x7ca...0x7ea, 0x7f4...0x7f5, 0x7fa...0x7fa, 0x800...0x815, 0x81a...0x81a, 0x824...0x824, 0x828...0x828, 0x840...0x858, 0x860...0x86a, 0x8a0...0x8b4, 0x8b6...0x8c7, 0x904...0x939, 0x93d...0x93d, 0x950...0x950, 0x958...0x961, 0x971...0x980, 0x985...0x98c, 0x98f...0x990, 0x993...0x9a8, 0x9aa...0x9b0, 0x9b2...0x9b2, 0x9b6...0x9b9, 0x9bd...0x9bd, 0x9ce...0x9ce, 0x9dc...0x9dd, 0x9df...0x9e1, 0x9f0...0x9f1, 0x9fc...0x9fc, 0xa05...0xa0a, 0xa0f...0xa10, 0xa13...0xa28, 0xa2a...0xa30, 0xa32...0xa33, 0xa35...0xa36, 0xa38...0xa39, 0xa59...0xa5c, 0xa5e...0xa5e, 0xa72...0xa74, 0xa85...0xa8d, 0xa8f...0xa91, 0xa93...0xaa8, 0xaaa...0xab0, 0xab2...0xab3, 0xab5...0xab9, 0xabd...0xabd, 0xad0...0xad0, 0xae0...0xae1, 0xaf9...0xaf9, 0xb05...0xb0c, 0xb0f...0xb10, 0xb13...0xb28, 0xb2a...0xb30, 0xb32...0xb33, 0xb35...0xb39, 0xb3d...0xb3d, 0xb5c...0xb5d, 0xb5f...0xb61, 0xb71...0xb71, 0xb83...0xb83, 0xb85...0xb8a, 0xb8e...0xb90, 0xb92...0xb95, 0xb99...0xb9a, 0xb9c...0xb9c, 0xb9e...0xb9f, 0xba3...0xba4, 0xba8...0xbaa, 0xbae...0xbb9, 0xbd0...0xbd0, 0xc05...0xc0c, 0xc0e...0xc10, 0xc12...0xc28, 0xc2a...0xc39, 0xc3d...0xc3d, 0xc58...0xc5a, 0xc60...0xc61, 0xc80...0xc80, 0xc85...0xc8c, 0xc8e...0xc90, 0xc92...0xca8, 0xcaa...0xcb3, 0xcb5...0xcb9, 0xcbd...0xcbd, 0xcde...0xcde, 0xce0...0xce1, 0xcf1...0xcf2, 0xd04...0xd0c, 0xd0e...0xd10, 0xd12...0xd3a, 0xd3d...0xd3d, 0xd4e...0xd4e, 0xd54...0xd56, 0xd5f...0xd61, 0xd7a...0xd7f, 0xd85...0xd96, 0xd9a...0xdb1, 0xdb3...0xdbb, 0xdbd...0xdbd, 0xdc0...0xdc6, 0xe01...0xe30, 0xe32...0xe33, 0xe40...0xe46, 0xe81...0xe82, 0xe84...0xe84, 0xe86...0xe8a, 0xe8c...0xea3, 0xea5...0xea5, 0xea7...0xeb0, 0xeb2...0xeb3, 0xebd...0xebd, 0xec0...0xec4, 0xec6...0xec6, 0xedc...0xedf, 0xf00...0xf00, 0xf40...0xf47, 0xf49...0xf6c, 0xf88...0xf8c, 0x1000...0x102a, 0x103f...0x103f, 0x1050...0x1055, 0x105a...0x105d, 0x1061...0x1061, 0x1065...0x1066, 0x106e...0x1070, 0x1075...0x1081, 0x108e...0x108e, 0x10a0...0x10c5, 0x10c7...0x10c7, 0x10cd...0x10cd, 0x10d0...0x10fa, 0x10fc...0x1248, 0x124a...0x124d, 0x1250...0x1256, 0x1258...0x1258, 0x125a...0x125d, 0x1260...0x1288, 0x128a...0x128d, 0x1290...0x12b0, 0x12b2...0x12b5, 0x12b8...0x12be, 0x12c0...0x12c0, 0x12c2...0x12c5, 0x12c8...0x12d6, 0x12d8...0x1310, 0x1312...0x1315, 0x1318...0x135a, 0x1380...0x138f, 0x13a0...0x13f5, 0x13f8...0x13fd, 0x1401...0x166c, 0x166f...0x167f, 0x1681...0x169a, 0x16a0...0x16ea, 0x16ee...0x16f8, 0x1700...0x170c, 0x170e...0x1711, 0x1720...0x1731, 0x1740...0x1751, 0x1760...0x176c, 0x176e...0x1770, 0x1780...0x17b3, 0x17d7...0x17d7, 0x17dc...0x17dc, 0x1820...0x1878, 0x1880...0x18a8, 0x18aa...0x18aa, 0x18b0...0x18f5, 0x1900...0x191e, 0x1950...0x196d, 0x1970...0x1974, 0x1980...0x19ab, 0x19b0...0x19c9, 0x1a00...0x1a16, 0x1a20...0x1a54, 0x1aa7...0x1aa7, 0x1b05...0x1b33, 0x1b45...0x1b4b, 0x1b83...0x1ba0, 0x1bae...0x1baf, 0x1bba...0x1be5, 0x1c00...0x1c23, 0x1c4d...0x1c4f, 0x1c5a...0x1c7d, 0x1c80...0x1c88, 0x1c90...0x1cba, 0x1cbd...0x1cbf, 0x1ce9...0x1cec, 0x1cee...0x1cf3, 0x1cf5...0x1cf6, 0x1cfa...0x1cfa, 0x1d00...0x1dbf, 0x1e00...0x1f15, 0x1f18...0x1f1d, 0x1f20...0x1f45, 0x1f48...0x1f4d, 0x1f50...0x1f57, 0x1f59...0x1f59, 0x1f5b...0x1f5b, 0x1f5d...0x1f5d, 0x1f5f...0x1f7d, 0x1f80...0x1fb4, 0x1fb6...0x1fbc, 0x1fbe...0x1fbe, 0x1fc2...0x1fc4, 0x1fc6...0x1fcc, 0x1fd0...0x1fd3, 0x1fd6...0x1fdb, 0x1fe0...0x1fec, 0x1ff2...0x1ff4, 0x1ff6...0x1ffc, 0x2071...0x2071, 0x207f...0x207f, 0x2090...0x209c, 0x2102...0x2102, 0x2107...0x2107, 0x210a...0x2113, 0x2115...0x2115, 0x2118...0x211d, 0x2124...0x2124, 0x2126...0x2126, 0x2128...0x2128, 0x212a...0x2139, 0x213c...0x213f, 0x2145...0x2149, 0x214e...0x214e, 0x2160...0x2188, 0x2c00...0x2c2e, 0x2c30...0x2c5e, 0x2c60...0x2ce4, 0x2ceb...0x2cee, 0x2cf2...0x2cf3, 0x2d00...0x2d25, 0x2d27...0x2d27, 0x2d2d...0x2d2d, 0x2d30...0x2d67, 0x2d6f...0x2d6f, 0x2d80...0x2d96, 0x2da0...0x2da6, 0x2da8...0x2dae, 0x2db0...0x2db6, 0x2db8...0x2dbe, 0x2dc0...0x2dc6, 0x2dc8...0x2dce, 0x2dd0...0x2dd6, 0x2dd8...0x2dde, 0x3005...0x3007, 0x3021...0x3029, 0x3031...0x3035, 0x3038...0x303c, 0x3041...0x3096, 0x309b...0x309f, 0x30a1...0x30fa, 0x30fc...0x30ff, 0x3105...0x312f, 0x3131...0x318e, 0x31a0...0x31bf, 0x31f0...0x31ff, 0x3400...0x4dbf, 0x4e00...0x9ffc, 0xa000...0xa48c, 0xa4d0...0xa4fd, 0xa500...0xa60c, 0xa610...0xa61f, 0xa62a...0xa62b, 0xa640...0xa66e, 0xa67f...0xa69d, 0xa6a0...0xa6ef, 0xa717...0xa71f, 0xa722...0xa788, 0xa78b...0xa7bf, 0xa7c2...0xa7ca, 0xa7f5...0xa801, 0xa803...0xa805, 0xa807...0xa80a, 0xa80c...0xa822, 0xa840...0xa873, 0xa882...0xa8b3, 0xa8f2...0xa8f7, 0xa8fb...0xa8fb, 0xa8fd...0xa8fe, 0xa90a...0xa925, 0xa930...0xa946, 0xa960...0xa97c, 0xa984...0xa9b2, 0xa9cf...0xa9cf, 0xa9e0...0xa9e4, 0xa9e6...0xa9ef, 0xa9fa...0xa9fe, 0xaa00...0xaa28, 0xaa40...0xaa42, 0xaa44...0xaa4b, 0xaa60...0xaa76, 0xaa7a...0xaa7a, 0xaa7e...0xaaaf, 0xaab1...0xaab1, 0xaab5...0xaab6, 0xaab9...0xaabd, 0xaac0...0xaac0, 0xaac2...0xaac2, 0xaadb...0xaadd, 0xaae0...0xaaea, 0xaaf2...0xaaf4, 0xab01...0xab06, 0xab09...0xab0e, 0xab11...0xab16, 0xab20...0xab26, 0xab28...0xab2e, 0xab30...0xab5a, 0xab5c...0xab69, 0xab70...0xabe2, 0xac00...0xd7a3, 0xd7b0...0xd7c6, 0xd7cb...0xd7fb, 0xf900...0xfa6d, 0xfa70...0xfad9, 0xfb00...0xfb06, 0xfb13...0xfb17, 0xfb1d...0xfb1d, 0xfb1f...0xfb28, 0xfb2a...0xfb36, 0xfb38...0xfb3c, 0xfb3e...0xfb3e, 0xfb40...0xfb41, 0xfb43...0xfb44, 0xfb46...0xfbb1, 0xfbd3...0xfd3d, 0xfd50...0xfd8f, 0xfd92...0xfdc7, 0xfdf0...0xfdfb, 0xfe70...0xfe74, 0xfe76...0xfefc, 0xff21...0xff3a, 0xff41...0xff5a, 0xff66...0xffbe, 0xffc2...0xffc7, 0xffca...0xffcf, 0xffd2...0xffd7, 0xffda...0xffdc, 0x10000...0x1000b, 0x1000d...0x10026, 0x10028...0x1003a, 0x1003c...0x1003d, 0x1003f...0x1004d, 0x10050...0x1005d, 0x10080...0x100fa, 0x10140...0x10174, 0x10280...0x1029c, 0x102a0...0x102d0, 0x10300...0x1031f, 0x1032d...0x1034a, 0x10350...0x10375, 0x10380...0x1039d, 0x103a0...0x103c3, 0x103c8...0x103cf, 0x103d1...0x103d5, 0x10400...0x1049d, 0x104b0...0x104d3, 0x104d8...0x104fb, 0x10500...0x10527, 0x10530...0x10563, 0x10600...0x10736, 0x10740...0x10755, 0x10760...0x10767, 0x10800...0x10805, 0x10808...0x10808, 0x1080a...0x10835, 0x10837...0x10838, 0x1083c...0x1083c, 0x1083f...0x10855, 0x10860...0x10876, 0x10880...0x1089e, 0x108e0...0x108f2, 0x108f4...0x108f5, 0x10900...0x10915, 0x10920...0x10939, 0x10980...0x109b7, 0x109be...0x109bf, 0x10a00...0x10a00, 0x10a10...0x10a13, 0x10a15...0x10a17, 0x10a19...0x10a35, 0x10a60...0x10a7c, 0x10a80...0x10a9c, 0x10ac0...0x10ac7, 0x10ac9...0x10ae4, 0x10b00...0x10b35, 0x10b40...0x10b55, 0x10b60...0x10b72, 0x10b80...0x10b91, 0x10c00...0x10c48, 0x10c80...0x10cb2, 0x10cc0...0x10cf2, 0x10d00...0x10d23, 0x10e80...0x10ea9, 0x10eb0...0x10eb1, 0x10f00...0x10f1c, 0x10f27...0x10f27, 0x10f30...0x10f45, 0x10fb0...0x10fc4, 0x10fe0...0x10ff6, 0x11003...0x11037, 0x11083...0x110af, 0x110d0...0x110e8, 0x11103...0x11126, 0x11144...0x11144, 0x11147...0x11147, 0x11150...0x11172, 0x11176...0x11176, 0x11183...0x111b2, 0x111c1...0x111c4, 0x111da...0x111da, 0x111dc...0x111dc, 0x11200...0x11211, 0x11213...0x1122b, 0x11280...0x11286, 0x11288...0x11288, 0x1128a...0x1128d, 0x1128f...0x1129d, 0x1129f...0x112a8, 0x112b0...0x112de, 0x11305...0x1130c, 0x1130f...0x11310, 0x11313...0x11328, 0x1132a...0x11330, 0x11332...0x11333, 0x11335...0x11339, 0x1133d...0x1133d, 0x11350...0x11350, 0x1135d...0x11361, 0x11400...0x11434, 0x11447...0x1144a, 0x1145f...0x11461, 0x11480...0x114af, 0x114c4...0x114c5, 0x114c7...0x114c7, 0x11580...0x115ae, 0x115d8...0x115db, 0x11600...0x1162f, 0x11644...0x11644, 0x11680...0x116aa, 0x116b8...0x116b8, 0x11700...0x1171a, 0x11800...0x1182b, 0x118a0...0x118df, 0x118ff...0x11906, 0x11909...0x11909, 0x1190c...0x11913, 0x11915...0x11916, 0x11918...0x1192f, 0x1193f...0x1193f, 0x11941...0x11941, 0x119a0...0x119a7, 0x119aa...0x119d0, 0x119e1...0x119e1, 0x119e3...0x119e3, 0x11a00...0x11a00, 0x11a0b...0x11a32, 0x11a3a...0x11a3a, 0x11a50...0x11a50, 0x11a5c...0x11a89, 0x11a9d...0x11a9d, 0x11ac0...0x11af8, 0x11c00...0x11c08, 0x11c0a...0x11c2e, 0x11c40...0x11c40, 0x11c72...0x11c8f, 0x11d00...0x11d06, 0x11d08...0x11d09, 0x11d0b...0x11d30, 0x11d46...0x11d46, 0x11d60...0x11d65, 0x11d67...0x11d68, 0x11d6a...0x11d89, 0x11d98...0x11d98, 0x11ee0...0x11ef2, 0x11fb0...0x11fb0, 0x12000...0x12399, 0x12400...0x1246e, 0x12480...0x12543, 0x13000...0x1342e, 0x14400...0x14646, 0x16800...0x16a38, 0x16a40...0x16a5e, 0x16ad0...0x16aed, 0x16b00...0x16b2f, 0x16b40...0x16b43, 0x16b63...0x16b77, 0x16b7d...0x16b8f, 0x16e40...0x16e7f, 0x16f00...0x16f4a, 0x16f50...0x16f50, 0x16f93...0x16f9f, 0x16fe0...0x16fe1, 0x16fe3...0x16fe3, 0x17000...0x187f7, 0x18800...0x18cd5, 0x18d00...0x18d08, 0x1b000...0x1b11e, 0x1b150...0x1b152, 0x1b164...0x1b167, 0x1b170...0x1b2fb, 0x1bc00...0x1bc6a, 0x1bc70...0x1bc7c, 0x1bc80...0x1bc88, 0x1bc90...0x1bc99, 0x1d400...0x1d454, 0x1d456...0x1d49c, 0x1d49e...0x1d49f, 0x1d4a2...0x1d4a2, 0x1d4a5...0x1d4a6, 0x1d4a9...0x1d4ac, 0x1d4ae...0x1d4b9, 0x1d4bb...0x1d4bb, 0x1d4bd...0x1d4c3, 0x1d4c5...0x1d505, 0x1d507...0x1d50a, 0x1d50d...0x1d514, 0x1d516...0x1d51c, 0x1d51e...0x1d539, 0x1d53b...0x1d53e, 0x1d540...0x1d544, 0x1d546...0x1d546, 0x1d54a...0x1d550, 0x1d552...0x1d6a5, 0x1d6a8...0x1d6c0, 0x1d6c2...0x1d6da, 0x1d6dc...0x1d6fa, 0x1d6fc...0x1d714, 0x1d716...0x1d734, 0x1d736...0x1d74e, 0x1d750...0x1d76e, 0x1d770...0x1d788, 0x1d78a...0x1d7a8, 0x1d7aa...0x1d7c2, 0x1d7c4...0x1d7cb, 0x1e100...0x1e12c, 0x1e137...0x1e13d, 0x1e14e...0x1e14e, 0x1e2c0...0x1e2eb, 0x1e800...0x1e8c4, 0x1e900...0x1e943, 0x1e94b...0x1e94b, 0x1ee00...0x1ee03, 0x1ee05...0x1ee1f, 0x1ee21...0x1ee22, 0x1ee24...0x1ee24, 0x1ee27...0x1ee27, 0x1ee29...0x1ee32, 0x1ee34...0x1ee37, 0x1ee39...0x1ee39, 0x1ee3b...0x1ee3b, 0x1ee42...0x1ee42, 0x1ee47...0x1ee47, 0x1ee49...0x1ee49, 0x1ee4b...0x1ee4b, 0x1ee4d...0x1ee4f, 0x1ee51...0x1ee52, 0x1ee54...0x1ee54, 0x1ee57...0x1ee57, 0x1ee59...0x1ee59, 0x1ee5b...0x1ee5b, 0x1ee5d...0x1ee5d, 0x1ee5f...0x1ee5f, 0x1ee61...0x1ee62, 0x1ee64...0x1ee64, 0x1ee67...0x1ee6a, 0x1ee6c...0x1ee72, 0x1ee74...0x1ee77, 0x1ee79...0x1ee7c, 0x1ee7e...0x1ee7e, 0x1ee80...0x1ee89, 0x1ee8b...0x1ee9b, 0x1eea1...0x1eea3, 0x1eea5...0x1eea9, 0x1eeab...0x1eebb, 0x20000...0x2a6dd, 0x2a700...0x2b734, 0x2b740...0x2b81d, 0x2b820...0x2cea1, 0x2ceb0...0x2ebe0, 0x2f800...0x2fa1d, 0x30000...0x3134a => true, - else => false, - }, - }; - } - - pub inline fn isIdentifierPart(codepoint: i32) bool { - return switch (codepoint) { - 'A'...'Z', 'a'...'z', '0'...'9', '$', '_' => true, - else => switch (codepoint) { - 0x30...0x39, 0x41...0x5a, 0x5f...0x5f, 0x61...0x7a, 0xaa...0xaa, 0xb5...0xb5, 0xb7...0xb7, 0xba...0xba, 0xc0...0xd6, 0xd8...0xf6, 0xf8...0x2c1, 0x2c6...0x2d1, 0x2e0...0x2e4, 0x2ec...0x2ec, 0x2ee...0x2ee, 0x300...0x374, 0x376...0x377, 0x37a...0x37d, 0x37f...0x37f, 0x386...0x38a, 0x38c...0x38c, 0x38e...0x3a1, 0x3a3...0x3f5, 0x3f7...0x481, 0x483...0x487, 0x48a...0x52f, 0x531...0x556, 0x559...0x559, 0x560...0x588, 0x591...0x5bd, 0x5bf...0x5bf, 0x5c1...0x5c2, 0x5c4...0x5c5, 0x5c7...0x5c7, 0x5d0...0x5ea, 0x5ef...0x5f2, 0x610...0x61a, 0x620...0x669, 0x66e...0x6d3, 0x6d5...0x6dc, 0x6df...0x6e8, 0x6ea...0x6fc, 0x6ff...0x6ff, 0x710...0x74a, 0x74d...0x7b1, 0x7c0...0x7f5, 0x7fa...0x7fa, 0x7fd...0x7fd, 0x800...0x82d, 0x840...0x85b, 0x860...0x86a, 0x8a0...0x8b4, 0x8b6...0x8c7, 0x8d3...0x8e1, 0x8e3...0x963, 0x966...0x96f, 0x971...0x983, 0x985...0x98c, 0x98f...0x990, 0x993...0x9a8, 0x9aa...0x9b0, 0x9b2...0x9b2, 0x9b6...0x9b9, 0x9bc...0x9c4, 0x9c7...0x9c8, 0x9cb...0x9ce, 0x9d7...0x9d7, 0x9dc...0x9dd, 0x9df...0x9e3, 0x9e6...0x9f1, 0x9fc...0x9fc, 0x9fe...0x9fe, 0xa01...0xa03, 0xa05...0xa0a, 0xa0f...0xa10, 0xa13...0xa28, 0xa2a...0xa30, 0xa32...0xa33, 0xa35...0xa36, 0xa38...0xa39, 0xa3c...0xa3c, 0xa3e...0xa42, 0xa47...0xa48, 0xa4b...0xa4d, 0xa51...0xa51, 0xa59...0xa5c, 0xa5e...0xa5e, 0xa66...0xa75, 0xa81...0xa83, 0xa85...0xa8d, 0xa8f...0xa91, 0xa93...0xaa8, 0xaaa...0xab0, 0xab2...0xab3, 0xab5...0xab9, 0xabc...0xac5, 0xac7...0xac9, 0xacb...0xacd, 0xad0...0xad0, 0xae0...0xae3, 0xae6...0xaef, 0xaf9...0xaff, 0xb01...0xb03, 0xb05...0xb0c, 0xb0f...0xb10, 0xb13...0xb28, 0xb2a...0xb30, 0xb32...0xb33, 0xb35...0xb39, 0xb3c...0xb44, 0xb47...0xb48, 0xb4b...0xb4d, 0xb55...0xb57, 0xb5c...0xb5d, 0xb5f...0xb63, 0xb66...0xb6f, 0xb71...0xb71, 0xb82...0xb83, 0xb85...0xb8a, 0xb8e...0xb90, 0xb92...0xb95, 0xb99...0xb9a, 0xb9c...0xb9c, 0xb9e...0xb9f, 0xba3...0xba4, 0xba8...0xbaa, 0xbae...0xbb9, 0xbbe...0xbc2, 0xbc6...0xbc8, 0xbca...0xbcd, 0xbd0...0xbd0, 0xbd7...0xbd7, 0xbe6...0xbef, 0xc00...0xc0c, 0xc0e...0xc10, 0xc12...0xc28, 0xc2a...0xc39, 0xc3d...0xc44, 0xc46...0xc48, 0xc4a...0xc4d, 0xc55...0xc56, 0xc58...0xc5a, 0xc60...0xc63, 0xc66...0xc6f, 0xc80...0xc83, 0xc85...0xc8c, 0xc8e...0xc90, 0xc92...0xca8, 0xcaa...0xcb3, 0xcb5...0xcb9, 0xcbc...0xcc4, 0xcc6...0xcc8, 0xcca...0xccd, 0xcd5...0xcd6, 0xcde...0xcde, 0xce0...0xce3, 0xce6...0xcef, 0xcf1...0xcf2, 0xd00...0xd0c, 0xd0e...0xd10, 0xd12...0xd44, 0xd46...0xd48, 0xd4a...0xd4e, 0xd54...0xd57, 0xd5f...0xd63, 0xd66...0xd6f, 0xd7a...0xd7f, 0xd81...0xd83, 0xd85...0xd96, 0xd9a...0xdb1, 0xdb3...0xdbb, 0xdbd...0xdbd, 0xdc0...0xdc6, 0xdca...0xdca, 0xdcf...0xdd4, 0xdd6...0xdd6, 0xdd8...0xddf, 0xde6...0xdef, 0xdf2...0xdf3, 0xe01...0xe3a, 0xe40...0xe4e, 0xe50...0xe59, 0xe81...0xe82, 0xe84...0xe84, 0xe86...0xe8a, 0xe8c...0xea3, 0xea5...0xea5, 0xea7...0xebd, 0xec0...0xec4, 0xec6...0xec6, 0xec8...0xecd, 0xed0...0xed9, 0xedc...0xedf, 0xf00...0xf00, 0xf18...0xf19, 0xf20...0xf29, 0xf35...0xf35, 0xf37...0xf37, 0xf39...0xf39, 0xf3e...0xf47, 0xf49...0xf6c, 0xf71...0xf84, 0xf86...0xf97, 0xf99...0xfbc, 0xfc6...0xfc6, 0x1000...0x1049, 0x1050...0x109d, 0x10a0...0x10c5, 0x10c7...0x10c7, 0x10cd...0x10cd, 0x10d0...0x10fa, 0x10fc...0x1248, 0x124a...0x124d, 0x1250...0x1256, 0x1258...0x1258, 0x125a...0x125d, 0x1260...0x1288, 0x128a...0x128d, 0x1290...0x12b0, 0x12b2...0x12b5, 0x12b8...0x12be, 0x12c0...0x12c0, 0x12c2...0x12c5, 0x12c8...0x12d6, 0x12d8...0x1310, 0x1312...0x1315, 0x1318...0x135a, 0x135d...0x135f, 0x1369...0x1371, 0x1380...0x138f, 0x13a0...0x13f5, 0x13f8...0x13fd, 0x1401...0x166c, 0x166f...0x167f, 0x1681...0x169a, 0x16a0...0x16ea, 0x16ee...0x16f8, 0x1700...0x170c, 0x170e...0x1714, 0x1720...0x1734, 0x1740...0x1753, 0x1760...0x176c, 0x176e...0x1770, 0x1772...0x1773, 0x1780...0x17d3, 0x17d7...0x17d7, 0x17dc...0x17dd, 0x17e0...0x17e9, 0x180b...0x180d, 0x1810...0x1819, 0x1820...0x1878, 0x1880...0x18aa, 0x18b0...0x18f5, 0x1900...0x191e, 0x1920...0x192b, 0x1930...0x193b, 0x1946...0x196d, 0x1970...0x1974, 0x1980...0x19ab, 0x19b0...0x19c9, 0x19d0...0x19da, 0x1a00...0x1a1b, 0x1a20...0x1a5e, 0x1a60...0x1a7c, 0x1a7f...0x1a89, 0x1a90...0x1a99, 0x1aa7...0x1aa7, 0x1ab0...0x1abd, 0x1abf...0x1ac0, 0x1b00...0x1b4b, 0x1b50...0x1b59, 0x1b6b...0x1b73, 0x1b80...0x1bf3, 0x1c00...0x1c37, 0x1c40...0x1c49, 0x1c4d...0x1c7d, 0x1c80...0x1c88, 0x1c90...0x1cba, 0x1cbd...0x1cbf, 0x1cd0...0x1cd2, 0x1cd4...0x1cfa, 0x1d00...0x1df9, 0x1dfb...0x1f15, 0x1f18...0x1f1d, 0x1f20...0x1f45, 0x1f48...0x1f4d, 0x1f50...0x1f57, 0x1f59...0x1f59, 0x1f5b...0x1f5b, 0x1f5d...0x1f5d, 0x1f5f...0x1f7d, 0x1f80...0x1fb4, 0x1fb6...0x1fbc, 0x1fbe...0x1fbe, 0x1fc2...0x1fc4, 0x1fc6...0x1fcc, 0x1fd0...0x1fd3, 0x1fd6...0x1fdb, 0x1fe0...0x1fec, 0x1ff2...0x1ff4, 0x1ff6...0x1ffc, 0x203f...0x2040, 0x2054...0x2054, 0x2071...0x2071, 0x207f...0x207f, 0x2090...0x209c, 0x20d0...0x20dc, 0x20e1...0x20e1, 0x20e5...0x20f0, 0x2102...0x2102, 0x2107...0x2107, 0x210a...0x2113, 0x2115...0x2115, 0x2118...0x211d, 0x2124...0x2124, 0x2126...0x2126, 0x2128...0x2128, 0x212a...0x2139, 0x213c...0x213f, 0x2145...0x2149, 0x214e...0x214e, 0x2160...0x2188, 0x2c00...0x2c2e, 0x2c30...0x2c5e, 0x2c60...0x2ce4, 0x2ceb...0x2cf3, 0x2d00...0x2d25, 0x2d27...0x2d27, 0x2d2d...0x2d2d, 0x2d30...0x2d67, 0x2d6f...0x2d6f, 0x2d7f...0x2d96, 0x2da0...0x2da6, 0x2da8...0x2dae, 0x2db0...0x2db6, 0x2db8...0x2dbe, 0x2dc0...0x2dc6, 0x2dc8...0x2dce, 0x2dd0...0x2dd6, 0x2dd8...0x2dde, 0x2de0...0x2dff, 0x3005...0x3007, 0x3021...0x302f, 0x3031...0x3035, 0x3038...0x303c, 0x3041...0x3096, 0x3099...0x309f, 0x30a1...0x30ff, 0x3105...0x312f, 0x3131...0x318e, 0x31a0...0x31bf, 0x31f0...0x31ff, 0x3400...0x4dbf, 0x4e00...0x9ffc, 0xa000...0xa48c, 0xa4d0...0xa4fd, 0xa500...0xa60c, 0xa610...0xa62b, 0xa640...0xa66f, 0xa674...0xa67d, 0xa67f...0xa6f1, 0xa717...0xa71f, 0xa722...0xa788, 0xa78b...0xa7bf, 0xa7c2...0xa7ca, 0xa7f5...0xa827, 0xa82c...0xa82c, 0xa840...0xa873, 0xa880...0xa8c5, 0xa8d0...0xa8d9, 0xa8e0...0xa8f7, 0xa8fb...0xa8fb, 0xa8fd...0xa92d, 0xa930...0xa953, 0xa960...0xa97c, 0xa980...0xa9c0, 0xa9cf...0xa9d9, 0xa9e0...0xa9fe, 0xaa00...0xaa36, 0xaa40...0xaa4d, 0xaa50...0xaa59, 0xaa60...0xaa76, 0xaa7a...0xaac2, 0xaadb...0xaadd, 0xaae0...0xaaef, 0xaaf2...0xaaf6, 0xab01...0xab06, 0xab09...0xab0e, 0xab11...0xab16, 0xab20...0xab26, 0xab28...0xab2e, 0xab30...0xab5a, 0xab5c...0xab69, 0xab70...0xabea, 0xabec...0xabed, 0xabf0...0xabf9, 0xac00...0xd7a3, 0xd7b0...0xd7c6, 0xd7cb...0xd7fb, 0xf900...0xfa6d, 0xfa70...0xfad9, 0xfb00...0xfb06, 0xfb13...0xfb17, 0xfb1d...0xfb28, 0xfb2a...0xfb36, 0xfb38...0xfb3c, 0xfb3e...0xfb3e, 0xfb40...0xfb41, 0xfb43...0xfb44, 0xfb46...0xfbb1, 0xfbd3...0xfd3d, 0xfd50...0xfd8f, 0xfd92...0xfdc7, 0xfdf0...0xfdfb, 0xfe00...0xfe0f, 0xfe20...0xfe2f, 0xfe33...0xfe34, 0xfe4d...0xfe4f, 0xfe70...0xfe74, 0xfe76...0xfefc, 0xff10...0xff19, 0xff21...0xff3a, 0xff3f...0xff3f, 0xff41...0xff5a, 0xff65...0xffbe, 0xffc2...0xffc7, 0xffca...0xffcf, 0xffd2...0xffd7, 0xffda...0xffdc, 0x10000...0x1000b, 0x1000d...0x10026, 0x10028...0x1003a, 0x1003c...0x1003d, 0x1003f...0x1004d, 0x10050...0x1005d, 0x10080...0x100fa, 0x10140...0x10174, 0x101fd...0x101fd, 0x10280...0x1029c, 0x102a0...0x102d0, 0x102e0...0x102e0, 0x10300...0x1031f, 0x1032d...0x1034a, 0x10350...0x1037a, 0x10380...0x1039d, 0x103a0...0x103c3, 0x103c8...0x103cf, 0x103d1...0x103d5, 0x10400...0x1049d, 0x104a0...0x104a9, 0x104b0...0x104d3, 0x104d8...0x104fb, 0x10500...0x10527, 0x10530...0x10563, 0x10600...0x10736, 0x10740...0x10755, 0x10760...0x10767, 0x10800...0x10805, 0x10808...0x10808, 0x1080a...0x10835, 0x10837...0x10838, 0x1083c...0x1083c, 0x1083f...0x10855, 0x10860...0x10876, 0x10880...0x1089e, 0x108e0...0x108f2, 0x108f4...0x108f5, 0x10900...0x10915, 0x10920...0x10939, 0x10980...0x109b7, 0x109be...0x109bf, 0x10a00...0x10a03, 0x10a05...0x10a06, 0x10a0c...0x10a13, 0x10a15...0x10a17, 0x10a19...0x10a35, 0x10a38...0x10a3a, 0x10a3f...0x10a3f, 0x10a60...0x10a7c, 0x10a80...0x10a9c, 0x10ac0...0x10ac7, 0x10ac9...0x10ae6, 0x10b00...0x10b35, 0x10b40...0x10b55, 0x10b60...0x10b72, 0x10b80...0x10b91, 0x10c00...0x10c48, 0x10c80...0x10cb2, 0x10cc0...0x10cf2, 0x10d00...0x10d27, 0x10d30...0x10d39, 0x10e80...0x10ea9, 0x10eab...0x10eac, 0x10eb0...0x10eb1, 0x10f00...0x10f1c, 0x10f27...0x10f27, 0x10f30...0x10f50, 0x10fb0...0x10fc4, 0x10fe0...0x10ff6, 0x11000...0x11046, 0x11066...0x1106f, 0x1107f...0x110ba, 0x110d0...0x110e8, 0x110f0...0x110f9, 0x11100...0x11134, 0x11136...0x1113f, 0x11144...0x11147, 0x11150...0x11173, 0x11176...0x11176, 0x11180...0x111c4, 0x111c9...0x111cc, 0x111ce...0x111da, 0x111dc...0x111dc, 0x11200...0x11211, 0x11213...0x11237, 0x1123e...0x1123e, 0x11280...0x11286, 0x11288...0x11288, 0x1128a...0x1128d, 0x1128f...0x1129d, 0x1129f...0x112a8, 0x112b0...0x112ea, 0x112f0...0x112f9, 0x11300...0x11303, 0x11305...0x1130c, 0x1130f...0x11310, 0x11313...0x11328, 0x1132a...0x11330, 0x11332...0x11333, 0x11335...0x11339, 0x1133b...0x11344, 0x11347...0x11348, 0x1134b...0x1134d, 0x11350...0x11350, 0x11357...0x11357, 0x1135d...0x11363, 0x11366...0x1136c, 0x11370...0x11374, 0x11400...0x1144a, 0x11450...0x11459, 0x1145e...0x11461, 0x11480...0x114c5, 0x114c7...0x114c7, 0x114d0...0x114d9, 0x11580...0x115b5, 0x115b8...0x115c0, 0x115d8...0x115dd, 0x11600...0x11640, 0x11644...0x11644, 0x11650...0x11659, 0x11680...0x116b8, 0x116c0...0x116c9, 0x11700...0x1171a, 0x1171d...0x1172b, 0x11730...0x11739, 0x11800...0x1183a, 0x118a0...0x118e9, 0x118ff...0x11906, 0x11909...0x11909, 0x1190c...0x11913, 0x11915...0x11916, 0x11918...0x11935, 0x11937...0x11938, 0x1193b...0x11943, 0x11950...0x11959, 0x119a0...0x119a7, 0x119aa...0x119d7, 0x119da...0x119e1, 0x119e3...0x119e4, 0x11a00...0x11a3e, 0x11a47...0x11a47, 0x11a50...0x11a99, 0x11a9d...0x11a9d, 0x11ac0...0x11af8, 0x11c00...0x11c08, 0x11c0a...0x11c36, 0x11c38...0x11c40, 0x11c50...0x11c59, 0x11c72...0x11c8f, 0x11c92...0x11ca7, 0x11ca9...0x11cb6, 0x11d00...0x11d06, 0x11d08...0x11d09, 0x11d0b...0x11d36, 0x11d3a...0x11d3a, 0x11d3c...0x11d3d, 0x11d3f...0x11d47, 0x11d50...0x11d59, 0x11d60...0x11d65, 0x11d67...0x11d68, 0x11d6a...0x11d8e, 0x11d90...0x11d91, 0x11d93...0x11d98, 0x11da0...0x11da9, 0x11ee0...0x11ef6, 0x11fb0...0x11fb0, 0x12000...0x12399, 0x12400...0x1246e, 0x12480...0x12543, 0x13000...0x1342e, 0x14400...0x14646, 0x16800...0x16a38, 0x16a40...0x16a5e, 0x16a60...0x16a69, 0x16ad0...0x16aed, 0x16af0...0x16af4, 0x16b00...0x16b36, 0x16b40...0x16b43, 0x16b50...0x16b59, 0x16b63...0x16b77, 0x16b7d...0x16b8f, 0x16e40...0x16e7f, 0x16f00...0x16f4a, 0x16f4f...0x16f87, 0x16f8f...0x16f9f, 0x16fe0...0x16fe1, 0x16fe3...0x16fe4, 0x16ff0...0x16ff1, 0x17000...0x187f7, 0x18800...0x18cd5, 0x18d00...0x18d08, 0x1b000...0x1b11e, 0x1b150...0x1b152, 0x1b164...0x1b167, 0x1b170...0x1b2fb, 0x1bc00...0x1bc6a, 0x1bc70...0x1bc7c, 0x1bc80...0x1bc88, 0x1bc90...0x1bc99, 0x1bc9d...0x1bc9e, 0x1d165...0x1d169, 0x1d16d...0x1d172, 0x1d17b...0x1d182, 0x1d185...0x1d18b, 0x1d1aa...0x1d1ad, 0x1d242...0x1d244, 0x1d400...0x1d454, 0x1d456...0x1d49c, 0x1d49e...0x1d49f, 0x1d4a2...0x1d4a2, 0x1d4a5...0x1d4a6, 0x1d4a9...0x1d4ac, 0x1d4ae...0x1d4b9, 0x1d4bb...0x1d4bb, 0x1d4bd...0x1d4c3, 0x1d4c5...0x1d505, 0x1d507...0x1d50a, 0x1d50d...0x1d514, 0x1d516...0x1d51c, 0x1d51e...0x1d539, 0x1d53b...0x1d53e, 0x1d540...0x1d544, 0x1d546...0x1d546, 0x1d54a...0x1d550, 0x1d552...0x1d6a5, 0x1d6a8...0x1d6c0, 0x1d6c2...0x1d6da, 0x1d6dc...0x1d6fa, 0x1d6fc...0x1d714, 0x1d716...0x1d734, 0x1d736...0x1d74e, 0x1d750...0x1d76e, 0x1d770...0x1d788, 0x1d78a...0x1d7a8, 0x1d7aa...0x1d7c2, 0x1d7c4...0x1d7cb, 0x1d7ce...0x1d7ff, 0x1da00...0x1da36, 0x1da3b...0x1da6c, 0x1da75...0x1da75, 0x1da84...0x1da84, 0x1da9b...0x1da9f, 0x1daa1...0x1daaf, 0x1e000...0x1e006, 0x1e008...0x1e018, 0x1e01b...0x1e021, 0x1e023...0x1e024, 0x1e026...0x1e02a, 0x1e100...0x1e12c, 0x1e130...0x1e13d, 0x1e140...0x1e149, 0x1e14e...0x1e14e, 0x1e2c0...0x1e2f9, 0x1e800...0x1e8c4, 0x1e8d0...0x1e8d6, 0x1e900...0x1e94b, 0x1e950...0x1e959, 0x1ee00...0x1ee03, 0x1ee05...0x1ee1f, 0x1ee21...0x1ee22, 0x1ee24...0x1ee24, 0x1ee27...0x1ee27, 0x1ee29...0x1ee32, 0x1ee34...0x1ee37, 0x1ee39...0x1ee39, 0x1ee3b...0x1ee3b, 0x1ee42...0x1ee42, 0x1ee47...0x1ee47, 0x1ee49...0x1ee49, 0x1ee4b...0x1ee4b, 0x1ee4d...0x1ee4f, 0x1ee51...0x1ee52, 0x1ee54...0x1ee54, 0x1ee57...0x1ee57, 0x1ee59...0x1ee59, 0x1ee5b...0x1ee5b, 0x1ee5d...0x1ee5d, 0x1ee5f...0x1ee5f, 0x1ee61...0x1ee62, 0x1ee64...0x1ee64, 0x1ee67...0x1ee6a, 0x1ee6c...0x1ee72, 0x1ee74...0x1ee77, 0x1ee79...0x1ee7c, 0x1ee7e...0x1ee7e, 0x1ee80...0x1ee89, 0x1ee8b...0x1ee9b, 0x1eea1...0x1eea3, 0x1eea5...0x1eea9, 0x1eeab...0x1eebb, 0x1fbf0...0x1fbf9, 0x20000...0x2a6dd, 0x2a700...0x2b734, 0x2b740...0x2b81d, 0x2b820...0x2cea1, 0x2ceb0...0x2ebe0, 0x2f800...0x2fa1d, 0x30000...0x3134a, 0xe0100...0xe01ef => true, - else => false, - }, - }; - } +/// isIDStartESNext checks if a codepoint is valid in the isIDStartESNext category +pub fn isIDStartESNext(cp: u21) bool { + const high = cp >> 8; + const low = cp & 0xFF; + const stage2_idx = idStartESNext.stage1[high]; + const bit_pos = stage2_idx + low; + const u64_idx = bit_pos >> 6; + const bit_idx = @as(u6, @intCast(bit_pos & 63)); + return (idStartESNext.stage2[u64_idx] & (@as(u64, 1) << bit_idx)) != 0; +} +const idStartESNext = struct { + pub const stage1 = [_]u16{ 0, 256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, 4096, 256, 4352, 4608, 4864, 256, 5120, 5376, 5632, 5888, 6144, 6400, 6656, 6912, 256, 7168, 7424, 7680, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 8192, 8448, 7936, 7936, 8704, 8960, 7936, 7936, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 6912, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 9216, 256, 9472, 9728, 9984, 10240, 10496, 10752, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 11008, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 256, 11264, 11520, 256, 11776, 12032, 12288, 12544, 12800, 13056, 13312, 13568, 13824, 256, 14080, 14336, 14592, 14848, 15104, 15360, 15616, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 17664, 17920, 18176, 18432, 18688, 18944, 7936, 19200, 19456, 19712, 19968, 256, 256, 256, 20224, 20480, 20736, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 20992, 256, 256, 256, 256, 21248, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 256, 256, 21504, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 256, 256, 21760, 22016, 7936, 7936, 22272, 22528, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 22784, 256, 256, 256, 256, 23040, 23296, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 23552, 256, 23808, 24064, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 24320, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 24576, 24832, 25088, 25344, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 25600, 25856, 26112, 26368, 7936, 26624, 7936, 7936, 26880, 27136, 27392, 7936, 7936, 7936, 7936, 27648, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 27904, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 28160, 28416, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 28672, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 28928, 256, 256, 29184, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 256, 256, 29440, 7936, 7936, 7936, 7936, 7936, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 29696, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 29952, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936, 7936 }; + pub const stage2 = [_]u64{ 0, 576460743847706622, 297241973452963840, 18410715276682199039, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 88094074470339, 0, 13609596598936928256, 18446744056529672000, 18428729675200069631, 18446744073709551615, 18446744073709551615, 18446744073709550595, 18446744073709551615, 18446462598732840959, 18446744069456527359, 511, 2119858418286592, 18446744069414584320, 18446392229988665343, 18446744073709551615, 11241196188469297151, 281474976514048, 18446744073709543424, 563224831328255, 301749971126844416, 1168302407679, 18446471390564450303, 18446744069414616831, 1023, 2594073385365405680, 18446181140919287808, 2577745637692514273, 1153765945374687232, 247132830528276448, 7881300924956672, 2589004636761079776, 144115200960823296, 2589004636760940512, 562965791113216, 288167810662516712, 65536, 2594071186342010848, 13539213312, 2589567586714640353, 1688864355778560, 2882303761516978160, 18158513712597581824, 3457638613854978016, 127, 3940649673949182, 127, 2309783315290257366, 4026531935, 1, 35184372088575, 7936, 0, 9223380832947798015, 18438229877581611008, 18446744069414600707, 17870283321406070975, 18446744073709551615, 18446744070446333439, 9168765891372858879, 18446744073701162813, 18446744073696837631, 134217727, 18446744069414649855, 4557642822898941951, 18446744073709551614, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446638520593285119, 18446744069548802046, 144053615424700415, 1125897759621119, 527761286627327, 4503599627370495, 276824064, 18446744069414584320, 144115188075855871, 18446469195802607615, 18014398509481983, 2147483647, 8796093022142464, 18446480190918885375, 1023, 18446744069422972927, 2097151, 549755813888, 0, 4503599627370464, 8160, 18158724812380307448, 274877906943, 68719476735, 4611686018360336384, 16717361816799216127, 319718190147960832, 18446744073709551615, 18446744073709551615, 18446744073709551615, 0, 18446744070475743231, 4611686017001275199, 6908521828386340863, 2295745090394464220, 0, 9223934986808197120, 536805376, 0, 17582049991377026180, 18446744069414601696, 511, 0, 0, 0, 0, 0, 18446744073709551615, 18446744073709551615, 18446744073709551615, 3509778554814463, 18446498607738650623, 141836999983103, 9187201948305063935, 2139062143, 2251241253188403424, 18446744073709551614, 18446744069288755199, 17870283321406128127, 18446462598732840928, 18446744073709551615, 18446744069414617087, 18446462598732840960, 18446744073709551615, 18446744073709551615, 8191, 4611686018427322368, 13198434443263, 9223512774343131135, 18446744070488326143, 281474976710655, 18446744060816261120, 18446744073709551615, 18446744073709550079, 18445618173868443647, 34359736251, 4503599627370495, 4503599627370492, 7564921474075590656, 18446462873610746880, 2305843004918726783, 2251799813685232, 8935422993945886720, 2199023255551, 14159317224157876215, 4495436853045886975, 7890092085477381, 18446602782178705022, 18446466996645134335, 18446744073709551615, 34359738367, 18446744073709551615, 18446744073709551615, 18446462667452317695, 1152921504606845055, 18446744073709551615, 18446532967477018623, 18446744073709551615, 67108863, 6881498030004502655, 18446744073709551579, 1125899906842623, 18446744073709027328, 4611686018427387903, 18446744073709486080, 18446744073709355007, 1152640029630136575, 0, 18437455399478099968, 18446744073709551615, 2305843009213693951, 576460743713488896, 18446743798965862398, 9223372036854775807, 486341884, 13258596753222922239, 1073692671, 18446744073709551615, 576460752303423487, 0, 9007199254740991, 0, 0, 0, 0, 18446744069951455231, 131071, 18446708893632430079, 18014398509418495, 18446744070488326143, 4128527, 18446744073709551615, 18446744073709551615, 18446462599806582783, 1152921504591118335, 18446463698244468735, 17870001915148894207, 2016486715970549759, 0, 36028797018963967, 1095220854783, 575897802350002111, 0, 10502394331027995967, 36028792728190975, 2147483647, 15762594400829440, 288230371860938751, 0, 13907115649320091647, 0, 18014398491590657, 2305843004918726656, 536870911, 137438953215, 18014398509481983, 2251795522912255, 262143, 0, 18446744073709551615, 511, 2251799813685247, 2251799813685247, 68719476735, 0, 0, 0, 0, 0, 848822976643071, 0, 18446463149025525759, 18446462598732841023, 18446462598732840963, 36028792723996703, 72057594037927928, 10696049115004928, 281474976710648, 2199023190016, 549755813880, 20266198323101840, 2251799813685240, 335544350, 9223389629040558079, 1, 18446464796682337663, 2147483647, 2589004636760940512, 16643063808, 0, 0, 9007199254740991, 15032387456, 281474976710655, 176, 0, 0, 140737488355327, 251658240, 281474976710655, 16, 72066390130950143, 0, 134217727, 127, 0, 0, 17592186044415, 0, 18446744069414584320, 9223372041149743103, 9223653511822045823, 2, 18446740770879700992, 42949804031, 290482175965394945, 18446744073441181696, 18446462599269712895, 144115188075855871, 140737488354815, 18445618173802708993, 65535, 0, 562949953420159, 18446741595513421888, 16778239, 0, 0, 0, 0, 2251795518717952, 4503599627239412, 0, 281474976710656, 0, 18446744073709551615, 18446744073709551615, 67108863, 0, 18446744073709551615, 140737488355327, 18446744073709551615, 18446744073709551615, 18446744073709551615, 15, 0, 0, 0, 0, 18446744073709486080, 562949953421311, 281474976710655, 126, 0, 0, 18446744073709551615, 127, 0, 0, 144115188075855871, 18446462600880324607, 9223372036854775807, 70368744112128, 281474976710655, 16212958624174047247, 65535, 0, 0, 18446744073709551615, 0, 0, 18446744073709551615, 67583, 4294443008, 47244640256, 18446744073709551615, 18446744073709551615, 18446744073709551615, 72057594037927935, 18446744073709551615, 18446744073709551615, 18446744073709551615, 4194303, 511, 0, 0, 0, 0, 0, 0, 8065665457643847680, 1125934266580991, 18446463629527547904, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 1152921504606846975, 18446744073709551615, 2305570330330005503, 67043839, 0, 18446744073709551615, 18446744073707454463, 17005555242810474495, 18446744073709551599, 8935141660164089791, 18446744073709419615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446743249075830783, 17870283321271910397, 18437736874452713471, 18446603336221163519, 18446741874686295551, 4087, 8660801552383, 0, 0, 0, 18446462598732840960, 70368744177663, 0, 0, 4575692405780512767, 16384, 0, 0, 0, 0, 70368744112128, 17592186044415, 0, 0, 0, 17592185978880, 0, 0, 0, 9223213153129594880, 18446744073709551615, 18446744073709551615, 18446744073709551615, 31, 18446744073709551615, 2063, 0, 0, 790380184120328175, 6843210385291930244, 1152917029519358975, 0, 18446744073709551615, 18446744073709551615, 18446744073709551615, 4294967295, 288230376151711743, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744070488326143, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446462615912710143, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446462607322775551, 18446744073709551615, 1073741823, 0, 0, 1073741823, 0, 0, 0, 18446744073709551615, 18446744073709488127, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 281474976710655, 0 }; }; -// // ----- The benchmark ------ - -// const std = @import("std"); - -// const part_codepoints_slice: []const i32 = &start_codepoints; -// const start_codepoints_slice: []const i32 = &part_codepoints; - -// pub const HashTable = struct { -// var starts: std.AutoHashMap(i32, void) = undefined; -// var parts: std.AutoHashMap(i32, void) = undefined; - -// pub fn isIdentifierStart(codepoint: i32) bool { -// if (codepoint > 255) return starts.contains(codepoint); -// return switch (codepoint) { -// 'A'...'Z', 'a'...'z', '$', '_' => true, -// else => false, -// }; -// } - -// pub fn isIdentifierPart(codepoint: i32) bool { -// if (codepoint > 255) return parts.contains(codepoint); -// return switch (codepoint) { -// 'A'...'Z', 'a'...'z', '0'...'9', '$', '_' => true, -// else => false, -// }; -// } - -// pub fn init(allocator: std.mem.Allocator) !void { -// starts = std.AutoHashMap(i32, void).init(allocator); -// parts = std.AutoHashMap(i32, void).init(allocator); - -// var i: i32 = 0; -// var j: i32 = 0; - -// while (i < start_codepoints.len) : (i += 2) { -// j = start_codepoints[i]; -// while (j <= start_codepoints[i + 1]) : (j += 1) { -// try starts.put(j, {}); -// } -// } -// i = 0; -// while (i < part_codepoints.len) : (i += 2) { -// j = part_codepoints[i]; -// while (j <= part_codepoints[i + 1]) : (j += 1) { -// try parts.put(j, {}); -// } -// } -// } -// }; - -// pub const BinarySearch = struct { - -// // "lookupInUnicodeMap" in TypeScript -// // esbuild does something similar -// fn search(comptime map: []const i32, code: i32) bool { -// // Bail out quickly if it couldn't possibly be in the map. -// if (code < map[0]) { -// return false; -// } - -// // Perform binary search in one of the Unicode range maps -// var lo: i32 = 0; -// var hi: i32 = map.len; -// var mid: i32 = undefined; - -// while (lo + 1 < hi) { -// mid = lo + (hi - lo) / 2; -// // mid has to be even to catch a range's beginning -// mid -= mid % 2; -// if (map[mid] <= code and code <= map[mid + 1]) { -// return true; -// } -// if (code < map[mid]) { -// hi = mid; -// } else { -// lo = mid + 2; -// } -// } - -// return false; -// } - -// // https://source.chromium.org/chromium/v8/v8.git/+/master:src/strings/char-predicates-inl.h;l=133 -// pub fn isIdentifierStart(codepoint: i32) bool { -// if (codepoint > 255) return search(start_codepoints_slice, codepoint); -// return switch (codepoint) { -// 'A'...'Z', 'a'...'z', '$', '_' => true, -// else => false, -// }; -// } - -// pub fn isIdentifierPart(codepoint: i32) bool { -// if (codepoint > 255) return search(part_codepoints_slice, codepoint); -// return switch (codepoint) { -// 'A'...'Z', 'a'...'z', '0'...'9', '$', '_' => true, -// else => false, -// }; -// } -// }; - -// const unicode_text: []const u8 = -// \\ -// \\_a["" + "constructor"] = 133 /* ConstructorKeyword */, -// \\_a.debugger = 87 /* DebuggerKeyword */, -// \\_a.declare = 134 /* DeclareKeyword */, -// \\_a.default = 88 /* DefaultKeyword */, -// \\_a.delete = 89 /* DeleteKeyword */, -// \\_a.do = 90 /* DoKeyword */, -// \\_a.else = 91 /* ElseKeyword */, -// \\_a.enum = 92 /* EnumKeyword */, -// \\_a.export = 93 /* ExportKeyword */, -// \\_a.extends = 94 /* ExtendsKeyword */, -// \\_a.false = 95 /* FalseKeyword */, -// \\_a.finally = 96 /* FinallyKeyword */, -// \\_a.for = 97 /* ForKeyword */, -// \\_a.from = 154 /* FromKeyword */, -// \\_a.function = 98 /* FunctionKeyword */, -// \\_a.get = 135 /* GetKeyword */, -// \\_a.if = 99 /* IfKeyword */, -// \\_a.implements = 117 /* ImplementsKeyword */, -// \\_a.import = 100 /* ImportKeyword */, -// \\_a.in = 101 /* InKeyword */, -// \\_a.infer = 136 /* InferKeyword */, -// \\_a.instanceof = 102 /* InstanceOfKeyword */, -// \\_a.interface = 118 /* InterfaceKeyword */, -// \\_a.intrinsic = 137 /* IntrinsicKeyword */, -// \\_a.is = 138 /* IsKeyword */, -// \\_a.keyof = 139 /* KeyOfKeyword */, -// \\_a.let = 119 /* LetKeyword */, -// \\_a.module = 140 /* ModuleKeyword */, -// \\_a.namespace = 141 /* NamespaceKeyword */, -// \\_a.never = 142 /* NeverKeyword */, -// \\_a.new = 103 /* NewKeyword */, -// \\_a.null = 104 /* NullKeyword */, -// \\_a.number = 145 /* NumberKeyword */, -// \\_a.object = 146 /* ObjectKeyword */, -// \\_a.package = 120 /* PackageKeyword */, -// \\_a.private = 121 /* PrivateKeyword */, -// \\_a.protected = 122 /* ProtectedKeyword */, -// \\_a.public = 123 /* PublicKeyword */, -// \\_a.override = 157 /* OverrideKeyword */, -// \\_a.readonly = 143 /* ReadonlyKeyword */, -// \\_a.require = 144 /* RequireKeyword */, -// \\_a.global = 155 /* GlobalKeyword */, -// \\_a.return = 105 /* ReturnKeyword */, -// \\_a.set = 147 /* SetKeyword */, -// \\_a.static = 124 /* StaticKeyword */, -// \\_a.string = 148 /* StringKeyword */, -// \\_a.super = 106 /* SuperKeyword */, -// \\_a.switch = 107 /* SwitchKeyword */, -// \\_a.symbol = 149 /* SymbolKeyword */, -// \\_a.this = 108 /* ThisKeyword */, -// \\_a.throw = 109 /* ThrowKeyword */, -// \\_a.true = 110 /* TrueKeyword */, -// \\_a.try = 111 /* TryKeyword */, -// \\_a.type = 150 /* TypeKeyword */, -// \\_a.typeof = 112 /* TypeOfKeyword */, -// \\_a.undefined = 151 /* UndefinedKeyword */, -// \\_a.unique = 152 /* UniqueKeyword */, -// \\_a.unknown = 153 /* UnknownKeyword */, -// \\_a.var = 113 /* VarKeyword */, -// \\_a.void = 114 /* VoidKeyword */, -// \\_a.while = 115 /* WhileKeyword */, -// \\_a.with = 116 /* WithKeyword */, -// \\_a.yield = 125 /* YieldKeyword */, -// \\_a.async = 130 /* AsyncKeyword */, -// \\_a.await = 131 /* AwaitKeyword */, -// \\_a.of = 158 /* OfKeyword */, -// \\_a); -// \\var textToKeyword = new ts.Map(ts.getEntries(ts.textToKeywordObj)); -// \\var textToToken = new ts.Map(ts.getEntries(__assign(__assign({}, ts.textToKeywordObj), { "{": 18 /* OpenBraceToken */, "}": 19 /* CloseBraceToken */, "(": 20 /* OpenParenToken */, ")": 21 /* CloseParenToken */, "[": 22 /* OpenBracketToken */, "]": 23 /* CloseBracketToken */, ".": 24 /* DotToken */, "...": 25 /* DotDotDotToken */, ";": 26 /* SemicolonToken */, ",": 27 /* CommaToken */, "<": 29 /* LessThanToken */, ">": 31 /* GreaterThanToken */, "<=": 32 /* LessThanEqualsToken */, ">=": 33 /* GreaterThanEqualsToken */, "==": 34 /* EqualsEqualsToken */, "!=": 35 /* ExclamationEqualsToken */, "===": 36 /* EqualsEqualsEqualsToken */, "!==": 37 /* ExclamationEqualsEqualsToken */, "=>": 38 /* EqualsGreaterThanToken */, "+": 39 /* PlusToken */, "-": 40 /* MinusToken */, "**": 42 /* AsteriskAsteriskToken */, "*": 41 /* AsteriskToken */, "/": 43 /* SlashToken */, "%": 44 /* PercentToken */, "++": 45 /* PlusPlusToken */, "--": 46 /* MinusMinusToken */, "<<": 47 /* LessThanLessThanToken */, ">": 48 /* GreaterThanGreaterThanToken */, ">>>": 49 /* GreaterThanGreaterThanGreaterThanToken */, "&": 50 /* AmpersandToken */, "|": 51 /* BarToken */, "^": 52 /* CaretToken */, "!": 53 /* ExclamationToken */, "~": 54 /* TildeToken */, "&&": 55 /* AmpersandAmpersandToken */, "||": 56 /* BarBarToken */, "?": 57 /* QuestionToken */, "??": 60 /* QuestionQuestionToken */, "?.": 28 /* QuestionDotToken */, ":": 58 /* ColonToken */, "=": 63 /* EqualsToken */, "+=": 64 /* PlusEqualsToken */, "-=": 65 /* MinusEqualsToken */, "*=": 66 /* AsteriskEqualsToken */, "**=": 67 /* AsteriskAsteriskEqualsToken */, "/=": 68 /* SlashEqualsToken */, "%=": 69 /* PercentEqualsToken */, "<<=": 70 /* LessThanLessThanEqualsToken */, ">>=": 71 /* GreaterThanGreaterThanEqualsToken */, ">>>=": 72 /* GreaterThanGreaterThanGreaterThanEqualsToken */, "&=": 73 /* AmpersandEqualsToken */, "|=": 74 /* BarEqualsToken */, "^=": 78 /* CaretEqualsToken */, "||=": 75 /* BarBarEqualsToken */, "&&=": 76 /* AmpersandAmpersandEqualsToken */, "??=": 77 /* QuestionQuestionEqualsToken */, "@": 59 /* AtToken */, "#": 62 /* HashToken */, "`": 61 /* BacktickToken */ }))); -// \\/* -// \\As per ECMAScript Language Specification 3th Edition, Section 7.6: Identifiers -// \\IdentifierStart :: -// \\Can contain Unicode 3.0.0 categories: -// \\Uppercase letter (Lu), -// \\Lowercase letter (Ll), -// \\Titlecase letter (Lt), -// \\Modifier letter (Lm), -// \\Other letter (Lo), or -// \\Letter number (Nl). -// \\IdentifierPart :: = -// \\Can contain IdentifierStart + Unicode 3.0.0 categories: -// \\Non-spacing mark (Mn), -// \\Combining spacing mark (Mc), -// \\Decimal number (Nd), or -// \\Connector punctuation (Pc). -// \\ -// \\Codepoint ranges for ES3 Identifiers are extracted from the Unicode 3.0.0 specification at: -// \\http://www.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.txt -// \\*/ -// \\var unicodeES3IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1610, 1649, 1747, 1749, 1749, 1765, 1766, 1786, 1788, 1808, 1808, 1810, 1836, 1920, 1957, 2309, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2784, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3294, 3294, 3296, 3297, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3424, 3425, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, 3840, 3840, 3904, 3911, 3913, 3946, 3976, 3979, 4096, 4129, 4131, 4135, 4137, 4138, 4176, 4181, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6067, 6176, 6263, 6272, 6312, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8319, 8319, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12346, 12353, 12436, 12445, 12446, 12449, 12538, 12540, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65138, 65140, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500,]; -// \\var unicodeES3IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 768, 846, 864, 866, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1155, 1158, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1441, 1443, 1465, 1467, 1469, 1471, 1471, 1473, 1474, 1476, 1476, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1621, 1632, 1641, 1648, 1747, 1749, 1756, 1759, 1768, 1770, 1773, 1776, 1788, 1808, 1836, 1840, 1866, 1920, 1968, 2305, 2307, 2309, 2361, 2364, 2381, 2384, 2388, 2392, 2403, 2406, 2415, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2492, 2494, 2500, 2503, 2504, 2507, 2509, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2562, 2562, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2649, 2652, 2654, 2654, 2662, 2676, 2689, 2691, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2784, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2876, 2883, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2913, 2918, 2927, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3031, 3031, 3047, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3134, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3168, 3169, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3262, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3297, 3302, 3311, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3390, 3395, 3398, 3400, 3402, 3405, 3415, 3415, 3424, 3425, 3430, 3439, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3805, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3946, 3953, 3972, 3974, 3979, 3984, 3991, 3993, 4028, 4038, 4038, 4096, 4129, 4131, 4135, 4137, 4138, 4140, 4146, 4150, 4153, 4160, 4169, 4176, 4185, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 4969, 4977, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6099, 6112, 6121, 6160, 6169, 6176, 6263, 6272, 6313, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8319, 8319, 8400, 8412, 8417, 8417, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12346, 12353, 12436, 12441, 12442, 12445, 12446, 12449, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65056, 65059, 65075, 65076, 65101, 65103, 65136, 65138, 65140, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500,]; -// \\/* -// \\As per ECMAScript Language Specification 5th Edition, Section 7.6: ISyntaxToken Names and Identifiers -// \\IdentifierStart :: -// \\Can contain Unicode 6.2 categories: -// \\Uppercase letter (Lu), -// \\Lowercase letter (Ll), -// \\Titlecase letter (Lt), -// \\Modifier letter (Lm), -// \\Other letter (Lo), or -// \\Letter number (Nl). -// \\IdentifierPart ::㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ -// \\Can contain IdentifierStart + Unicode 6.2 categories: -// \\Non-spacing mark (Mn), -// \\Combining spacing mark (Mc), -// \\Decimal number (Nd), -// \\Connector punctuation (Pc), -// \\, or -// \\. -// \\ -// \\Codepoint ranges for ES5 Identifiers are extracted from the Unicode 6.2 specification at: -// \\http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt -// \\*/ -// \\var unicodeES5IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2208, 2208, 2210, 2220, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, 7413, 7414, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500,]; -// \\var unicodeES5IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1520, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2048, 2093, 2112, 2139, 2208, 2208, 2210, 2220, 2276, 2302, 2304, 2403, 2406, 2415, 2417, 2423, 2425, 2431, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3161, 3168, 3171, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3396, 3398, 3400, 3402, 3406, 3415, 3415, 3424, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6263, 6272, 6314, 6320, 6389, 6400, 6428, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6617, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7376, 7378, 7380, 7414, 7424, 7654, 7676, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 11823, 11823, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12442, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42647, 42655, 42737, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43047, 43072, 43123, 43136, 43204, 43216, 43225, 43232, 43255, 43259, 43259, 43264, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43643, 43648, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65062, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500,]; -// \\/** -// \\* Generated by scripts/regenerate-unicode-identifier-parts.js on node v12.4.0 with unicode 12.1 -// \\* based on http://www.unicode.org/reports/tr31/ and https://www.ecma-international.org/ecma-262/6.0/#sec-names-and-keywords -// \\* unicodeESNextIdentifierSt💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 art corresponds to the ID_Start and Other_ID_Start property, and -// \\* unicodeESNextIdentifierPart corresponds to ID_Continue, Other_ID_Continue, plus ID_Start and Other_ID_Start -// \\*/ -// \\var unicodeESNextIdentifierStart = [65, 90, 97, 122, 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 895, 895, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1488, 1514, 1519, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2144, 2154, 2208, 2228, 2230, 2237, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2432, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2556, 2556, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2809, 2809, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3133, 3133, 3160, 3162, 3168, 3169, 3200, 3200, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3412, 3414, 3423, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6264, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6430, 6480, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7401, 7404, 7406, 7411, 7413, 7414, 7418, 7418, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12443, 12447, 12449, 12538, 12540, 12543, 12549, 12591, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40943, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42653, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42943, 42946, 42950, 42999, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43261, 43262, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43488, 43492, 43494, 43503, 43514, 43518, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43646, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43879, 43888, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66335, 66349, 66378, 66384, 66421, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 67072, 67382, 67392, 67413, 67424, 67431, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68096, 68112, 68115, 68117, 68119, 68121, 68149, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68324, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68899, 69376, 69404, 69415, 69415, 69424, 69445, 69600, 69622, 69635, 69687, 69763, 69807, 69840, 69864, 69891, 69926, 69956, 69956, 69968, 70002, 70006, 70006, 70019, 70066, 70081, 70084, 70106, 70106, 70108, 70108, 70144, 70161, 70163, 70187, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70366, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70461, 70461, 70480, 70480, 70493, 70497, 70656, 70708, 70727, 70730, 70751, 70751, 70784, 70831, 70852, 70853, 70855, 70855, 71040, 71086, 71128, 71131, 71168, 71215, 71236, 71236, 71296, 71338, 71352, 71352, 71424, 71450, 71680, 71723, 71840, 71903, 71935, 71935, 72096, 72103, 72106, 72144, 72161, 72161, 72163, 72163, 72192, 72192, 72203, 72242, 72250, 72250, 72272, 72272, 72284, 72329, 72349, 72349, 72384, 72440, 72704, 72712, 72714, 72750, 72768, 72768, 72818, 72847, 72960, 72966, 72968, 72969, 72971, 73008, 73030, 73030, 73056, 73061, 73063, 73064, 73066, 73097, 73112, 73112, 73440, 73458, 73728, 74649, 74752, 74862, 74880, 75075, 77824, 78894, 82944, 83526, 92160, 92728, 92736, 92766, 92880, 92909, 92928, 92975, 92992, 92995, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94032, 94032, 94099, 94111, 94176, 94177, 94179, 94179, 94208, 100343, 100352, 101106, 110592, 110878, 110928, 110930, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 123136, 123180, 123191, 123197, 123214, 123214, 123584, 123627, 124928, 125124, 125184, 125251, 125259, 125259, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 131072, 173782, 173824, 177972, 177984, 178205, 178208, 183969, 183984, 191456, 194560, 195101]; -// \\var unicodeESNextIdentifierPart = [48, 57, 65, 90, 95, 95, 97, 122, 170, 170, 181, 181, 183, 183, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 895, 895, 902, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1519, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2045, 2045, 2048, 2093, 2112, 2139, 2144, 2154, 2208, 2228, 2230, 2237, 2259, 2273, 2275, 2403, 2406, 2415, 2417, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2556, 2556, 2558, 2558, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2809, 2815, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3072, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3162, 3168, 3171, 3174, 3183, 3200, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3328, 3331, 3333, 3340, 3342, 3344, 3346, 3396, 3398, 3400, 3402, 3406, 3412, 3415, 3423, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3558, 3567, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4969, 4977, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6264, 6272, 6314, 6320, 6389, 6400, 6430, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6618, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6832, 6845, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7376, 7378, 7380, 7418, 7424, 7673, 7675, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12447, 12449, 12538, 12540, 12543, 12549, 12591, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40943, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42737, 42775, 42783, 42786, 42888, 42891, 42943, 42946, 42950, 42999, 43047, 43072, 43123, 43136, 43205, 43216, 43225, 43232, 43255, 43259, 43259, 43261, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43488, 43518, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43879, 43888, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65071, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66045, 66045, 66176, 66204, 66208, 66256, 66272, 66272, 66304, 66335, 66349, 66378, 66384, 66426, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66720, 66729, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 67072, 67382, 67392, 67413, 67424, 67431, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68099, 68101, 68102, 68108, 68115, 68117, 68119, 68121, 68149, 68152, 68154, 68159, 68159, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68326, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68903, 68912, 68921, 69376, 69404, 69415, 69415, 69424, 69456, 69600, 69622, 69632, 69702, 69734, 69743, 69759, 69818, 69840, 69864, 69872, 69881, 69888, 69940, 69942, 69951, 69956, 69958, 69968, 70003, 70006, 70006, 70016, 70084, 70089, 70092, 70096, 70106, 70108, 70108, 70144, 70161, 70163, 70199, 70206, 70206, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70378, 70384, 70393, 70400, 70403, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70459, 70468, 70471, 70472, 70475, 70477, 70480, 70480, 70487, 70487, 70493, 70499, 70502, 70508, 70512, 70516, 70656, 70730, 70736, 70745, 70750, 70751, 70784, 70853, 70855, 70855, 70864, 70873, 71040, 71093, 71096, 71104, 71128, 71133, 71168, 71232, 71236, 71236, 71248, 71257, 71296, 71352, 71360, 71369, 71424, 71450, 71453, 71467, 71472, 71481, 71680, 71738, 71840, 71913, 71935, 71935, 72096, 72103, 72106, 72151, 72154, 72161, 72163, 72164, 72192, 72254, 72263, 72263, 72272, 72345, 72349, 72349, 72384, 72440, 72704, 72712, 72714, 72758, 72760, 72768, 72784, 72793, 72818, 72847, 72850, 72871, 72873, 72886, 72960, 72966, 72968, 72969, 72971, 73014, 73018, 73018, 73020, 73021, 73023, 73031, 73040, 73049, 73056, 73061, 73063, 73064, 73066, 73102, 73104, 73105, 73107, 73112, 73120, 73129, 73440, 73462, 73728, 74649, 74752, 74862, 74880, 75075, 77824, 78894, 82944, 83526, 92160, 92728, 92736, 92766, 92768, 92777, 92880, 92909, 92912, 92916, 92928, 92982, 92992, 92995, 93008, 93017, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94031, 94087, 94095, 94111, 94176, 94177, 94179, 94179, 94208, 100343, 100352, 101106, 110592, 110878, 110928, 110930, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 113821, 113822, 119141, 119145, 119149, 119154, 119163, 119170, 119173, 119179, 119210, 119213, 119362, 119364, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 120782, 120831, 121344, 121398, 121403, 121452, 121461, 121461, 121476, 121476, 121499, 121503, 121505, 121519, 122880, 122886, 122888, 122904, 122907, 122913, 122915, 122916, 122918, 122922, 123136, 123180, 123184, 123197, 123200, 123209, 123214, 123214, 123584, 123641, 124928, 125124, 125136, 125142, 125184, 125259, 125264, 125273, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 131072, 173782, 173824, 177972, 177984, 178205, 178208, 183969, 183984, 191456, 194560, 195101, 917760, 917999]; -// \\/** -// \\* Test for whether a single line comment with leading whitespace trimmed's text contains a directive. -// \\*/ -// \\var commentDirectiveRegExSingleLine = /^\/\/\/?\s*@(ts-expect-error|ts-ignore)/; -// \\/** -// \\* Test for whether a multi-line comment with leading whitespace trimmed's last line contains a directive. -// \\*/ -// \\var commentDirectiveRegExMultiLine = /^(?:\/|\*)*\s*@(ts-expect-error|ts-ignore)/; -// \\ /** @deprecated Use `factory.updateTaggedTemplate` or the factory supplied by your transformation context instead. */ -// \\ ts.updateTaggedTemplate = ts.Debug.deprecate(function updateTaggedTemplate(node, tag, typeArgumentsOrTemplate, template) { -// \\ var typeArguments; -// \\ if (template) { -// \\ typeArguments = typeArgumentsOrTemplate; -// \\ } -// \\ else { -// \\ template = typeArgumentsOrTemplate; -// \\ } -// \\ return ts.factory.updateTaggedTemplateExpression(node, tag, typeArguments, template); -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.updateBinary` or the factory supplied by your transformation context instead. */ -// \\ ts.updateBinary = ts.Debug.deprecate(function updateBinary(node, left, right, operator) { -// \\ if (operator === void 0) { operator = node.operatorToken; } -// \\ if (typeof operator === "number") { -// \\ operator = operator === node.operatorToken.kind ? node.operatorToken : ts.factory.createToken(operator); -// \\ } -// \\ return ts.factory.updateBinaryExpression(node, left, operator, right); -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.createConditional` or the factory supplied by your transformation context instead. */ -// \\ ts.createConditional = ts.Debug.deprecate(function createConditional(condition, questionTokenOrWhenTrue, whenTrueOrWhenFalse, colonToken, whenFalse) { -// \\ return arguments.length === 5 ? ts.factory.createCondit 🤎💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 ionalExpression(condition, questionTokenOrWhenTrue, whenTrueOrWhenFalse, colonToken, whenFalse) : -// \\ arguments.length === 3 ? ts.factory.createConditionalExpression(condition, ts.factory.createToken(57 /* QuestionToken */), questionTokenOrWhenTrue, ts.factory.createToken(58 /* ColonToken */), whenTrueOrWhenFalse) : -// \\ ts.Debug.fail("Argument count mismatch"); -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.createYield` or the factory supplied by your transformation context instead. */ -// \\ ts.createYield = ts.Debug.deprecate(function createYield(asteriskTokenOrExpression, expression) { -// \\ var asteriskToken; -// \\ if (expression) { -// \\ asteriskToken = asteriskTokenOrExpression; -// \\ } -// \\ else { -// \\ expression = asteriskTokenOrExpression; -// \\ } -// \\ return ts.factory.createYieldExpre 🤎💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 ssion(asteriskToken, expression); -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.createClassExpression` or the factory supplied by your transformation context instead. */ -// \\ ts.createClassExpression = ts.Debug.deprecate(function createClassExpression(modifiers, name, typeParameters, heritageClauses, members) { -// \\ return ts.factory.createClassExpression(/*decorators*/ undefined, modifiers, name, typeParameters, heritageClauses, members); -// \\ }, factoryDeprecation); 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ -// \\ /** @deprecated Use `factory.updateClassExpression` or the factory supplied by your transformation context instead. */ -// \\ ts.updateClassExpression = ts.Debug.deprecate(function updateClassExpression(node, modifiers, name, typeParameters, heritageClauses, members) { -// \\ return ts.factory.updateClassExpression(node, /*decorato 🤎💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 rs*/ undefined, modifiers, name, typeParameters, heritageClauses, members); -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.createPropertySignature` or the factory supplied by your transformation context instead. */ -// \\ ts.createPropertySignature = ts.Debug.deprecate(function createPropertySignature(modifiers, name, questionToken, type, initializer) { -// \\ var node = ts.factory.createPropertySignature(modifiers, name, questionToken, type); -// \\ node.initializer = initializer; -// \\ return node; -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.updatePropertySignature` or the factory supplied by your transformation context instead. */ -// \\ ts.updatePropertySignature = ts.Debug.deprecate(function updatePropertySignature(node, modifiers, name, questionToken, type, initializer) { -// \\ var updated = ts.factory.updatePropertySignature(node, modifiers, name, questionToken, type); -// \\ if (node.initia 💛 💚 💙 💜 🖤 🤍 🤎 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 lizer !== initializer) { -// \\ if (updated === node) { -// \\ updated = ts 💚 💙 💜 🖤 🤍 🤎 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 .factory.cloneNode(node); -// \\ } -// \\ updated.ini ` 💛 💚 💙 💜 🖤 🤍 🤎 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 tializer = initializer; -// \\ } -// \\ return updated;⏏ ♀ 💚 💙 💜 🖤 🤍 🤎📢 👁‍🗨 💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 ♂ ⚕ ♾️ -// \\ }, factoryDeprecation 💛 💚 💙 💜 🖤 🤍🕞 💛⏏ ♀ ♂ ⚕ ♾️ -// \\ /** @deprecated Use⏏ ♀ 💚 💙 💜 🖤 🤍 🤎📢 👁‍🗨 💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 ♂ ⚕ ♾️ -// \\ ts.createExpression ` 💛 💚 💙 💜 🖤 🤍 🤎💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 Wi 💛⏏ ♀ ♂ ⚕ ♾️ -// \\ return ts.factory⏏ 💚 💙 💜 🖤 🤍 🤎 👁‍🗨 💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 ♀ ♂ ⚕ ♾️ -// \\ }, factoryDeprecation 💛⏏ ♀ ♂ ⚕ ♾️ -// \\ /** @deprecated Use⏏ ♀ ♂ ⚕ ♾️ -// \\ ts.updateExpressionWi 💛⏏ ♀ ♂ ⚕ ♾️ -// \\ }, factoryDeprecation);👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ /** @deprecated Use `factory.createArrowFunction` or the factory supplied by your transformation context instead. */👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ ts.createArrowFunction = ts.Debug.deprecate(function createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanTokenOrBody, body) { -// \\ return arguments.length === 6 ? ts.factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanTokenOrBody, body) : -// \\ arguments.length === 5 ? ts.factory.createA 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 -// \\💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 rrowFunction(modifiers, typeParamete👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ }, factoryDeprecation); 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 -// \\💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 -// \\ /** @deprecated Use `factory.updateArrowFunction` o 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍 ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 -// \\💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 r the factory supplied by your transformation context instead. */ -// \\ ts.updateArrowFunction = ts.Debug.deprecate(functio 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 -// \\💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 n updateArrowFunction(node, modifiers, typeParameters, parameters, type, equalsGreaterThanTokenOrBody, body) { -// \\ return arguments.length === 7 ? ts.factory.upda 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 -// \\💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 teArrowFunction(node, modifiers, typeParameters, parameters, type, equalsGreaterThanTokenOrBody, body) : -// \\ arguments.length === 6 ? ts.factory.updateA 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 -// \\💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 rrowFunction(node, modifiers, typeParameters, parameters, type, node.equalsGreaterThanToken, equalsGreaterThanTokenOrBody) : -// \\ ts.Debug.fail("Argument count mismatch" 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 -// \\ 💔 ❣️ 💕 💞 💓 -// \\ 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 -// \\💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 );👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽eDeclaration(name, exclamationTokenOrType, typeOrInitializer, initializer) { -// \\ return arguments.length === 4 ? ts.factory.createVariableDeclaration(name, exclamationTokenOrType, typeOrInitializer, initializer) :👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ argu💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 ✔️ ☑️ 🔘 🔴 🟠 🟡 🟢 🔵 ments.length >= 1 && arguments.length <= 3 ? ts.factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, exclamationTokenOrType, typeOrInitializer) : -// \\ ts.Debug.fail("Argument count mismatch");👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.updateVariableDeclaration` or the factory supplied by your transformation context instead. */👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ return arguments.length === 5 ? ts.factory.updateVariableDeclaration(node, name, exclamationTokenOrType, typeOrInitializer, initializer) : -// \\ arguments.length === 4 ? ts.factory.updateVariableDeclaration(node, name, node.exclamationToken, exclamationTokenOrType, typeOrInitializer) :👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ ts.Debug.fail("Argument count mismatch"); -// \\ }, factoryDeprecation); -// \\ 😀 😃 😄 😁 😆 🤩 😅 😂 🤣 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 😥 🤤 😭 😓 😪 😴 🥱 🙄 🤨 🧐 🤔 🤫 🤭 🤥 😬 🤐 🤢 🤮 🤧 😷 🤒 🤕 😈 👿 👹 👺 💩 👻 💀 ☠️ 👽 👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 👐 🙌 👏 🙏 🤲 🤝 👍 👎 👊 ✊ 🤛 🤜 🤞 ✌️ 🤘 🤏 👌 👈 👉 👆 👇 ☝️ ✋ 🤚 🖐 🖖 👋 🤙 💪 🖕 🤟 ✍️ 🤳 💅 🖖 💄 💋 👄 👅 👂 🦻 👃 🦵 🦶 🦾 🦿 👣 👁 👀 🗣 👤 👥 👶 👦 👧 🧒 👨 👩 🧑 👱‍♀️ 👱 🧔 👴 👵 🧓 👲 👳‍♀️ 👳 🧕 👮‍♀️ 👮 👷‍♀️ 👷 💂‍♀️ 💂 🕵️‍♀️ 🕵️ 👩‍⚕️ 👨‍⚕️ 👩‍🌾 👨‍🌾 👩‍🍳 👨‍🍳 👩‍🎓 👨‍🎓 👩‍🎤 👨‍🎤 👩‍🏫 👨‍🏫 👩‍🏭 👨‍🏭 👩‍💻 👨‍💻 👩‍💼 👨‍💼 👩‍🔧 👨‍🔧 👩‍🔬 👨‍🔬 👩‍🎨 👨‍🎨 👩‍🚒 👨‍🚒 👩‍✈️ 👨‍✈️ 👩‍🚀 👨‍🚀 👩‍⚖️ 👨‍⚖️ 🤶 🎅 👸 🤴 👰 🤵 👼 🤰 🤱 🙇‍♀️ 🙇 💁 💁‍♂️ 🙅 🙅‍♂️ 🙆 🙆‍♂️ 🙋 🙋‍♂️ 🤦‍♀️ 🤦‍♂️ 🤷‍♀️ 🤷‍♂️ 🙎 🙎‍♂️ 🙍 🙍‍♂️ 💇 💇‍♂️ 💆 💆‍♂️ 🧖‍♀️ 🧖‍♂️ 🧏 🧏‍♂️ 🧏‍♀️ 🧙‍♀️ 🧙‍♂️ 🧛‍♀️ 🧛‍♂️ 🧟‍♀️ 🧟‍♂️ 🧚‍♀️ 🧚‍♂️ 🧜‍♀️ 🧜‍♂️ 🧝‍♀️ 🧝‍♂️ 🧞‍♀️ 🧞‍♂️ 🕴 💃 🕺 👯 👯‍♂️ 🚶‍♀️ 🚶 🏃‍♀️ 🏃 🧍 🧍‍♂️ 🧍‍♀️ 🧎 🧎‍♂️ 🧎‍♀️ 👨‍🦯 👩‍🦯 👨‍🦼 👩‍🦼 👨‍🦽 👩‍🦽 🧑‍🤝‍🧑 👫 👭 👬 💑 👩‍❤️‍👩 👨‍❤️‍👨 💏 👩‍❤️‍💋‍👩 👨‍❤️‍💋‍👨 👪 👨‍👩‍👧 👨‍👩‍👧‍👦 👨‍👩‍👦‍👦 👨‍👩‍👧‍👧 👩‍👩‍👦 👩‍👩‍👧 👩‍👩‍👧‍👦 👩‍👩‍👦‍👦 👩‍👩‍👧‍👧 👨‍👨‍👦 👨‍👨‍👧 👨‍👨‍👧‍👦 👨‍👨‍👦‍👦 👨‍👨‍👧‍👧 👩‍👦 👩‍👧 👩‍👧‍👦 👩‍👦‍👦 👩‍👧‍👧 👨‍👦 👨‍👧 👨‍👧‍👦 👨‍👦‍👦 👨‍👧‍👧 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 👒 🎩 🎓 👑 ⛑ 🎒 👝 👛 👜 💼 👓 🕶 🤿 🌂 ☂️ 🧣 🧤 🧥 🦺 🥻 🩱 🩲 🩳 🩰 🧦 🧢 ⛷ 🏂 🏋️‍♀️ 🏋️ 🤺 🤼‍♀️ 🤼‍♂️ 🤸‍♀️ 🤸‍♂️ ⛹️‍♀️ ⛹️ 🤾‍♀️ 🤾‍♂️ 🏌️‍♀️ 🏌️ 🏄‍♀️ 🏄 🏊‍♀️ 🏊 🤽‍♀️ 🤽‍♂️ 🚣‍♀️ 🚣 🏇 🚴‍♀️ 🚴 🚵‍♀️ 🚵 🤹‍♀️ 🤹‍♂️ 🧗‍♀️ 🧗‍♂️ 🧘‍♀️ 🧘‍♂️ 🥰 🥵 🥶 🥳 🥴 🥺 🦸 🦹 🧑‍🦰 🧑‍🦱 🧑‍🦳 🧑‍🦲 🧑‍⚕️ 🧑‍🎓 🧑‍🏫 🧑‍⚖️ 🧑‍🌾 🧑‍🍳 🧑‍🔧 🧑‍🏭 🧑‍💼 🧑‍🔬 🧑‍💻 🧑‍🎤 🧑‍🎨 🧑‍✈️ 🧑‍🚀 🧑‍🚒 🧑‍🦯 🧑‍🦼 🧑‍🦽 🦰 🦱 🦲 🦳 -// \\ /** @deprecated Use `factory.createImportClause` or the factory supplied by your transformation context instead. */ -// \\ ts.createImportClause = ts.Debug.deprecate(function createImportClause(name, namedBindings, isTypeOnly) {👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ return ts.factory.createImportClause(isTypeOnly, name, namedBindings); -// \\ }, factoryDeprecation);👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽ry supplied by your transformation context instead. */ -// \\ ts.updateImportClause = ts.Debug.deprecate(function updateImportClause(node, name, namedBindings, isTypeOnly) { -// \\ return ts.factory.updateImportClause(node, isTypeOnly, name, namedBindings); -// \\ }, factoryDeprecation);👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ /** @deprecated Use `factory.createExportDeclaration` or the factory supplied by your transformation context instead. */👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🏋🏿‍♀️ 🏋🏿 🤸🏿‍♀️ 🤸🏿‍♂️ ⛹🏿‍♀️ ⛹🏿 🤾🏿‍♀️ 🤾🏿‍♂️ 🏌🏿‍♀️ 🏌🏿 🏄🏿‍♀️ 🏄🏿 🏊🏿‍♀️ 🏊🏿 🤽🏿‍♀️ 🤽🏿‍♂️ 🚣🏿‍♀️ 🚣🏿 🏇🏿 🚴🏿‍♀️ 🚴🏿 🚵🏿‍♀️ 🚵🏿 🤹🏿‍♀️ 🤹🏿‍♂️ 🛀🏿 🧒🏿 🧑🏿 🧓🏿 🧕🏿 🧔🏿 🤱🏿 🧙🏿‍♀️ 🧙🏿‍♂️ 🧚🏿‍♀️ 🧚🏿‍♂️ 🧛🏿‍♀️ 🧛🏿‍♂️ 🧜🏿‍♀️ 🧜🏿‍♂️ 🧝🏿‍♀️ 🧝🏿‍♂️ 🧖🏿‍♀️ 🧖🏿‍♂️ 🧗🏿‍♀️ 🧗🏿‍♂️ 🧘🏿‍♀️ 🧘🏿‍♂️ 🤟🏿 🤲🏿 💏🏿 💑🏿 🤏🏿 🦻🏿 🧏🏿 🧏🏿‍♂️ 🧏🏿‍♀️ 🧍🏿 🧍🏿‍♂️ 🧍🏿‍♀️ 🧎🏿 🧎🏿‍♂️ 🧎🏿‍♀️ 👨🏿‍🦯 👩🏿‍🦯 👨🏿‍🦼 👩🏿‍🦼 👨🏿‍🦽 👩🏿‍🦽 🧑🏿‍🤝‍🧑🏿 🧑🏿‍🦰 🧑🏿‍🦱 🧑🏿‍🦳 🧑🏿‍🦲 🧑🏿‍⚕️ 🧑🏿‍🎓 🧑🏿‍🏫 🧑🏿‍⚖️ 🧑🏿‍🌾 🧑🏿‍🍳 🧑🏿‍🔧 🧑🏿‍🏭 🧑🏿‍💼 🧑🏿‍🔬 🧑🏿‍💻 🧑🏿‍🎤 🧑🏿‍🎨 🧑🏿‍✈️ 🧑🏿‍🚀 🧑🏿‍🚒 🧑🏿‍🦯 🧑🏿‍🦼 🧑🏿‍🦽 -// \\ ts.createExportDeclaration = ts.Debug.deprecate(function createExportDeclaration(decorators, modifiers, exportClause, moduleSpecifier, isTypeOnly) { -// \\ if (isTypeOnly === void 0) { isTypeOnly = false; } -// \\ return ts.factory.createExportDeclaration(decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier);😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.updateExportDeclaration` or the factory supplied by your transformation context instead. */ -// \\ ts.updateEx 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍portDeclaration = ts.Debug.deprecate(function updateExportDeclaration(node, decorators, modifiers, exportClause, moduleSpecifier, isTypeOnly) { -// \\ return ts.factory.updateExportDeclaration(node, decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier); -// \\ }, factory 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍Deprecation); -// \\ /** @deprecated Use `factory.createJSDocParameterTag` or the factory supplied by your transformation context instead. */ -// \\ ts.createJSDocPar 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍amTag = ts.Debug 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍.deprecate(function createJSDocParamTag(name, isBracketed, typeExpression, comment) { -// \\ return ts.factory.createJSDocParameterTag(/*tagName*/ undefined, name, isBracketed, typeExpression, /*isNameFirst*/ false, comment ? ts.factory.createNodeArray([ts.factory.createJSDocText(comment)]) : undefivned); -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.createComma` or the factory supplied by your transformation context instead. */ -// \\ ts.createComma = ts.Debug.deprecate(function createComma(left, right) { -// \\ return ts.factory.createComma(left, right); -// \\ 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍🐱‍🏍 }, factoryDeprecation); -// \\ /** @deprecated 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍Use `factory.createLessThan` or the factory supplied by your transformation context instead. */ -// \\ ts.createLessThan = ts.Debug.deprecate(function createLessThan(left, right) {😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ }, factoryDeprecation); -// \\ /** @ 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍deprecated Use `factory.createAssignment` or the factory supplied by your transformation context instead. */😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ /** @deprecated Use `factory.createStrictEquality` or the factory supplied by your transformation context instead. */ -// \\ ts.createStrictEquality = ts.Debug.dep 🐱‍👤 🐱‍🚀 🐱‍🐉 🐱‍💻 🐱‍🏍recate(function createStrictEquality(left, right) { -// \\ return ts.factory.createStrictEquality(left, right);😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ }, factoryDeprecation); -// \\ /** @deprecated 🐱‍🐉 🐱‍💻 🐱‍👤 🐱‍🚀Use `factory.createStrictInequality` or the factory supplied by your transformation context instead. */ -// \\ ts.createStrictInequality = ts.Debug.deprecate(function createStrictInequality(left, right) { -// \\ return ts.factory.createStrictInequality(left, right); -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.createAdd` or the factory supplied b😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ return ts.factory.createSubtract(left, right); -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.createLogicalAnd` or the factory supplied by your transformation context instead. */ -// \\ ts.createLogicalAnd = ts.Debug.deprecate(function createLogicalAnd(left, right) { -// \\ return ts.factory.createLogicalAnd(left, right);😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use `factory.createLogicalOr` or the factory supplied by your transformation context instead. */ -// \\ ts.createLogicalOr = ts.Debug.deprecate(function createLogicalOr(left, right) {😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ return ts.factory.createLogicalOr(left, right);😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ }, factoryDeprecation);😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢supplied by your transformation context instead. */ -// \\ ts.createPostfixIncrement = ts.Debug.deprecate(function createPostfixIncrement(operand) {😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ return ts.factory.createPostfixIncrement(operand);😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ }, factoryDeprecation); -// \\ /** @deprecated Use an appropriate `factory` method instead. */ -// \\ ts.createNode = ts.Debug.deprecate(function createNode(kind, pos, end) { -// \\ if (pos === void 0) { pos = 0; }😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢NodeFactory.createBaseSourceFileNode(kind) : -// \\ kind === 79 /* Identifier */ ? ts.parseBaseNodeFactory.createBaseIdentifierNode(kind) : -// \\ kind === 80 /* PrivateIdentifier */ ? ts.parseBaseNodeFactory.createBasePrivateIdentifierNode(kind) : -// \\ !ts.isNodeKind(kind) ? ts.parseBaseNodeFactory.createBaseTokenNode(kind) :😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢a node ~for mutation~ with its `pos`, `end`, and `parent` set. -// \\ * -// \\ * NOTE: It is unsafe to change any properties of a `Node` that relate to its AST children, as those changes won't be -// \\ * captured with respect to transformations. -// \\ * -// \\ * @deprecated Use an appropriate `factory.update...` method instead, use `setCommentRange` or `setSourceMapRange`, and avoid setting `parent`.😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ ts.setTextRange(clone, node); -// \\ ts.setParent(clone, node.parent); -// \\ return clone;😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 🤪 😜 😝 😛 🤑 🤗 🤓 😎 🤡 🤠 😏 😒 😞 😔 😟 😕 🙁 ☹️ 😣 😖 😫 😩 😤 😠 😡 🤬 😶 😐 😑 😯 😦 😧 😮 😲 😵 🤯 😳 😱 😨 😰 😢 -// \\ }, { since: "4.0", warnAfter: "4.1", message: "Use an appropriate `factory.update...` method instead, use `setCommentRange` or `setSourceMapRange`, and avoid setting `parent`." }); -// \\ // #endregion Node Factory top-level exports -// \\ // DEPRECATION: Renamed node tests -// \\ // DEPRECATION PLAN:🟣 ⚫️ ⚪️ 🟤 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🟥 🟧 🟨 🟩 🟦 🟪 🟫 🔈 🔇 🔉 🔊 🔔 🔕 📣 -// \\ // - soft: 4.0 -// \\ // - warn: 4.1 -// \\ // - error: TBD -// \\ // #region Renamed node Tests -// \\ /** @deprecated Use `isTypeAssertionExpression` instead. */ -// \\ ts.isTypeAssertion = ts.Debug.deprecate(function isTypeAssertion(node) { -// \\ return node.kind === 209 /* TypeAssertionExpression */; -// \\ }, { -// \\ since: "4.0", -// \\ warnAfter: "4.1", -// \\ message: "Use `isTypeAssertionExpression` instead." -// \\ }); -// \\ // #endregion -// \\ // DEPRECATION: Renamed node tests -// \\ // DEPRECATION PLAN: -// \\ // - soft: 4.2 -// \\ // - warn: 4.3 -// \\ // - error: TBD -// \\ // #region Renamed node Tests -// \\ /** -// \\ * @deprecated Use `isMemberName` instead. -// \\ */ -// \\ ts.isIdentifierOrPrivateIdentifier = ts.Debug.deprecate(function isIdentifierOrPrivateIdentifier(node) { -// \\ return ts.isMemberName(node); -// \\ }, { -// \\ since: "4.2", -// \\ warnAfter: "4.3", -// \\ message: "Use `isMemberName` instead." -// \\ }); -// \\ // #endregion Renamed node Tests -// \\})(ts || (ts = {})); -// ; -// const ascii_text: []const u8 = -// \\ -// \\package js_lexer -// \\ -// \\// The lexer converts a source file to a stream of tokens. Unlike many -// \\// compilers, esbuild does not run the lexer to completion before the parser is -// \\// started. Instead, the lexer is called repeatedly by the parser as the parser -// \\// parses the file. This is because many tokens are context-sensitive and need -// \\// high-level information from the parser. Examples are regular expression -// \\// literals and JSX elements. -// \\// -// \\// For efficiency, the text associated with textual tokens is stored in two -// \\// separate ways depending on the token. Identifiers use UTF-8 encoding which -// \\// allows them to be slices of the input file without allocating extra memory. -// \\// Strings use UTF-16 encoding so they can represent unicode surrogates -// \\// accurately. -// \\ -// \\import ( -// \\"fmt" -// \\"strconv" -// \\"strings" -// \\"unicode" -// \\"unicode/utf8" -// \\ -// \\"github.com/evanw/esbuild/internal/js_ast" -// \\"github.com/evanw/esbuild/internal/logger" -// \\) -// \\ -// \\type T uint -// \\ -// \\// If you add a new token, remember to add it to "tokenToString" too -// \\const ( -// \\TEndOfFile T = iota -// \\TSyntaxError -// \\ -// \\// "#!/usr/bin/env node" -// \\THashbang -// \\ -// \\// Literals -// \\TNoSubstitutionTemplateLiteral // Contents are in lexer.StringLiteral ([]uint16) -// \\TNumericLiteral // Contents are in lexer.Number (float64) -// \\TStringLiteral // Contents are in lexer.StringLiteral ([]uint16) -// \\TBigIntegerLiteral // Contents are in lexer.Identifier (string) -// \\ -// \\// Pseudo-literals -// \\TTemplateHead // Contents are in lexer.StringLiteral ([]uint16) -// \\TTemplateMiddle // Contents are in lexer.StringLiteral ([]uint16) -// \\TTemplateTail // Contents are in lexer.StringLiteral ([]uint16) -// \\ -// \\// Punctuation -// \\TAmpersand -// \\TAmpersandAmpersand -// \\TAsterisk -// \\TAsteriskAsterisk -// \\TAt -// \\TBar -// \\TBarBar -// \\TCaret -// \\TCloseBrace -// \\TCloseBracket -// \\TCloseParen -// \\TColon -// \\TComma -// \\TDot -// \\TDotDotDot -// \\TEqualsEquals -// \\TEqualsEqualsEquals -// \\TEqualsGreaterThan -// \\TExclamation -// \\TExclamationEquals -// \\TExclamationEqualsEquals -// \\TGreaterThan -// \\TGreaterThanEquals -// \\TGreaterThanGreaterThan -// \\TGreaterThanGreaterThanGreaterThan -// \\TLessThan -// \\TLessThanEquals -// \\TLessThanLessThan -// \\TMinus -// \\TMinusMinus -// \\TOpenBrace -// \\TOpenBracket -// \\TOpenParen -// \\TPercent -// \\TPlus -// \\TPlusPlus -// \\TQuestion -// \\TQuestionDot -// \\TQuestionQuestion -// \\TSemicolon -// \\TSlash -// \\TTilde -// \\ -// \\// Assignments (keep in sync with IsAssign() below) -// \\TAmpersandAmpersandEquals -// \\TAmpersandEquals -// \\TAsteriskAsteriskEquals -// \\TAsteriskEquals -// \\TBarBarEquals -// \\TBarEquals -// \\TCaretEquals -// \\TEquals -// \\TGreaterThanGreaterThanEquals -// \\TGreaterThanGreaterThanGreaterThanEquals -// \\TLessThanLessThanEquals -// \\TMinusEquals -// \\TPercentEquals -// \\TPlusEquals -// \\TQuestionQuestionEquals -// \\TSlashEquals -// \\ -// \\// Class-private fields and methods -// \\TPrivateIdentifier -// \\ -// \\// Identifiers -// \\TIdentifier // Contents are in lexer.Identifier (string) -// \\TEscapedKeyword // A keyword that has been escaped as an identifer -// \\ -// \\// Reserved words -// \\TBreak -// \\TCase -// \\TCatch -// \\TClass -// \\TConst -// \\TContinue -// \\TDebugger -// \\TDefault -// \\TDelete -// \\TDo -// \\TElse -// \\TEnum -// \\TExport -// \\TExtends -// \\TFalse -// \\TFinally -// \\TFor -// \\TFunction -// \\TIf -// \\TImport -// \\TIn -// \\TInstanceof -// \\TNew -// \\TNull -// \\TReturn -// \\TSuper -// \\TSwitch -// \\TThis -// \\TThrow -// \\TTrue -// \\TTry -// \\TTypeof -// \\TVar -// \\TVoid -// \\TWhile -// \\TWith -// \\) -// \\ -// \\func (t T) IsAssign() bool { -// \\return t >= TAmpersandAmpersandEquals && t <= TSlashEquals -// \\} -// \\ -// \\var Keywords = map[string]T{ -// \\// Reserved words -// \\"break": TBreak, -// \\"case": TCase, -// \\"catch": TCatch, -// \\"class": TClass, -// \\"const": TConst, -// \\"continue": TContinue, -// \\"debugger": TDebugger, -// \\"default": TDefault, -// \\"delete": TDelete, -// \\"do": TDo, -// \\"else": TElse, -// \\"enum": TEnum, -// \\"export": TExport, -// \\"extends": TExtends, -// \\"false": TFalse, -// \\"finally": TFinally, -// \\"for": TFor, -// \\"function": TFunction, -// \\"if": TIf, -// \\"import": TImport, -// \\"in": TIn, -// \\"instanceof": TInstanceof, -// \\"new": TNew, -// \\"null": TNull, -// \\"return": TReturn, -// \\"super": TSuper, -// \\"switch": TSwitch, -// \\"this": TThis, -// \\"throw": TThrow, -// \\"true": TTrue, -// \\"try": TTry, -// \\"typeof": TTypeof, -// \\"var": TVar, -// \\"void": TVoid, -// \\"while": TWhile, -// \\"with": TWith, -// \\} -// \\ -// \\var StrictModeReservedWords = map[string]bool{ -// \\"implements": true, -// \\"interface": true, -// \\"let": true, -// \\"package": true, -// \\"private": true, -// \\"protected": true, -// \\"public": true, -// \\"static": true, -// \\"yield": true, -// \\} -// \\ -// \\type json struct { -// \\parse bool -// \\allowComments bool -// \\} -// \\ -// \\type Lexer struct { -// \\log logger.Log -// \\source logger.Source -// \\tracker logger.LineColumnTracker -// \\current int -// \\start int -// \\end int -// \\ApproximateNewlineCount int -// \\LegacyOctalLoc logger.Loc -// \\AwaitKeywordLoc logger.Loc -// \\FnOrArrowStartLoc logger.Loc -// \\PreviousBackslashQuoteInJSX logger.Range -// \\LegacyHTMLCommentRange logger.Range -// \\Token T -// \\HasNewlineBefore bool -// \\HasPureCommentBefore bool -// \\PreserveAllCommentsBefore bool -// \\IsLegacyOctalLiteral bool -// \\PrevTokenWasAwaitKeyword bool -// \\CommentsToPreserveBefore []js_ast.Comment -// \\AllOriginalComments []js_ast.Comment -// \\codePoint rune -// \\Identifier string -// \\JSXFactoryPragmaComment logger.Span -// \\JSXFragmentPragmaComment logger.Span -// \\SourceMappingURL logger.Span -// \\Number float64 -// \\rescanCloseBraceAsTemplateToken bool -// \\forGlobalName bool -// \\json json -// \\prevErrorLoc logger.Loc -// \\ -// \\// Escape sequences in string literals are decoded lazily because they are -// \\// not interpreted inside tagged templates, and tagged templates can contain -// \\// invalid escape sequences. If the decoded array is nil, the encoded value -// \\// should be passed to "tryToDecodeEscapeSequences" first. -// \\decodedStringLiteralOrNil []uint16 -// \\encodedStringLiteralStart int -// \\encodedStringLiteralText string -// \\ -// \\// The log is disabled during speculative scans that may backtrack -// \\IsLogDisabled bool -// \\} -// \\ -// \\type LexerPanic struct{} -// \\ -// \\func NewLexer(log logger.Log, source logger.Source) Lexer { -// \\lexer := Lexer{ -// \\log: log, -// \\source: source, -// \\tracker: logger.MakeLineColumnTracker(&source), -// \\prevErrorLoc: logger.Loc{Start: -1}, -// \\FnOrArrowStartLoc: logger.Loc{Start: -1}, -// \\} -// \\lexer.step() -// \\lexer.Next() -// \\return lexer -// \\} -// \\ -// \\func NewLexerGlobalName(log logger.Log, source logger.Source) Lexer { -// \\lexer := Lexer{ -// \\log: log, -// \\source: source, -// \\tracker: logger.MakeLineColumnTracker(&source), -// \\prevErrorLoc: logger.Loc{Start: -1}, -// \\FnOrArrowStartLoc: logger.Loc{Start: -1}, -// \\forGlobalName: true, -// \\} -// \\lexer.step() -// \\lexer.Next() -// \\return lexer -// \\} -// \\ -// \\func NewLexerJSON(log logger.Log, source logger.Source, allowComments bool) Lexer { -// \\lexer := Lexer{ -// \\log: log, -// \\source: source, -// \\tracker: logger.MakeLineColumnTracker(&source), -// \\prevErrorLoc: logger.Loc{Start: -1}, -// \\FnOrArrowStartLoc: logger.Loc{Start: -1}, -// \\json: json{ -// \\parse: true, -// \\allowComments: allowComments, -// \\}, -// \\} -// \\lexer.step() -// \\lexer.Next() -// \\return lexer -// \\} -// \\ -// \\func (lexer *Lexer) Loc() logger.Loc { -// \\return logger.Loc{Start: int32(lexer.start)} -// \\} -// \\ -// \\func (lexer *Lexer) Range() logger.Range { -// \\return logger.Range{Loc: logger.Loc{Start: int32(lexer.start)}, Len: int32(lexer.end - lexer.start)} -// \\} -// \\ -// \\func (lexer *Lexer) Raw() string { -// \\return lexer.source.Contents[lexer.start:lexer.end] -// \\} -// \\ -// \\func (lexer *Lexer) StringLiteral() []uint16 { -// \\if lexer.decodedStringLiteralOrNil == nil { -// \\// Lazily decode escape sequences if needed -// \\if decoded, ok, end := lexer.tryToDecodeEscapeSequences(lexer.encodedStringLiteralStart, lexer.encodedStringLiteralText, true /* reportErrors */); !ok { -// \\lexer.end = end -// \\lexer.SyntaxError() -// \\} else { -// \\lexer.decodedStringLiteralOrNil = decoded -// \\} -// \\} -// \\return lexer.decodedStringLiteralOrNil -// \\} -// \\ -// \\func (lexer *Lexer) CookedAndRawTemplateContents() ([]uint16, string) { -// \\var raw string -// \\ -// \\switch lexer.Token { -// \\case TNoSubstitutionTemplateLiteral, TTemplateTail: -// \\// "`x`" or "}x`" -// \\raw = lexer.source.Contents[lexer.start+1 : lexer.end-1] -// \\ -// \\case TTemplateHead, TTemplateMiddle: -// \\// "`x${" or "}x${" -// \\raw = lexer.source.Contents[lexer.start+1 : lexer.end-2] -// \\} -// \\ -// \\if strings.IndexByte(raw, '\r') != -1 { -// \\// From the specification: -// \\// -// \\// 11.8.6.1 Static Semantics: TV and TRV -// \\// -// \\// TV excludes the code units of LineContinuation while TRV includes -// \\// them. and LineTerminatorSequences are normalized to -// \\// for both TV and TRV. An explicit EscapeSequence is needed to -// \\// include a or sequence. -// \\ -// \\bytes := []byte(raw) -// \\end := 0 -// \\i := 0 -// \\ -// \\for i < len(bytes) { -// \\c := bytes[i] -// \\i++ -// \\ -// \\if c == '\r' { -// \\// Convert '\r\n' into '\n' -// \\if i < len(bytes) && bytes[i] == '\n' { -// \\i++ -// \\} -// \\ -// \\// Convert '\r' into '\n' -// \\c = '\n' -// \\} -// \\ -// \\bytes[end] = c -// \\end++ -// \\} -// \\ -// \\raw = string(bytes[:end]) -// \\} -// \\ -// \\// This will return nil on failure, which will become "undefined" for the tag -// \\cooked, _, _ := lexer.tryToDecodeEscapeSequences(lexer.start+1, raw, false /* reportErrors */) -// \\return cooked, raw -// \\} -// \\ -// \\func (lexer *Lexer) IsIdentifierOrKeyword() bool { -// \\return lexer.Token >= TIdentifier -// \\} -// \\ -// \\func (lexer *Lexer) IsContextualKeyword(text string) bool { -// \\return lexer.Token == TIdentifier && lexer.Raw() == text -// \\} -// \\ -// \\func (lexer *Lexer) ExpectContextualKeyword(text string) { -// \\if !lexer.IsContextualKeyword(text) { -// \\lexer.ExpectedString(fmt.Sprintf("%q", text)) -// \\} -// \\lexer.Next() -// \\} -// \\ -// \\func (lexer *Lexer) SyntaxError() { -// \\loc := logger.Loc{Start: int32(lexer.end)} -// \\message := "Unexpected end of file" -// \\if lexer.end < len(lexer.source.Contents) { -// \\c, _ := utf8.DecodeRuneInString(lexer.source.Contents[lexer.end:]) -// \\if c < 0x20 { -// \\message = fmt.Sprintf("Syntax error \"\\x%02X\"", c) -// \\} else if c >= 0x80 { -// \\message = fmt.Sprintf("Syntax error \"\\u{%x}\"", c) -// \\} else if c != '"' { -// \\message = fmt.Sprintf("Syntax error \"%c\"", c) -// \\} else { -// \\message = "Syntax error '\"'" -// \\} -// \\} -// \\lexer.addError(loc, message) -// \\panic(LexerPanic{}) -// \\} -// \\ -// \\func (lexer *Lexer) ExpectedString(text string) { -// \\// Provide a friendly error message about "await" without "async" -// \\if lexer.PrevTokenWasAwaitKeyword { -// \\var notes []logger.MsgData -// \\if lexer.FnOrArrowStartLoc.Start != -1 { -// \\note := logger.RangeData(&lexer.tracker, logger.Range{Loc: lexer.FnOrArrowStartLoc}, -// \\"Consider adding the \"async\" keyword here") -// \\note.Location.Suggestion = "async" -// \\notes = []logger.MsgData{note} -// \\} -// \\lexer.addRangeErrorWithNotes(RangeOfIdentifier(lexer.source, lexer.AwaitKeywordLoc), -// \\"\"await\" can only be used inside an \"async\" function", -// \\notes) -// \\panic(LexerPanic{}) -// \\} -// \\ -// \\found := fmt.Sprintf("%q", lexer.Raw()) -// \\if lexer.start == len(lexer.source.Contents) { -// \\found = "end of file" -// \\} -// \\lexer.addRangeError(lexer.Range(), fmt.Sprintf("Expected %s but found %s", text, found)) -// \\panic(LexerPanic{}) -// \\} -// \\ -// \\func (lexer *Lexer) Expected(token T) { -// \\if text, ok := tokenToString[token]; ok { -// \\lexer.ExpectedString(text) -// \\} else { -// \\lexer.Unexpected() -// \\} -// \\} -// \\ -// \\func (lexer *Lexer) Unexpected() { -// \\found := fmt.Sprintf("%q", lexer.Raw()) -// \\if lexer.start == len(lexer.source.Contents) { -// \\found = "end of file" -// \\} -// \\lexer.addRangeError(lexer.Range(), fmt.Sprintf("Unexpected %s", found)) -// \\panic(LexerPanic{}) -// \\} -// \\ -// \\func (lexer *Lexer) Expect(token T) { -// \\if lexer.Token != token { -// \\lexer.Expected(token) -// \\} -// \\lexer.Next() -// \\} -// \\ -// \\func (lexer *Lexer) ExpectOrInsertSemicolon() { -// \\if lexer.Token == TSemicolon || (!lexer.HasNewlineBefore && -// \\lexer.Token != TCloseBrace && lexer.Token != TEndOfFile) { -// \\lexer.Expect(TSemicolon) -// \\} -// \\} -// \\func (lexer *Lexer) ExpectLessThan(isInsideJSXElement bool) { -// \\switch lexer.Token { -// \\case TLessThan: -// \\if isInsideJSXElement { -// \\lexer.NextInsideJSXElement() -// \\} else { -// \\lexer.Next() -// \\} -// \\ -// \\case TLessThanEquals: -// \\lexer.Token = TEquals -// \\lexer.start++ -// \\lexer.maybeExpandEquals() -// \\ -// \\case TLessThanLessThan: -// \\lexer.Token = TLessThan -// \\lexer.start++ -// \\ -// \\case TLessThanLessThanEquals: -// \\lexer.Token = TLessThanEquals -// \\lexer.start++ -// \\ -// \\default: -// \\lexer.Expected(TLessThan) -// \\} -// \\} -// \\ -// \\// This parses a single ">" token. If that is the first part of a longer token, -// \\// this function splits off the first ">" and leaves the remainder of the -// \\// current token as another, smaller token. For example, ">>=" becomes ">=". -// \\func (lexer *Lexer) ExpectGreaterThan(isInsideJSXElement bool) { -// \\switch lexer.Token { -// \\case TGreaterThan: -// \\if isInsideJSXElement { -// \\lexer.NextInsideJSXElement() -// \\} else { -// \\lexer.Next() -// \\} -// \\ -// \\case TGreaterThanEquals: -// \\lexer.Token = TEquals -// \\lexer.start++ -// \\lexer.maybeExpandEquals() -// \\ -// \\case TGreaterThanGreaterThan: -// \\lexer.Token = TGreaterThan -// \\lexer.start++ -// \\ -// \\case TGreaterThanGreaterThanEquals: -// \\lexer.Token = TGreaterThanEquals -// \\lexer.start++ -// \\ -// \\case TGreaterThanGreaterThanGreaterThan: -// \\lexer.Token = TGreaterThanGreaterThan -// \\lexer.start++ -// \\ -// \\case TGreaterThanGreaterThanGreaterThanEquals: -// \\lexer.Token = TGreaterThanGreaterThanEquals -// \\lexer.start++ -// \\ -// \\default: -// \\lexer.Expected(TGreaterThan) -// \\} -// \\} -// \\ -// \\func (lexer *Lexer) maybeExpandEquals() { -// \\switch lexer.codePoint { -// \\case '>': -// \\// "=" + ">" = "=>" -// \\lexer.Token = TEqualsGreaterThan -// \\lexer.step() -// \\ -// \\case '=': -// \\// "=" + "=" = "==" -// \\lexer.Token = TEqualsEquals -// \\lexer.step() -// \\ -// \\if lexer.Token == '=' { -// \\// "=" + "==" = "===" -// \\lexer.Token = TEqualsEqualsEquals -// \\lexer.step() -// \\} -// \\} -// \\} -// \\ -// \\func IsIdentifier(text string) bool { -// \\if len(text) == 0 { -// \\return false -// \\} -// \\for i, codePoint := range text { -// \\if i == 0 { -// \\if !IsIdentifierStart(codePoint) { -// \\return false -// \\} -// \\} else { -// \\if !IsIdentifierContinue(codePoint) { -// \\return false -// \\} -// \\} -// \\} -// \\return true -// \\} -// \\ -// \\func IsIdentifierES5AndESNext(text string) bool { -// \\if len(text) == 0 { -// \\return false -// \\} -// \\for i, codePoint := range text { -// \\if i == 0 { -// \\if !IsIdentifierStartES5AndESNext(codePoint) { -// \\return false -// \\} -// \\} else { -// \\if !IsIdentifierContinueES5AndESNext(codePoint) { -// \\return false -// \\} -// \\} -// \\} -// \\return true -// \\} -// \\ -// \\func ForceValidIdentifier(text string) string { -// \\if IsIdentifier(text) { -// \\return text -// \\} -// \\sb := strings.Builder{} -// \\ -// \\// Identifier start -// \\c, width := utf8.DecodeRuneInString(text) -// \\text = text[width:] -// \\if IsIdentifierStart(c) { -// \\sb.WriteRune(c) -// \\} else { -// \\sb.WriteRune('_') -// \\} -// \\ -// \\// Identifier continue -// \\for text != "" { -// \\c, width := utf8.DecodeRuneInString(text) -// \\text = text[width:] -// \\if IsIdentifierContinue(c) { -// \\sb.WriteRune(c) -// \\} else { -// \\sb.WriteRune('_') -// \\} -// \\} -// \\ -// \\return sb.String() -// \\} -// \\ -// \\// This does "IsIdentifier(UTF16ToString(text))" without any allocations -// \\func IsIdentifierUTF16(text []uint16) bool { -// \\n := len(text) -// \\if n == 0 { -// \\return false -// \\} -// \\for i := 0; i < n; i++ { -// \\isStart := i == 0 -// \\r1 := rune(text[i]) -// \\if r1 >= 0xD800 && r1 <= 0xDBFF && i+1 < n { -// \\if r2 := rune(text[i+1]); r2 >= 0xDC00 && r2 <= 0xDFFF { -// \\r1 = (r1 << 10) + r2 + (0x10000 - (0xD800 << 10) - 0xDC00) -// \\i++ -// \\} -// \\} -// \\if isStart { -// \\if !IsIdentifierStart(r1) { -// \\return false -// \\} -// \\} else { -// \\if !IsIdentifierContinue(r1) { -// \\return false -// \\} -// \\} -// \\} -// \\return true -// \\} -// \\ -// \\// This does "IsIdentifierES5AndESNext(UTF16ToString(text))" without any allocations -// \\func IsIdentifierES5AndESNextUTF16(text []uint16) bool { -// \\n := len(text) -// \\if n == 0 { -// \\return false -// \\} -// \\for i := 0; i < n; i++ { -// \\isStart := i == 0 -// \\r1 := rune(text[i]) -// \\if r1 >= 0xD800 && r1 <= 0xDBFF && i+1 < n { -// \\if r2 := rune(text[i+1]); r2 >= 0xDC00 && r2 <= 0xDFFF { -// \\r1 = (r1 << 10) + r2 + (0x10000 - (0xD800 << 10) - 0xDC00) -// \\i++ -// \\} -// \\} -// \\if isStart { -// \\if !IsIdentifierStartES5AndESNext(r1) { -// \\return false -// \\} -// \\} else { -// \\if !IsIdentifierContinueES5AndESNext(r1) { -// \\return false -// \\} -// \\} -// \\} -// \\return true -// \\} -// \\ -// \\func IsIdentifierStart(codePoint rune) bool { -// \\switch codePoint { -// \\case '_', '$', -// \\'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', -// \\'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', -// \\'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', -// \\'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z': -// \\return true -// \\} -// \\ -// \\// All ASCII identifier start code points are listed above -// \\if codePoint < 0x7F { -// \\return false -// \\} -// \\ -// \\return unicode.Is(idStartES5OrESNext, codePoint) -// \\} -// \\ -// \\func IsIdentifierContinue(codePoint rune) bool { -// \\switch codePoint { -// \\case '_', '$', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', -// \\'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', -// \\'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', -// \\'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', -// \\'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z': -// \\return true -// \\} -// \\ -// \\// All ASCII identifier start code points are listed above -// \\if codePoint < 0x7F { -// \\return false -// \\} -// \\ -// \\// ZWNJ and ZWJ are allowed in identifiers -// \\if codePoint == 0x200C || codePoint == 0x200D { -// \\return true -// \\} -// \\ -// \\return unicode.Is(idContinueES5OrESNext, codePoint) -// \\} -// \\ -// \\func IsIdentifierStartES5AndESNext(codePoint rune) bool { -// \\switch codePoint { -// \\case '_', '$', -// \\'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', -// \\'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', -// \\'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', -// \\'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z': -// \\return true -// \\} -// \\ -// \\// All ASCII identifier start code points are listed above -// \\if codePoint < 0x7F { -// \\return false -// \\} -// \\ -// \\return unicode.Is(idStartES5AndESNext, codePoint) -// \\} -// \\ -// \\func IsIdentifierContinueES5AndESNext(codePoint rune) bool { -// \\switch codePoint { -// \\case '_', '$', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', -// \\'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', -// \\'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', -// \\'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', -// \\'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z': -// \\return true -// \\} -// \\ -// \\// All ASCII identifier start code points are listed above -// \\if codePoint < 0x7F { -// \\return false -// \\} -// \\ -// \\// ZWNJ and ZWJ are allowed in identifiers -// \\if codePoint == 0x200C || codePoint == 0x200D { -// \\return true -// \\} -// \\ -// \\return unicode.Is(idContinueES5AndESNext, codePoint) -// \\} -// \\ -// \\// See the "White Space Code Points" table in the ECMAScript standard -// \\func IsWhitespace(codePoint rune) bool { -// \\switch codePoint { -// \\case -// \\'\u0009', // character tabulation -// \\'\u000B', // line tabulation -// \\'\u000C', // form feed -// \\'\u0020', // space -// \\'\u00A0', // no-break space -// \\ -// \\// Unicode "Space_Separator" code points -// \\'\u1680', // ogham space mark -// \\'\u2000', // en quad -// \\'\u2001', // em quad -// \\'\u2002', // en space -// \\'\u2003', // em space -// \\'\u2004', // three-per-em space -// \\'\u2005', // four-per-em space -// \\'\u2006', // six-per-em space -// \\'\u2007', // figure space -// \\'\u2008', // punctuation space -// \\'\u2009', // thin space -// \\'\u200A', // hair space -// \\'\u202F', // narrow no-break space -// \\'\u205F', // medium mathematical space -// \\'\u3000', // ideographic space -// \\ -// \\'\uFEFF': // zero width non-breaking space -// \\return true -// \\ -// \\default: -// \\return false -// \\} -// \\} -// \\ -// \\func RangeOfIdentifier(source logger.Source, loc logger.Loc) logger.Range { -// \\text := source.Contents[loc.Start:] -// \\if len(text) == 0 { -// \\return logger.Range{Loc: loc, Len: 0} -// \\} -// \\ -// \\i := 0 -// \\c, _ := utf8.DecodeRuneInString(text[i:]) -// \\ -// \\// Handle private names -// \\if c == '#' { -// \\i++ -// \\c, _ = utf8.DecodeRuneInString(text[i:]) -// \\} -// \\ -// \\if IsIdentifierStart(c) || c == '\\' { -// \\// Search for the end of the identifier -// \\for i < len(text) { -// \\c2, width2 := utf8.DecodeRuneInString(text[i:]) -// \\if c2 == '\\' { -// \\i += width2 -// \\ -// \\// Skip over bracketed unicode escapes such as "\u{10000}" -// \\if i+2 < len(text) && text[i] == 'u' && text[i+1] == '{' { -// \\i += 2 -// \\for i < len(text) { -// \\if text[i] == '}' { -// \\i++ -// \\break -// \\} -// \\i++ -// \\} -// \\} -// \\} else if !IsIdentifierContinue(c2) { -// \\return logger.Range{Loc: loc, Len: int32(i)} -// \\} else { -// \\i += width2 -// \\} -// \\} -// \\} -// \\ -// \\// When minifying, this identifier may have originally been a string -// \\return source.RangeOfString(loc) -// \\} -// \\ -// \\func (lexer *Lexer) ExpectJSXElementChild(token T) { -// \\if lexer.Token != token { -// \\lexer.Expected(token) -// \\} -// \\lexer.NextJSXElementChild() -// \\} -// \\ -// \\func (lexer *Lexer) NextJSXElementChild() { -// \\lexer.HasNewlineBefore = false -// \\originalStart := lexer.end -// \\ -// \\for { -// \\lexer.start = lexer.end -// \\lexer.Token = 0 -// \\ -// \\switch lexer.codePoint { -// \\case -1: // This indicates the end of the file -// \\lexer.Token = TEndOfFile -// \\ -// \\case '{': -// \\lexer.step() -// \\lexer.Token = TOpenBrace -// \\ -// \\case '<': -// \\lexer.step() -// \\lexer.Token = TLessThan -// \\ -// \\default: -// \\needsFixing := false -// \\ -// \\stringLiteral: -// \\for { -// \\switch lexer.codePoint { -// \\case -1: -// \\// Reaching the end of the file without a closing element is an error -// \\lexer.SyntaxError() -// \\ -// \\case '&', '\r', '\n', '\u2028', '\u2029': -// \\// This needs fixing if it has an entity or if it's a multi-line string -// \\needsFixing = true -// \\lexer.step() -// \\ -// \\case '{', '<': -// \\// Stop when the string ends -// \\break stringLiteral -// \\ -// \\default: -// \\// Non-ASCII strings need the slow path -// \\if lexer.codePoint >= 0x80 { -// \\needsFixing = true -// \\} -// \\lexer.step() -// \\} -// \\} -// \\ -// \\lexer.Token = TStringLiteral -// \\text := lexer.source.Contents[originalStart:lexer.end] -// \\ -// \\if needsFixing { -// \\// Slow path -// \\lexer.decodedStringLiteralOrNil = fixWhitespaceAndDecodeJSXEntities(text) -// \\ -// \\// Skip this token if it turned out to be empty after trimming -// \\if len(lexer.decodedStringLiteralOrNil) == 0 { -// \\lexer.HasNewlineBefore = true -// \\continue -// \\} -// \\} else { -// \\// Fast path -// \\n := len(text) -// \\copy := make([]uint16, n) -// \\for i := 0; i < n; i++ { -// \\copy[i] = uint16(text[i]) -// \\} -// \\lexer.decodedStringLiteralOrNil = copy -// \\} -// \\} -// \\ -// \\break -// \\} -// \\} -// \\ -// \\func (lexer *Lexer) ExpectInsideJSXElement(token T) { -// \\if lexer.Token != token { -// \\lexer.Expected(token) -// \\} -// \\lexer.NextInsideJSXElement() -// \\} -// \\ -// \\func (lexer *Lexer) NextInsideJSXElement() { -// \\lexer.HasNewlineBefore = false -// \\ -// \\for { -// \\lexer.start = lexer.end -// \\lexer.Token = 0 -// \\ -// \\switch lexer.codePoint { -// \\case -1: // This indicates the end of the file -// \\lexer.Token = TEndOfFile -// \\ -// \\case '\r', '\n', '\u2028', '\u2029': -// \\lexer.step() -// \\lexer.HasNewlineBefore = true -// \\continue -// \\ -// \\case '\t', ' ': -// \\lexer.step() -// \\continue -// \\ -// \\case '.': -// \\lexer.step() -// \\lexer.Token = TDot -// \\ -// \\case '=': -// \\lexer.step() -// \\lexer.Token = TEquals -// \\ -// \\case '{': -// \\lexer.step() -// \\lexer.Token = TOpenBrace -// \\ -// \\case '}': -// \\lexer.step() -// \\lexer.Token = TCloseBrace -// \\ -// \\case '<': -// \\lexer.step() -// \\lexer.Token = TLessThan -// \\ -// \\case '>': -// \\lexer.step() -// \\lexer.Token = TGreaterThan -// \\ -// \\case '/': -// \\// '/' or '//' or '/* ... */' -// \\lexer.step() -// \\switch lexer.codePoint { -// \\case '/': -// \\singleLineComment: -// \\for { -// \\lexer.step() -// \\switch lexer.codePoint { -// \\case '\r', '\n', '\u2028', '\u2029': -// \\break singleLineComment -// \\ -// \\case -1: // This indicates the end of the file -// \\break singleLineComment -// \\} -// \\} -// \\continue -// \\ -// \\case '*': -// \\lexer.step() -// \\startRange := lexer.Range() -// \\multiLineComment: -// \\for { -// \\switch lexer.codePoint { -// \\case '*': -// \\lexer.step() -// \\if lexer.codePoint == '/' { -// \\lexer.step() -// \\break multiLineComment -// \\} -// \\ -// \\case '\r', '\n', '\u2028', '\u2029': -// \\lexer.step() -// \\lexer.HasNewlineBefore = true -// \\ -// \\case -1: // This indicates the end of the file -// \\lexer.start = lexer.end -// \\lexer.addErrorWithNotes(lexer.Loc(), "Expected \"*/\" to terminate multi-line comment", -// \\[]logger.MsgData{logger.RangeData(&lexer.tracker, startRange, "The multi-line comment starts here")}) -// \\panic(LexerPanic{}) -// \\ -// \\default: -// \\lexer.step() -// \\} -// \\} -// \\continue -// \\ -// \\default: -// \\lexer.Token = TSlash -// \\} -// \\ -// \\case '\'', '"': -// \\var backslash logger.Range -// \\quote := lexer.codePoint -// \\needsDecode := false -// \\lexer.step() -// \\ -// \\stringLiteral: -// \\for { -// \\switch lexer.codePoint { -// \\case -1: // This indicates the end of the file -// \\lexer.SyntaxError() -// \\ -// \\case '&': -// \\needsDecode = true -// \\lexer.step() -// \\ -// \\case '\\': -// \\backslash = logger.Range{Loc: logger.Loc{Start: int32(lexer.end)}, Len: 1} -// \\lexer.step() -// \\continue -// \\ -// \\case quote: -// \\if backslash.Len > 0 { -// \\backslash.Len++ -// \\lexer.PreviousBackslashQuoteInJSX = backslash -// \\} -// \\lexer.step() -// \\break stringLiteral -// \\ -// \\default: -// \\// Non-ASCII strings need the slow path -// \\if lexer.codePoint >= 0x80 { -// \\needsDecode = true -// \\} -// \\lexer.step() -// \\} -// \\backslash = logger.Range{} -// \\} -// \\ -// \\lexer.Token = TStringLiteral -// \\text := lexer.source.Contents[lexer.start+1 : lexer.end-1] -// \\ -// \\if needsDecode { -// \\// Slow path -// \\lexer.decodedStringLiteralOrNil = decodeJSXEntities([]uint16{}, text) -// \\} else { -// \\// Fast path -// \\n := len(text) -// \\copy := make([]uint16, n) -// \\for i := 0; i < n; i++ { -// \\copy[i] = uint16(text[i]) -// \\} -// \\lexer.decodedStringLiteralOrNil = copy -// \\} -// \\ -// \\default: -// \\// Check for unusual whitespace characters -// \\if IsWhitespace(lexer.codePoint) { -// \\lexer.step() -// \\continue -// \\} -// \\ -// \\if IsIdentifierStart(lexer.codePoint) { -// \\lexer.step() -// \\for IsIdentifierContinue(lexer.codePoint) || lexer.codePoint == '-' { -// \\lexer.step() -// \\} -// \\ -// \\// Parse JSX namespaces. These are not supported by React or TypeScript -// \\// but someone using JSX syntax in more obscure ways may find a use for -// \\// them. A namespaced name is just always turned into a string so you -// \\// can't use this feature to reference JavaScript identifiers. -// \\if lexer.codePoint == ':' { -// \\lexer.step() -// \\if IsIdentifierStart(lexer.codePoint) { -// \\lexer.step() -// \\for IsIdentifierContinue(lexer.codePoint) || lexer.codePoint == '-' { -// \\lexer.step() -// \\} -// \\} else { -// \\lexer.addError(logger.Loc{Start: lexer.Range().End()}, -// \\fmt.Sprintf("Expected identifier after %q in namespaced JSX name", lexer.Raw())) -// \\} -// \\} -// \\ -// \\lexer.Identifier = lexer.Raw() -// \\lexer.Token = TIdentifier -// \\break -// \\} -// \\ -// \\lexer.end = lexer.current -// \\lexer.Token = TSyntaxError -// \\} -// \\ -// \\return -// \\} -// \\} -// \\ -// \\func (lexer *Lexer) Next() { -// \\lexer.HasNewlineBefore = lexer.end == 0 -// \\lexer.HasPureCommentBefore = false -// \\lexer.PrevTokenWasAwaitKeyword = false -// \\lexer.CommentsToPreserveBefore = nil -// \\ -// \\for { -// \\lexer.start = lexer.end -// \\lexer.Token = 0 -// \\ -// \\switch lexer.codePoint { -// \\case -1: // This indicates the end of the file -// \\lexer.Token = TEndOfFile -// \\ -// \\case '#': -// \\if lexer.start == 0 && strings.HasPrefix(lexer.source.Contents, "#!") { -// \\// "#!/usr/bin/env node" -// \\lexer.Token = THashbang -// \\hashbang: -// \\for { -// \\lexer.step() -// \\switch lexer.codePoint { -// \\case '\r', '\n', '\u2028', '\u2029': -// \\break hashbang -// \\ -// \\case -1: // This indicates the end of the file -// \\break hashbang -// \\} -// \\} -// \\lexer.Identifier = lexer.Raw() -// \\} else { -// \\// "#foo" -// \\lexer.step() -// \\} -// ; - -// const repeat_count: usize = 1; -// const loop_count: usize = 1000; - -// pub fn main() anyerror!void { -// try HashTable.init(std.heap.c_allocator); -// Bitset.init(); -// { - -// // Ensure that the optimizer doesn't do something fancy with static memory addresses -// var code = try std.heap.c_allocator.dupe(u8, unicode_text); - -// var iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// var hash_table_count: usize = 0; -// var jump_table_count: usize = 0; -// var jump_table_elapsed: u64 = 0; -// var hash_table_elapsed: u64 = 0; -// var binary_search_elapsed: u64 = 0; -// var binary_search_count: usize = 0; -// var bitset_elapsed: u64 = 0; -// var bitset_count: usize = 0; - -// // change up the order these run in -// var loop_i: usize = 0; -// while (loop_i < loop_count) : (loop_i += 1) { -// { -// var iteration_i: usize = 0; -// var timer = try std.time.Timer.start(); -// while (iteration_i < repeat_count) : (iteration_i += 1) { -// @setEvalBranchQuota(99999); -// iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// hash_table_count = 0; -// while (iter.nextCodepoint()) |cp| { -// hash_table_count += @as(usize, @intFromBool(HashTable.isIdentifierStart(cp) or HashTable.isIdentifierPart(cp))); -// } -// } -// hash_table_elapsed += timer.read(); -// } - -// { -// var iteration_i: usize = 0; -// var timer = try std.time.Timer.start(); -// while (iteration_i < repeat_count) : (iteration_i += 1) { -// @setEvalBranchQuota(99999); -// iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// jump_table_count = 0; -// while (iter.nextCodepoint()) |cp| { -// jump_table_count += @as( -// usize, -// @intFromBool(JumpTable.isIdentifierStart(cp) or JumpTable.isIdentifierPart(cp)), -// ); -// } -// } -// jump_table_elapsed += timer.read(); -// } - -// { -// var iteration_i: usize = 0; -// var timer = try std.time.Timer.start(); -// while (iteration_i < repeat_count) : (iteration_i += 1) { -// @setEvalBranchQuota(99999); -// iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// binary_search_count = 0; -// while (iter.nextCodepoint()) |cp| { -// binary_search_count += @as( -// usize, -// @intFromBool( -// BinarySearch.isIdentifierStart( -// cp, -// ) or BinarySearch.isIdentifierPart( -// cp, -// ), -// ), -// ); -// } -// } -// binary_search_elapsed += timer.read(); -// } - -// { -// var iteration_i: usize = 0; -// var timer = try std.time.Timer.start(); -// while (iteration_i < repeat_count) : (iteration_i += 1) { -// @setEvalBranchQuota(99999); -// iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// bitset_count = 0; -// while (iter.nextCodepoint()) |cp| { -// bitset_count += @as( -// usize, -// @intFromBool( -// Bitset.isIdentifierStart( -// cp, -// ) or Bitset.isIdentifierPart( -// cp, -// ), -// ), -// ); -// } -// } -// bitset_elapsed += timer.read(); -// } -// } - -// .print( -// \\---- Unicode text ----- -// \\ -// \\Timings (sum of running {d} times each, lower is better): -// \\ -// \\ Binary Search : {d}ns -// \\ Hash Table : {d}ns -// \\ Switch statement : {d}ns -// \\ Bitset : {d}ns -// \\ -// \\Match count (these should be the same): -// \\ -// \\ Binary Search : {d} -// \\ Hash Table : {d} -// \\ Switch statement : {d} -// \\ Bitset : {d} -// \\ -// \\ -// , -// .{ -// repeat_count * loop_count, -// binary_search_elapsed, -// hash_table_elapsed, -// jump_table_elapsed, -// bitset_elapsed, - -// binary_search_count, -// hash_table_count, -// jump_table_count, -// bitset_count, -// }, -// ); -// } - -// { - -// // Ensure that the optimizer doesn't do something fancy with static memory addresses -// var code = try std.heap.c_allocator.dupe(u8, ascii_text); - -// var iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// var hash_table_count: usize = 0; -// var jump_table_count: usize = 0; -// var jump_table_elapsed: u64 = 0; -// var hash_table_elapsed: u64 = 0; -// var binary_search_elapsed: u64 = 0; -// var binary_search_count: usize = 0; -// var bitset_count: usize = 0; -// var bitset_elapsed: u64 = 0; - -// // change up the order these run in -// var loop_i: usize = 0; -// while (loop_i < loop_count) : (loop_i += 1) { -// { -// var iteration_i: usize = 0; -// var timer = try std.time.Timer.start(); -// while (iteration_i < repeat_count) : (iteration_i += 1) { -// @setEvalBranchQuota(99999); -// iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// hash_table_count = 0; -// while (iter.nextCodepoint()) |cp| { -// hash_table_count += @as(usize, @intFromBool(HashTable.isIdentifierStart(cp) or HashTable.isIdentifierPart(cp))); -// } -// } -// hash_table_elapsed += timer.read(); -// } - -// { -// var iteration_i: usize = 0; -// var timer = try std.time.Timer.start(); -// while (iteration_i < repeat_count) : (iteration_i += 1) { -// @setEvalBranchQuota(99999); -// iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// jump_table_count = 0; -// while (iter.nextCodepoint()) |cp| { -// jump_table_count += @as( -// usize, -// @intFromBool(JumpTable.isIdentifierStart(cp) or JumpTable.isIdentifierPart(cp)), -// ); -// } -// } -// jump_table_elapsed += timer.read(); -// } - -// { -// var iteration_i: usize = 0; -// var timer = try std.time.Timer.start(); -// while (iteration_i < repeat_count) : (iteration_i += 1) { -// @setEvalBranchQuota(99999); -// iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// binary_search_count = 0; -// while (iter.nextCodepoint()) |cp| { -// binary_search_count += @as( -// usize, -// @intFromBool( -// BinarySearch.isIdentifierStart( -// cp, -// ) or BinarySearch.isIdentifierPart( -// cp, -// ), -// ), -// ); -// } -// } -// binary_search_elapsed += timer.read(); -// } - -// { -// var iteration_i: usize = 0; -// var timer = try std.time.Timer.start(); -// while (iteration_i < repeat_count) : (iteration_i += 1) { -// @setEvalBranchQuota(99999); -// iter = std.unicode.Utf8Iterator{ .bytes = code, .i = 0 }; -// bitset_count = 0; -// while (iter.nextCodepoint()) |cp| { -// bitset_count += @as( -// usize, -// @intFromBool( -// Bitset.isIdentifierStart( -// cp, -// ) or Bitset.isIdentifierPart( -// cp, -// ), -// ), -// ); -// } -// } -// bitset_elapsed += timer.read(); -// } -// } - -// { -// iter = std.unicode.Utf8Iterator{ .bytes = ascii_text, .i = 0 }; -// while (iter.nextCodepoint()) |cp| { -// if (cp > 127) std.debug.panic("This is not ASCII at {d}", .{iter.i}); -// } -// } - -// ( -// \\---- ASCII text ----- -// \\ -// \\Timings (sum of running {d} times each, lower is better): -// \\ -// \\ Binary Search : {d}ns -// \\ Hash Table : {d}ns -// \\ Switch statement : {d}ns -// \\ Bitset : {d}ns -// \\ -// \\Match count (these should be the same): -// \\ -// \\ Binary Search : {d} -// \\ Hash Table : {d} -// \\ Switch statement : {d} -// \\ Bitset : {d} -// \\ -// \\ -// , -// .{ -// repeat_count * loop_count, -// binary_search_elapsed, -// hash_table_elapsed, -// jump_table_elapsed, -// bitset_elapsed, - -// binary_search_count, -// hash_table_count, -// jump_table_count, -// bitset_count, -// }, -// ); -// } -// } +/// isIDContinueESNext checks if a codepoint is valid in the isIDContinueESNext category +pub fn isIDContinueESNext(cp: u21) bool { + const high = cp >> 8; + const low = cp & 0xFF; + const stage2_idx = idContinueESNext.stage1[high]; + const bit_pos = stage2_idx + low; + const u64_idx = bit_pos >> 6; + const bit_idx = @as(u6, @intCast(bit_pos & 63)); + return (idContinueESNext.stage2[u64_idx] & (@as(u64, 1) << bit_idx)) != 0; +} +const idContinueESNext = struct { + pub const stage1 = [_]u16{ 0, 256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, 4096, 256, 4352, 4608, 4864, 256, 5120, 5376, 5632, 5888, 6144, 6400, 6656, 256, 256, 6912, 7168, 7424, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7936, 8192, 7680, 7680, 8448, 8704, 7680, 7680, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 8960, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 9216, 256, 9472, 9728, 9984, 10240, 10496, 10752, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 11008, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 256, 11264, 11520, 256, 11776, 12032, 12288, 12544, 12800, 13056, 13312, 13568, 13824, 256, 14080, 14336, 14592, 14848, 15104, 15360, 15616, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 17664, 17920, 18176, 18432, 18688, 18944, 7680, 19200, 19456, 19712, 19968, 256, 256, 256, 20224, 20480, 20736, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 20992, 256, 256, 256, 256, 21248, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 256, 256, 21504, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 256, 256, 21760, 22016, 7680, 7680, 22272, 22528, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 22784, 256, 256, 256, 256, 23040, 23296, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 23552, 256, 23808, 24064, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 24320, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 24576, 7680, 24832, 25088, 7680, 25344, 25600, 25856, 26112, 7680, 7680, 26368, 7680, 7680, 7680, 7680, 26624, 26880, 27136, 27392, 7680, 27648, 7680, 7680, 27904, 28160, 28416, 7680, 7680, 7680, 7680, 28672, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 28928, 7680, 7680, 7680, 7680, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 29184, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 29440, 29696, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 29952, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 30208, 256, 256, 30464, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 256, 256, 30720, 7680, 7680, 7680, 7680, 7680, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 30976, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 31232, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 31488, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680 }; + pub const stage2 = [_]u64{ 287948901175001088, 576460745995190270, 333270770471927808, 18410715276682199039, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 88094074470339, 18446744073709551615, 13609878073913638911, 18446744056529672128, 18428729675200069631, 18446744073709551615, 18446744073709551615, 18446744073709550843, 18446744073709551615, 18446462598732840959, 18446744069456527359, 13835058055282033151, 2119858418286774, 18446744069548736512, 18446678103011885055, 18446744073709551615, 11529212845433552895, 18446744073709486080, 18446744073709545471, 1125899906842623, 2612087783874887679, 70368744177663, 18446471390799331327, 18446744073692806911, 18446744056529682431, 18446744073709551615, 18446462392574410751, 17565725197581524975, 5765733215448889759, 15235112390417287150, 18014125208779143, 17576984196650090478, 18302910150157089727, 17576984196649951214, 844217444219295, 14123225865944680428, 281200107273671, 17582050746231021567, 281265183931871, 17577547146603651055, 4221915814182367, 18446744073709412351, 18158794964244397535, 3457638613854978030, 3658904103781503, 576460752303423486, 67076095, 4611685674830002134, 4093607775, 14024213633433600001, 18446216308128218879, 2305843009196916703, 64, 18446744073709551615, 18446744073709487103, 18446744070488326143, 17870283321406070975, 18446744073709551615, 18446744070446333439, 9168765891372858879, 18446744073701162813, 18446744073696837631, 1123704775901183, 18446744069414649855, 4557642822898941951, 18446744073709551614, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446638520593285119, 18446744069548802046, 144053615424700415, 9007197111451647, 3905461007941631, 18446744073709551615, 4394566287359, 18446744069481674752, 144115188075855871, 18446471394825863167, 18014398509481983, 1152657619668697087, 8796093022207936, 18446480190918885375, 134153215, 18446744069683019775, 11529215043920986111, 13834777130128311295, 32767, 18446744073709551615, 4494803601399807, 18446744073709551615, 4503599627370495, 72057594037927935, 4611686018427380735, 16717361816799216127, 576460752302833664, 18446744070475743231, 4611686017001275199, 6908521828386340863, 2295745090394464220, 9223372036854788096, 9223934986809245697, 536805376, 562821641207808, 17582049991377026180, 18446744069414601696, 511, 0, 0, 0, 0, 0, 18446744073709551615, 18446744073709551615, 18446744073709551615, 4494940973301759, 18446498607738650623, 9223513873854758911, 9187201948305063935, 18446744071553646463, 2251518330118602976, 18446744073709551614, 18446744069389418495, 17870283321406128127, 18446462598732840928, 18446744073709551615, 18446744069414617087, 18446462598732840960, 18446744073709551615, 18446744073709551615, 18446744073709551615, 0, 18446744073709551615, 18446744073709551615, 8191, 4611686018427322368, 17592185987071, 13830835930631503871, 18446744073709551615, 1125899906842623, 18446744060816261120, 18446744073709551615, 18446744073709550079, 18445618173868443647, 18691697672191, 4503599627370495, 18446744073709551615, 16789419406609285183, 18446532967477018623, 2305843004919775231, 18446744073709551615, 9223372032626884609, 36028797018963967, 18194542490348896255, 18446744073709551615, 35184368733388807, 18446602782178705022, 18446466996645134335, 18446744073709551615, 288010473826156543, 18446744073709551615, 18446744073709551615, 18446462667452317695, 1152921504606845055, 18446744073709551615, 18446532967477018623, 18446744073709551615, 67108863, 6881498031078244479, 18446744073709551579, 1125899906842623, 18446744073709027328, 4611686018427387903, 18446744073709486080, 18446744073709355007, 1152640029630136575, 7036870122864639, 18437455399478157312, 18446744073709551615, 2305843009213693951, 9799832780635308032, 18446743798965862398, 9223372036854775807, 486341884, 13258596753222922239, 1073692671, 18446744073709551615, 576460752303423487, 0, 9007199254740991, 0, 2305843009213693952, 0, 0, 18446744069951455231, 4295098367, 18446708893632430079, 576460752303359999, 18446744070488326143, 4128527, 18446744073709551615, 18446744073709551615, 18446466993558126591, 1152921504591118335, 18446463698244468735, 17870001915148894207, 2016486715970549759, 0, 36028797018963967, 1095220854783, 575897802350002111, 0, 10502394331027995967, 36028792728190975, 2147483647, 15762594400829440, 288230371860938751, 0, 13907115649320091647, 0, 9745789593611923567, 2305843004918726656, 536870911, 549755813631, 18014398509481983, 2251795522912255, 262143, 0, 18446744073709551615, 511, 2251799813685247, 2251799813685247, 287950000686628863, 0, 0, 0, 0, 0, 875211255709695, 16140901064495857664, 18446463149025525759, 18446462598732972031, 18446462598732841023, 36028792723996703, 18446744073709551615, 9241386160486350975, 576460752303423487, 287951100198191108, 18437736874454810623, 22517998136787184, 18446744073709551615, 402644511, 13907115649319829503, 3, 18446464796682337663, 287957697268023295, 18153444948953374703, 8760701963286943, 0, 0, 18446744073709551615, 16173172735, 18446744073709551615, 67043519, 0, 0, 18392700878181105663, 1056964609, 18446744073709551615, 67043345, 144115188075855871, 1023, 287966492958392319, 127, 0, 0, 576460752303423487, 0, 18446744069414584320, 9223376434901286911, 17996384110963061375, 67043343, 18446740770879700992, 120208752639, 9223372036854775807, 18446744073709486208, 18446462599336820735, 144115188075855871, 18410715276690587135, 18445618173869752321, 36027697507139583, 0, 13006395723845991295, 18446741595580465407, 4393784803327, 0, 0, 0, 0, 36028792723996672, 14411518807585456127, 67043335, 281474976710656, 0, 18446744073709551615, 18446744073709551615, 67108863, 0, 18446744073709551615, 140737488355327, 18446744073709551615, 18446744073709551615, 18446744073709551615, 15, 0, 0, 0, 0, 18446744073709486080, 562949953421311, 281474976710655, 4194303, 0, 0, 18446744073709551615, 127, 0, 0, 144115188075855871, 18446466994631868415, 9223372036854775807, 8796093022143487, 36028797018963967, 16212958624241090575, 65535, 0, 0, 18446744073709551615, 0, 0, 18446744073709551615, 18446744073709520895, 4294934783, 844540894248960, 18446744073709551615, 18446744073709551615, 18446744073709551615, 72057594037927935, 18446744073709551615, 18446744073709551615, 18446744073709551615, 4194303, 511, 0, 0, 0, 0, 0, 0, 8065665457643847680, 1125934266580991, 18446463629527547904, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 1152921504606846975, 18446744073709551615, 2305570330330005503, 1677656575, 0, 18446532967477018623, 127, 0, 0, 0, 17872504197455282176, 65970697670631, 0, 0, 28, 0, 0, 18446744073709551615, 18446744073707454463, 17005555242810474495, 18446744073709551599, 8935141660164089791, 18446744073709419615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446743249075830783, 17870283321271910397, 18437736874452713471, 18446603336221163519, 18446741874686295551, 18446744073709539319, 17906312118425092095, 9042383626829823, 281470547525648, 0, 8660801552383, 0, 0, 0, 18446471240106377087, 70368744177663, 32768, 0, 4611439727822766079, 17407, 0, 0, 0, 0, 140737488289792, 288230376151711743, 0, 0, 0, 288230376151646208, 0, 0, 0, 9223213153129594880, 18446744073709551615, 18446744073709551615, 18446744073709551615, 8323103, 18446744073709551615, 67047423, 0, 0, 790380184120328175, 6843210385291930244, 1152917029519358975, 0, 0, 0, 0, 287948901175001088, 18446744073709551615, 18446744073709551615, 18446744073709551615, 4294967295, 288230376151711743, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744070488326143, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446462615912710143, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446462607322775551, 18446744073709551615, 1073741823, 0, 0, 1073741823, 0, 0, 0, 18446744073709551615, 18446744073709488127, 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615, 281474976710655, 0, 18446744073709551615, 18446744073709551615, 18446744073709551615, 281474976710655 }; +}; diff --git a/src/js_lexer/identifier_cache.zig b/src/js_lexer/identifier_cache.zig deleted file mode 100644 index de1ea0e771..0000000000 --- a/src/js_lexer/identifier_cache.zig +++ /dev/null @@ -1,22 +0,0 @@ -const std = @import("std"); -const bun = @import("root").bun; -const identifier_data = @import("./identifier_data.zig"); - -pub const CachedBitset = extern struct { - range: [2]i32, - len: u32, - - pub fn fromFile(comptime filename: anytype) CachedBitset { - return comptime @as(CachedBitset, @bitCast(bun.asByteSlice(@embedFile(filename)).ptr[0..@sizeOf(CachedBitset)].*)); - } -}; - -pub fn setMasks(masks: [*:0]const u8, comptime MaskType: type, masky: MaskType) void { - const FieldInfo: std.builtin.Type.StructField = std.meta.fieldInfo(MaskType, "masks"); - masky.masks = @as(masks, @bitCast(FieldInfo.type)); -} - -pub const id_start_meta = identifier_data.id_start_cached; -pub const id_continue_meta = identifier_data.id_continue_cached; -pub const id_start = identifier_data.id_start; -pub const id_continue = identifier_data.id_continue; diff --git a/src/js_lexer/identifier_data.zig b/src/js_lexer/identifier_data.zig deleted file mode 100644 index 1c98ac2503..0000000000 --- a/src/js_lexer/identifier_data.zig +++ /dev/null @@ -1,178 +0,0 @@ -const std = @import("std"); - -const ZWJ = .{ 0x200C, 0x200D }; - -// "unicodeESNextIdentifierStart" -pub const start_codepoints = [_]i32{ 65, 90, 97, 122, 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 895, 895, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1488, 1514, 1519, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2144, 2154, 2208, 2228, 2230, 2237, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2432, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2556, 2556, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2809, 2809, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3133, 3133, 3160, 3162, 3168, 3169, 3200, 3200, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3412, 3414, 3423, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6264, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6430, 6480, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7401, 7404, 7406, 7411, 7413, 7414, 7418, 7418, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12443, 12447, 12449, 12538, 12540, 12543, 12549, 12591, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40943, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42653, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42943, 42946, 42950, 42999, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43261, 43262, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43488, 43492, 43494, 43503, 43514, 43518, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43646, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43879, 43888, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66335, 66349, 66378, 66384, 66421, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 67072, 67382, 67392, 67413, 67424, 67431, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68096, 68112, 68115, 68117, 68119, 68121, 68149, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68324, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68899, 69376, 69404, 69415, 69415, 69424, 69445, 69600, 69622, 69635, 69687, 69763, 69807, 69840, 69864, 69891, 69926, 69956, 69956, 69968, 70002, 70006, 70006, 70019, 70066, 70081, 70084, 70106, 70106, 70108, 70108, 70144, 70161, 70163, 70187, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70366, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70461, 70461, 70480, 70480, 70493, 70497, 70656, 70708, 70727, 70730, 70751, 70751, 70784, 70831, 70852, 70853, 70855, 70855, 71040, 71086, 71128, 71131, 71168, 71215, 71236, 71236, 71296, 71338, 71352, 71352, 71424, 71450, 71680, 71723, 71840, 71903, 71935, 71935, 72096, 72103, 72106, 72144, 72161, 72161, 72163, 72163, 72192, 72192, 72203, 72242, 72250, 72250, 72272, 72272, 72284, 72329, 72349, 72349, 72384, 72440, 72704, 72712, 72714, 72750, 72768, 72768, 72818, 72847, 72960, 72966, 72968, 72969, 72971, 73008, 73030, 73030, 73056, 73061, 73063, 73064, 73066, 73097, 73112, 73112, 73440, 73458, 73728, 74649, 74752, 74862, 74880, 75075, 77824, 78894, 82944, 83526, 92160, 92728, 92736, 92766, 92880, 92909, 92928, 92975, 92992, 92995, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94032, 94032, 94099, 94111, 94176, 94177, 94179, 94179, 94208, 100343, 100352, 101106, 110592, 110878, 110928, 110930, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 123136, 123180, 123191, 123197, 123214, 123214, 123584, 123627, 124928, 125124, 125184, 125251, 125259, 125259, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 131072, 173782, 173824, 177972, 177984, 178205, 178208, 183969, 183984, 191456, 194560, 195101 }; -// "unicodeESNextIdentifierPart" -pub const part_codepoints = ZWJ ++ [_]i32{ 48, 57, 65, 90, 95, 95, 97, 122, 170, 170, 181, 181, 183, 183, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 895, 895, 902, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1519, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2045, 2045, 2048, 2093, 2112, 2139, 2144, 2154, 2208, 2228, 2230, 2237, 2259, 2273, 2275, 2403, 2406, 2415, 2417, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2556, 2556, 2558, 2558, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2809, 2815, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3072, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3162, 3168, 3171, 3174, 3183, 3200, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3328, 3331, 3333, 3340, 3342, 3344, 3346, 3396, 3398, 3400, 3402, 3406, 3412, 3415, 3423, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3558, 3567, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4969, 4977, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6264, 6272, 6314, 6320, 6389, 6400, 6430, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6618, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6832, 6845, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7376, 7378, 7380, 7418, 7424, 7673, 7675, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12447, 12449, 12538, 12540, 12543, 12549, 12591, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40943, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42737, 42775, 42783, 42786, 42888, 42891, 42943, 42946, 42950, 42999, 43047, 43072, 43123, 43136, 43205, 43216, 43225, 43232, 43255, 43259, 43259, 43261, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43488, 43518, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43879, 43888, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65071, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66045, 66045, 66176, 66204, 66208, 66256, 66272, 66272, 66304, 66335, 66349, 66378, 66384, 66426, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66720, 66729, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 67072, 67382, 67392, 67413, 67424, 67431, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68099, 68101, 68102, 68108, 68115, 68117, 68119, 68121, 68149, 68152, 68154, 68159, 68159, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68326, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68903, 68912, 68921, 69376, 69404, 69415, 69415, 69424, 69456, 69600, 69622, 69632, 69702, 69734, 69743, 69759, 69818, 69840, 69864, 69872, 69881, 69888, 69940, 69942, 69951, 69956, 69958, 69968, 70003, 70006, 70006, 70016, 70084, 70089, 70092, 70096, 70106, 70108, 70108, 70144, 70161, 70163, 70199, 70206, 70206, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70378, 70384, 70393, 70400, 70403, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70459, 70468, 70471, 70472, 70475, 70477, 70480, 70480, 70487, 70487, 70493, 70499, 70502, 70508, 70512, 70516, 70656, 70730, 70736, 70745, 70750, 70751, 70784, 70853, 70855, 70855, 70864, 70873, 71040, 71093, 71096, 71104, 71128, 71133, 71168, 71232, 71236, 71236, 71248, 71257, 71296, 71352, 71360, 71369, 71424, 71450, 71453, 71467, 71472, 71481, 71680, 71738, 71840, 71913, 71935, 71935, 72096, 72103, 72106, 72151, 72154, 72161, 72163, 72164, 72192, 72254, 72263, 72263, 72272, 72345, 72349, 72349, 72384, 72440, 72704, 72712, 72714, 72758, 72760, 72768, 72784, 72793, 72818, 72847, 72850, 72871, 72873, 72886, 72960, 72966, 72968, 72969, 72971, 73014, 73018, 73018, 73020, 73021, 73023, 73031, 73040, 73049, 73056, 73061, 73063, 73064, 73066, 73102, 73104, 73105, 73107, 73112, 73120, 73129, 73440, 73462, 73728, 74649, 74752, 74862, 74880, 75075, 77824, 78894, 82944, 83526, 92160, 92728, 92736, 92766, 92768, 92777, 92880, 92909, 92912, 92916, 92928, 92982, 92992, 92995, 93008, 93017, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94031, 94087, 94095, 94111, 94176, 94177, 94179, 94179, 94208, 100343, 100352, 101106, 110592, 110878, 110928, 110930, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 113821, 113822, 119141, 119145, 119149, 119154, 119163, 119170, 119173, 119179, 119210, 119213, 119362, 119364, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 120782, 120831, 121344, 121398, 121403, 121452, 121461, 121461, 121476, 121476, 121499, 121503, 121505, 121519, 122880, 122886, 122888, 122904, 122907, 122913, 122915, 122916, 122918, 122922, 123136, 123180, 123184, 123197, 123200, 123209, 123214, 123214, 123584, 123641, 124928, 125124, 125136, 125142, 125184, 125259, 125264, 125273, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 131072, 173782, 173824, 177972, 177984, 178205, 178208, 183969, 183984, 191456, 194560, 195101, 917760, 917999 }; - -const start_codepoints_including_ascii = [_]i32{ - 'a', - 'z', - 'A', - 'Z', - '_', - '_', - '$', - '$', -} ++ start_codepoints; -const part_codepoints_including_ascii = [_]i32{ - 'a', - 'z', - 'A', - 'Z', - '0', - '9', - '_', - '_', - '$', - '$', -} ++ part_codepoints; - -const id_start_range: [2]i32 = brk: { - var minmax = [2]i32{ std.math.maxInt(i32), 0 }; - - for (start_codepoints_including_ascii) |c| { - @setEvalBranchQuota(9999); - minmax[0] = if (c < minmax[0]) c else minmax[0]; - minmax[1] = if (c > minmax[1]) c else minmax[1]; - } - - break :brk minmax; -}; -const id_start_count = id_start_range[1] - id_start_range[0] + 1; - -const id_end_range: [2]i32 = brk: { - var minmax = [2]i32{ std.math.maxInt(i32), 0 }; - - for (part_codepoints_including_ascii) |c| { - @setEvalBranchQuota(9999); - minmax[0] = if (c < minmax[0]) c else minmax[0]; - minmax[1] = if (c > minmax[1]) c else minmax[1]; - } - - break :brk minmax; -}; - -const id_end_count = id_end_range[1] - id_end_range[0] + 1; - -// Do not use std.bit_set. -pub const IDStartType = @import("../bit_set.zig").StaticBitSet(id_start_count + 1); -pub const IDContinueType = @import("../bit_set.zig").StaticBitSet(id_end_count + 1); - -pub const id_start: IDStartType = brk: { - var bits: IDStartType = IDStartType.initEmpty(); - var i: usize = 0; - - @setEvalBranchQuota(999999); - while (i < start_codepoints_including_ascii.len) : (i += 2) { - var min = start_codepoints_including_ascii[i]; - const max = start_codepoints_including_ascii[i + 1]; - while (min <= max) : (min += 1) { - @setEvalBranchQuota(999999); - bits.set(id_start_range[1] - min); - } - } - break :brk bits; -}; - -pub const id_continue: IDContinueType = brk: { - var bits: IDContinueType = IDContinueType.initEmpty(); - var i: usize = 0; - - while (i < part_codepoints_including_ascii.len) : (i += 2) { - var min = part_codepoints_including_ascii[i]; - const max = part_codepoints_including_ascii[i + 1]; - @setEvalBranchQuota(999999); - while (min <= max) : (min += 1) { - @setEvalBranchQuota(999999); - bits.set(id_end_range[1] - min); - } - } - break :brk bits; -}; - -const Cache = @import("./identifier_cache.zig"); - -pub const id_start_cached = Cache.CachedBitset{ .range = id_start_range, .len = id_start_count + 1 }; -pub const id_continue_cached = Cache.CachedBitset{ .range = id_end_range, .len = id_end_count + 1 }; - -fn main() anyerror!void { - const id_continue_data = std.mem.asBytes(&id_continue.masks); - const id_start_data = std.mem.asBytes(&id_start.masks); - - try std.posix.chdir(std.fs.path.dirname(@src().file).?); - var start = try std.fs.cwd().createFileZ("id_start_bitset.meta.blob", .{ .truncate = true }); - try start.writeAll(std.mem.asBytes(&id_start_cached)); - start.close(); - - var start_masks = try std.fs.cwd().createFileZ("id_start_bitset.blob", .{ .truncate = true }); - try start_masks.writeAll(id_start_data); - start_masks.close(); - - var continue_meta = try std.fs.cwd().createFileZ("id_continue_bitset.meta.blob", .{ .truncate = true }); - var continue_blob = try std.fs.cwd().createFileZ("id_continue_bitset.blob", .{ .truncate = true }); - - try continue_meta.writeAll(std.mem.asBytes(&id_continue_cached)); - continue_meta.close(); - try continue_blob.writeAll(std.mem.asBytes(id_continue_data)); - continue_blob.close(); -} - -test "Check" { - const id_start_cached_correct = Cache.CachedBitset{ .range = id_start_range, .len = id_start_count + 1 }; - const id_continue_cached_correct = Cache.CachedBitset{ .range = id_end_range, .len = id_end_count + 1 }; - try std.posix.chdir(std.fs.path.dirname(@src().file).?); - var start_cached = try std.fs.cwd().openFileZ("id_start_bitset.meta.blob", .{ .mode = .read_only }); - const start_cached_data = try start_cached.readToEndAlloc(std.heap.c_allocator, 4096); - - try std.testing.expectEqualSlices(u8, start_cached_data, std.mem.asBytes(&id_start_cached_correct)); - - var continue_cached = try std.fs.cwd().openFileZ("id_continue_bitset.meta.blob", .{ .mode = .read_only }); - const continue_cached_data = try continue_cached.readToEndAlloc(std.heap.c_allocator, 4096); - - try std.testing.expectEqualSlices(u8, continue_cached_data, std.mem.asBytes(&id_continue_cached_correct)); - - var start_blob_file = try std.fs.cwd().openFileZ("id_start_bitset.blob", .{ .mode = .read_only }); - const start_blob_data = try start_blob_file.readToEndAlloc(std.heap.c_allocator, try start_blob_file.getEndPos()); - var continue_blob_file = try std.fs.cwd().openFileZ("id_continue_bitset.blob", .{ .mode = .read_only }); - const continue_blob_data = try continue_blob_file.readToEndAlloc(std.heap.c_allocator, try continue_blob_file.getEndPos()); - - try std.testing.expectEqualSlices(u8, start_blob_data, std.mem.asBytes(&id_start.masks)); - try std.testing.expectEqualSlices(u8, continue_blob_data, std.mem.asBytes(&id_continue.masks)); -} - -test "Check #2" { - const id_start_cached_correct = Cache.CachedBitset{ .range = id_start_range, .len = id_start_count + 1 }; - const id_continue_cached_correct = Cache.CachedBitset{ .range = id_end_range, .len = id_end_count + 1 }; - try std.posix.chdir(std.fs.path.dirname(@src().file).?); - const start_cached_data = std.mem.asBytes(&Cache.id_start_meta); - - try std.testing.expectEqualSlices(u8, start_cached_data, std.mem.asBytes(&id_start_cached_correct)); - - const continue_cached_data = std.mem.asBytes(&Cache.id_continue_meta); - - try std.testing.expectEqualSlices(u8, continue_cached_data, std.mem.asBytes(&id_continue_cached_correct)); - - const start_blob_data = Cache.id_start_masks; - const continue_blob_data = Cache.id_continue_masks; - - try std.testing.expectEqualSlices(u8, start_blob_data, std.mem.asBytes(&id_start.masks)); - try std.testing.expectEqualSlices(u8, continue_blob_data, std.mem.asBytes(&id_continue.masks)); -} - -test "Check #3" { - try std.testing.expectEqualSlices(usize, &Cache.id_start.masks, &id_start.masks); - try std.testing.expectEqualSlices(usize, &Cache.id_continue.masks, &id_continue.masks); - - var i: i32 = id_end_range[0]; - while (i < id_end_range[1]) : (i += 1) { - try std.testing.expectEqual(id_continue.isSet(@as(usize, @intCast(id_end_range[1] - i))), Cache.id_continue.isSet(@as(usize, @intCast(id_end_range[1] - i)))); - } - - i = id_start_range[0]; - while (i < id_start_range[1]) : (i += 1) { - try std.testing.expectEqual(id_start.isSet(@as(usize, @intCast(id_start_range[1] - i))), Cache.id_start.isSet(@as(usize, @intCast(id_start_range[1] - i)))); - } -} From bba998a6119cab36a890c066e6e7757d6e8fe9c1 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 26 Dec 2024 11:48:11 -0800 Subject: [PATCH 098/125] Create .cursorignore --- .cursorignore | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .cursorignore diff --git a/.cursorignore b/.cursorignore new file mode 100644 index 0000000000..122894c7f4 --- /dev/null +++ b/.cursorignore @@ -0,0 +1,6 @@ +# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv) +bench +vendor +*-fixture.{js,ts} +zig-cache +packages/bun-uws/fuzzing \ No newline at end of file From 19675f474a84313936c356ec64167fe3ef4e9d70 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 26 Dec 2024 11:48:30 -0800 Subject: [PATCH 099/125] Update .cursorignore --- .cursorignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.cursorignore b/.cursorignore index 122894c7f4..e56b21e52f 100644 --- a/.cursorignore +++ b/.cursorignore @@ -3,4 +3,5 @@ bench vendor *-fixture.{js,ts} zig-cache -packages/bun-uws/fuzzing \ No newline at end of file +packages/bun-uws/fuzzing +build \ No newline at end of file From 4bcc5b25d97938524ff42b1589ca67fc02bfb776 Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Fri, 27 Dec 2024 01:34:49 -0800 Subject: [PATCH 100/125] node: fix all of test-event-emitter (#16009) --- scripts/check-node-all.sh | 41 +++++ scripts/check-node.sh | 8 +- src/bake/BakeProduction.cpp | 3 +- src/bake/BakeSourceProvider.cpp | 7 +- src/bun.js/ConsoleObject.zig | 120 ++++++------ src/bun.js/api/BunObject.zig | 24 ++- src/bun.js/bindings/BunPlugin.cpp | 3 +- src/bun.js/bindings/BunProcess.cpp | 67 ++----- src/bun.js/bindings/CallSite.cpp | 4 +- src/bun.js/bindings/CommonJSModuleRecord.cpp | 3 +- src/bun.js/bindings/ConsoleObject.cpp | 6 +- src/bun.js/bindings/ErrorCode.cpp | 160 ++++++++++++++-- src/bun.js/bindings/ErrorCode.h | 1 + src/bun.js/bindings/ErrorCode.ts | 1 + src/bun.js/bindings/ImportMetaObject.cpp | 3 +- src/bun.js/bindings/JSBundlerPlugin.cpp | 3 +- .../bindings/JSEnvironmentVariableMap.cpp | 2 +- src/bun.js/bindings/JSFFIFunction.cpp | 21 ++- src/bun.js/bindings/UtilInspect.cpp | 6 +- src/bun.js/bindings/ZigGlobalObject.cpp | 12 +- src/bun.js/bindings/bindings.zig | 43 +---- src/bun.js/bindings/webcore/JSDOMIterator.h | 3 +- src/bun.js/javascript.zig | 4 +- src/bun.js/modules/BunJSCModule.h | 5 +- src/bun.js/modules/NodeUtilTypesModule.h | 114 +++++------- src/bun.js/test/diff_format.zig | 4 +- src/bun.js/test/pretty_format.zig | 37 ++-- src/bun.js/web_worker.zig | 10 +- src/bun.js/webcore/body.zig | 4 +- src/bun.js/webcore/request.zig | 4 +- src/bun.js/webcore/response.zig | 8 +- src/js/internal/errors.ts | 1 + src/js/node/domain.ts | 15 ++ src/js/node/events.ts | 172 ++++++++++++------ test/js/bun/net/socket.test.ts | 4 +- .../child_process/child_process-node.test.js | 4 +- .../node/child_process/child_process.test.ts | 2 +- .../test/parallel/test-async-hooks-vm-gc.js | 15 ++ .../parallel/test-dgram-send-address-types.js | 47 +++++ .../parallel/test-event-emitter-errors.js | 37 ++++ .../test-event-emitter-invalid-listener.js | 20 ++ ...st-event-emitter-listeners-side-effects.js | 60 ++++++ ...-emitter-max-listeners-warning-for-null.js | 22 +++ ...mitter-max-listeners-warning-for-symbol.js | 24 +++ ...est-event-emitter-max-listeners-warning.js | 30 +++ .../test-event-emitter-max-listeners.js | 88 +++++++++ ...mitter-no-error-provided-to-error-event.js | 56 ++++++ ...test-event-emitter-remove-all-listeners.js | 123 +++++++++++++ .../test-event-emitter-remove-listeners.js | 170 +++++++++++++++++ .../test-require-delete-array-iterator.js | 13 ++ .../test-stream-readable-setEncoding-null.js | 15 ++ .../parallel/test-stream-readable-unshift.js | 170 +++++++++++++++++ .../node/test/parallel/test-util-styletext.js | 43 +++++ .../test-vm-global-property-enumerator.js | 49 +++++ .../test-vm-global-property-prototype.js | 83 +++++++++ test/js/node/test/parallel/test-weakref.js | 13 ++ ...orker-message-channel-sharedarraybuffer.js | 28 +++ ...est-worker-workerdata-sharedarraybuffer.js | 32 ++++ .../test-zlib-deflate-constructors.js | 18 +- .../test/parallel/test-zlib-failed-init.js | 4 +- .../test/parallel/test-zlib-flush-flags.js | 6 +- .../test-zlib-not-string-or-buffer.js | 30 +++ test/js/node/util/bun-inspect.test.ts | 4 +- test/js/node/util/custom-inspect.test.js | 7 +- test/js/node/util/test-util-types.test.js | 1 + 65 files changed, 1733 insertions(+), 404 deletions(-) create mode 100755 scripts/check-node-all.sh create mode 100644 test/js/node/test/parallel/test-async-hooks-vm-gc.js create mode 100644 test/js/node/test/parallel/test-dgram-send-address-types.js create mode 100644 test/js/node/test/parallel/test-event-emitter-errors.js create mode 100644 test/js/node/test/parallel/test-event-emitter-invalid-listener.js create mode 100644 test/js/node/test/parallel/test-event-emitter-listeners-side-effects.js create mode 100644 test/js/node/test/parallel/test-event-emitter-max-listeners-warning-for-null.js create mode 100644 test/js/node/test/parallel/test-event-emitter-max-listeners-warning-for-symbol.js create mode 100644 test/js/node/test/parallel/test-event-emitter-max-listeners-warning.js create mode 100644 test/js/node/test/parallel/test-event-emitter-max-listeners.js create mode 100644 test/js/node/test/parallel/test-event-emitter-no-error-provided-to-error-event.js create mode 100644 test/js/node/test/parallel/test-event-emitter-remove-all-listeners.js create mode 100644 test/js/node/test/parallel/test-event-emitter-remove-listeners.js create mode 100644 test/js/node/test/parallel/test-require-delete-array-iterator.js create mode 100644 test/js/node/test/parallel/test-stream-readable-setEncoding-null.js create mode 100644 test/js/node/test/parallel/test-stream-readable-unshift.js create mode 100644 test/js/node/test/parallel/test-util-styletext.js create mode 100644 test/js/node/test/parallel/test-vm-global-property-enumerator.js create mode 100644 test/js/node/test/parallel/test-vm-global-property-prototype.js create mode 100644 test/js/node/test/parallel/test-weakref.js create mode 100644 test/js/node/test/parallel/test-worker-message-channel-sharedarraybuffer.js create mode 100644 test/js/node/test/parallel/test-worker-workerdata-sharedarraybuffer.js create mode 100644 test/js/node/test/parallel/test-zlib-not-string-or-buffer.js diff --git a/scripts/check-node-all.sh b/scripts/check-node-all.sh new file mode 100755 index 0000000000..9358e55ae9 --- /dev/null +++ b/scripts/check-node-all.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +# How to use this script: +# 1. Pick a module from node's standard library (e.g. 'assert', 'fs') +# 2. Copy over relevant tests from node's parallel test suite into test/js/node/test/parallel +# 3. Run this script, e.g. `./scripts/check-node.sh fs` +# 4. Tests that passed get staged for commit + +i=0 +j=0 + +if [ -z "$1" ] +then + echo "Usage: $0 " + exit 1 +fi + +case $1 in + -h|--help) + echo "Usage: $0 " + echo "Run all parallel tests for a single module in node's standard library" + exit 0 + ;; +esac + +export BUN_DEBUG_QUIET_LOGS=1 + +for x in $(find test/js/node/test/parallel -type f -name "test-$1*.js") +do + i=$((i+1)) + echo ./$x + if timeout 2 $PWD/build/debug/bun-debug ./$x + then + j=$((j+1)) + git add ./$x + fi + echo +done + +echo $i tests tested +echo $j tests passed diff --git a/scripts/check-node.sh b/scripts/check-node.sh index 47c2787186..a3c3159525 100755 --- a/scripts/check-node.sh +++ b/scripts/check-node.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # How to use this script: # 1. Pick a module from node's standard library (e.g. 'assert', 'fs') @@ -9,7 +9,7 @@ i=0 j=0 -if [[ -z $1 ]] +if [ -z "$1" ] then echo "Usage: $0 " exit 1 @@ -18,13 +18,12 @@ fi case $1 in -h|--help) echo "Usage: $0 " - echo "Run all parallel tests for a single module in node's standard library" + echo "Run all unstaged parallel tests for a single module in node's standard library" exit 0 ;; esac export BUN_DEBUG_QUIET_LOGS=1 -export NO_COLOR=1 for x in $(git ls-files test/js/node/test/parallel --exclude-standard --others | grep test-$1) do @@ -36,7 +35,6 @@ do git add ./$x fi echo - echo done echo $i tests tested diff --git a/src/bake/BakeProduction.cpp b/src/bake/BakeProduction.cpp index d7a1fb9842..1db8e9ee5b 100644 --- a/src/bake/BakeProduction.cpp +++ b/src/bake/BakeProduction.cpp @@ -1,5 +1,6 @@ #include "BakeProduction.h" #include "BunBuiltinNames.h" +#include "JavaScriptCore/CallData.h" #include "WebCoreJSBuiltins.h" #include "JavaScriptCore/JSPromise.h" #include "JavaScriptCore/Exception.h" @@ -38,7 +39,7 @@ extern "C" JSC::JSPromise* BakeRenderRoutesForProdStatic( args.append(styles); NakedPtr returnedException = nullptr; - auto result = JSC::call(global, cb, callData, JSC::jsUndefined(), args, returnedException); + auto result = JSC::profiledCall(global, JSC::ProfilingReason::API, cb, callData, JSC::jsUndefined(), args, returnedException); if (UNLIKELY(returnedException)) { // This should be impossible because it returns a promise. return JSC::JSPromise::rejectedPromise(global, returnedException->value()); diff --git a/src/bake/BakeSourceProvider.cpp b/src/bake/BakeSourceProvider.cpp index 2a51ffa0aa..2b1c4a9d14 100644 --- a/src/bake/BakeSourceProvider.cpp +++ b/src/bake/BakeSourceProvider.cpp @@ -1,6 +1,7 @@ // clang-format off #include "BakeSourceProvider.h" #include "BakeGlobalObject.h" +#include "JavaScriptCore/CallData.h" #include "JavaScriptCore/Completion.h" #include "JavaScriptCore/Identifier.h" #include "JavaScriptCore/JSCJSValue.h" @@ -41,7 +42,7 @@ extern "C" JSC::EncodedJSValue BakeLoadInitialServerCode(GlobalObject* global, B args.append(JSC::jsBoolean(separateSSRGraph)); // separateSSRGraph args.append(Zig::ImportMetaObject::create(global, "bake://server-runtime.js"_s)); // importMeta - return JSC::JSValue::encode(JSC::call(global, fn, callData, JSC::jsUndefined(), args)); + return JSC::JSValue::encode(JSC::profiledCall(global, JSC::ProfilingReason::API, fn, callData, JSC::jsUndefined(), args)); } extern "C" JSC::JSInternalPromise* BakeLoadModuleByKey(GlobalObject* global, JSC::JSString* key) { @@ -61,7 +62,7 @@ extern "C" JSC::EncodedJSValue BakeLoadServerHmrPatch(GlobalObject* global, BunS WTF::TextPosition(), JSC::SourceProviderSourceType::Program )); - + JSC::JSValue result = vm.interpreter.executeProgram(sourceCode, global, global); RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode({})); @@ -124,7 +125,7 @@ extern "C" JSC::EncodedJSValue BakeRegisterProductionChunk(JSC::JSGlobalObject* WTF::TextPosition(), JSC::SourceProviderSourceType::Module )); - + global->moduleLoader()->provideFetch(global, key, sourceCode); RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode({})); diff --git a/src/bun.js/ConsoleObject.zig b/src/bun.js/ConsoleObject.zig index b6f05770b6..33ebd2fa14 100644 --- a/src/bun.js/ConsoleObject.zig +++ b/src/bun.js/ConsoleObject.zig @@ -226,7 +226,7 @@ fn messageWithTypeAndLevel_( } if (print_length > 0) - format2( + try format2( level, global, vals, @@ -344,7 +344,7 @@ pub const TablePrinter = struct { value, this.globalObject, false, - ); + ) catch {}; // TODO: return @truncate(width); } @@ -492,7 +492,7 @@ pub const TablePrinter = struct { node.release(); } } - value_formatter.format( + try value_formatter.format( tag, Writer, writer, @@ -772,7 +772,7 @@ pub fn format2( comptime Writer: type, writer: Writer, options: FormatOptions, -) void { +) bun.JSError!void { if (len == 1) { // initialized later in this function. var fmt = ConsoleObject.Formatter{ @@ -795,7 +795,7 @@ pub fn format2( if (level == .Error) { writer.writeAll(comptime Output.prettyFmt("", true)) catch {}; } - fmt.format( + try fmt.format( tag, Writer, writer, @@ -807,7 +807,7 @@ pub fn format2( writer.writeAll(comptime Output.prettyFmt("", true)) catch {}; } } else { - fmt.format( + try fmt.format( tag, Writer, writer, @@ -828,7 +828,7 @@ pub fn format2( } } if (options.enable_colors) { - fmt.format( + try fmt.format( tag, Writer, writer, @@ -837,7 +837,7 @@ pub fn format2( true, ); } else { - fmt.format( + try fmt.format( tag, Writer, writer, @@ -890,7 +890,7 @@ pub fn format2( tag.tag = .{ .StringPossiblyFormatted = {} }; } - fmt.format(tag, Writer, writer, this_value, global, true); + try fmt.format(tag, Writer, writer, this_value, global, true); if (fmt.remaining_values.len == 0) { break; } @@ -912,7 +912,7 @@ pub fn format2( tag.tag = .{ .StringPossiblyFormatted = {} }; } - fmt.format(tag, Writer, writer, this_value, global, false); + try fmt.format(tag, Writer, writer, this_value, global, false); if (fmt.remaining_values.len == 0) break; @@ -988,7 +988,7 @@ pub const Formatter = struct { defer { self.formatter.remaining_values = &[_]JSValue{}; } - self.formatter.format( + try self.formatter.format( Tag.get(self.value, self.formatter.globalThis), @TypeOf(writer), writer, @@ -1367,7 +1367,7 @@ pub const Formatter = struct { slice_: Slice, global: *JSGlobalObject, comptime enable_ansi_colors: bool, - ) void { + ) bun.JSError!void { var writer = WrappedWriter(Writer){ .ctx = writer_, .estimated_line_length = &this.estimated_line_length, @@ -1425,7 +1425,7 @@ pub const Formatter = struct { const max_before_e_notation = 1000000000000000000000; const min_before_e_notation = 0.000001; switch (token) { - .s => this.printAs(Tag.String, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors), + .s => try this.printAs(Tag.String, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors), .i => { // 1. If Type(current) is Symbol, let converted be NaN // 2. Otherwise, let converted be the result of Call(%parseInt%, undefined, current, 10) @@ -1551,7 +1551,7 @@ pub const Formatter = struct { // > implementation-specific, potentially-interactive representation // > of an object judged to be maximally useful and informative. } - this.format(Tag.get(next_value, global), Writer, writer_, next_value, global, enable_ansi_colors); + try this.format(Tag.get(next_value, global), Writer, writer_, next_value, global, enable_ansi_colors); }, .c => { @@ -1722,7 +1722,7 @@ pub const Formatter = struct { key, this.formatter.globalThis, enable_ansi_colors, - ); + ) catch {}; // TODO: this.writer.writeAll(": ") catch unreachable; const value_tag = Tag.getAdvanced(value, globalObject, .{ .hide_global = true, @@ -1735,7 +1735,7 @@ pub const Formatter = struct { value, this.formatter.globalThis, enable_ansi_colors, - ); + ) catch {}; // TODO: } else { if (!single_line) { this.writer.writeAll("\n") catch unreachable; @@ -1752,7 +1752,7 @@ pub const Formatter = struct { nextValue, this.formatter.globalThis, enable_ansi_colors, - ); + ) catch {}; // TODO: } this.count += 1; if (!single_line) { @@ -1793,7 +1793,7 @@ pub const Formatter = struct { nextValue, this.formatter.globalThis, enable_ansi_colors, - ); + ) catch {}; // TODO: if (!single_line) { this.formatter.printComma(Writer, this.writer, enable_ansi_colors) catch unreachable; @@ -1953,7 +1953,7 @@ pub const Formatter = struct { } } - this.format(tag, Writer, ctx.writer, value, globalThis, enable_ansi_colors); + this.format(tag, Writer, ctx.writer, value, globalThis, enable_ansi_colors) catch {}; // TODO: if (tag.cell.isStringLike()) { if (comptime enable_ansi_colors) { @@ -1976,7 +1976,6 @@ pub const Formatter = struct { } extern fn JSC__JSValue__callCustomInspectFunction( - *JSC.JSGlobalObject, *JSC.JSGlobalObject, JSValue, JSValue, @@ -1994,12 +1993,11 @@ pub const Formatter = struct { value: JSValue, jsType: JSValue.JSType, comptime enable_ansi_colors: bool, - ) void { + ) bun.JSError!void { if (this.failed) return; if (this.globalThis.hasException()) { - this.failed = true; - return; + return error.JSError; } var writer = WrappedWriter(Writer){ .ctx = writer_, .estimated_line_length = &this.estimated_line_length }; @@ -2042,14 +2040,11 @@ pub const Formatter = struct { defer str.deinit(); this.addForNewLine(str.len); const slice = str.slice(); - this.writeWithFormatting(Writer, writer_, @TypeOf(slice), slice, this.globalThis, enable_ansi_colors); + try this.writeWithFormatting(Writer, writer_, @TypeOf(slice), slice, this.globalThis, enable_ansi_colors); }, .String => { // This is called from the '%s' formatter, so it can actually be any value - const str: bun.String = bun.String.tryFromJS(value, this.globalThis) orelse { - writer.failed = true; - return; - }; + const str: bun.String = try bun.String.fromJS2(value, this.globalThis); defer str.deref(); this.addForNewLine(str.length()); @@ -2067,7 +2062,7 @@ pub const Formatter = struct { writer.writeAll(Output.prettyFmt("", true)); if (str.isUTF16()) { - this.printAs(.JSON, Writer, writer_, value, .StringObject, enable_ansi_colors); + try this.printAs(.JSON, Writer, writer_, value, .StringObject, enable_ansi_colors); return; } @@ -2179,7 +2174,6 @@ pub const Formatter = struct { // Call custom inspect function. Will return the error if there is one // we'll need to pass the callback through to the "this" value in here const result = JSC__JSValue__callCustomInspectFunction( - JSC.VirtualMachine.get().global, this.globalThis, this.custom_formatted_object.function, this.custom_formatted_object.this, @@ -2189,16 +2183,13 @@ pub const Formatter = struct { &is_exception, ); if (is_exception) { - // Previously, this printed [native code] - // TODO: in the future, should this throw when in Bun.inspect? - writer.print("[custom formatter threw an exception]", .{}); - return; + return error.JSError; } // Strings are printed directly, otherwise we recurse. It is possible to end up in an infinite loop. if (result.isString()) { writer.print("{}", .{result.fmtString(this.globalThis)}); } else { - this.format(ConsoleObject.Formatter.Tag.get(result, this.globalThis), Writer, writer_, result, this.globalThis, enable_ansi_colors); + try this.format(ConsoleObject.Formatter.Tag.get(result, this.globalThis), Writer, writer_, result, this.globalThis, enable_ansi_colors); } }, .Symbol => { @@ -2355,11 +2346,7 @@ pub const Formatter = struct { break :first; } - this.format(tag, Writer, writer_, element, this.globalThis, enable_ansi_colors); - if (this.globalThis.hasException()) { - this.failed = true; - } - if (this.failed) return; + try this.format(tag, Writer, writer_, element, this.globalThis, enable_ansi_colors); if (tag.cell.isStringLike()) { if (comptime enable_ansi_colors) { @@ -2424,8 +2411,7 @@ pub const Formatter = struct { .disable_inspect_custom = this.disable_inspect_custom, }); - this.format(tag, Writer, writer_, element, this.globalThis, enable_ansi_colors); - if (this.failed) return; + try this.format(tag, Writer, writer_, element, this.globalThis, enable_ansi_colors); if (tag.cell.isStringLike()) { if (comptime enable_ansi_colors) { @@ -2469,7 +2455,7 @@ pub const Formatter = struct { }; value.forEachPropertyNonIndexed(this.globalThis, &iter, Iterator.forEach); if (this.globalThis.hasException()) { - this.failed = true; + return error.JSError; } if (this.failed) return; } @@ -2508,7 +2494,7 @@ pub const Formatter = struct { this.quote_keys = true; defer this.quote_keys = prev_quote_keys; - return this.printAs( + return try this.printAs( .Object, Writer, writer_, @@ -2524,7 +2510,7 @@ pub const Formatter = struct { this.quote_keys = true; defer this.quote_keys = prev_quote_keys; - return this.printAs( + return try this.printAs( .Object, Writer, writer_, @@ -2536,7 +2522,7 @@ pub const Formatter = struct { } // this case should never happen - return this.printAs(.Undefined, Writer, writer_, .undefined, .Cell, enable_ansi_colors); + return try this.printAs(.Undefined, Writer, writer_, .undefined, .Cell, enable_ansi_colors); } else if (value.as(JSC.API.Bun.Timer.TimerObject)) |timer| { this.addForNewLine("Timeout(# ) ".len + bun.fmt.fastDigitCount(@as(u64, @intCast(@max(timer.id, 0))))); if (timer.kind == .setInterval) { @@ -2561,12 +2547,12 @@ pub const Formatter = struct { return; } else if (jsType != .DOMWrapper) { if (value.isCallable(this.globalThis.vm())) { - return this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors); + return try this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors); } - return this.printAs(.Object, Writer, writer_, value, jsType, enable_ansi_colors); + return try this.printAs(.Object, Writer, writer_, value, jsType, enable_ansi_colors); } - return this.printAs(.Object, Writer, writer_, value, .Event, enable_ansi_colors); + return try this.printAs(.Object, Writer, writer_, value, .Event, enable_ansi_colors); }, .NativeCode => { if (value.getClassInfoName()) |class_name| { @@ -2790,7 +2776,7 @@ pub const Formatter = struct { const prev_quote_keys = this.quote_keys; this.quote_keys = true; defer this.quote_keys = prev_quote_keys; - this.printAs(.Object, Writer, writer_, result, value.jsType(), enable_ansi_colors); + try this.printAs(.Object, Writer, writer_, result, value.jsType(), enable_ansi_colors); return; } @@ -2833,7 +2819,7 @@ pub const Formatter = struct { const event_type = switch (EventType.map.fromJS(this.globalThis, event_type_value) orelse .unknown) { .MessageEvent, .ErrorEvent => |evt| evt, else => { - return this.printAs(.Object, Writer, writer_, value, .Event, enable_ansi_colors); + return try this.printAs(.Object, Writer, writer_, value, .Event, enable_ansi_colors); }, }; @@ -2879,7 +2865,7 @@ pub const Formatter = struct { .hide_global = true, .disable_inspect_custom = this.disable_inspect_custom, }); - this.format(tag, Writer, writer_, message_value, this.globalThis, enable_ansi_colors); + try this.format(tag, Writer, writer_, message_value, this.globalThis, enable_ansi_colors); if (this.failed) return; this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable; if (!this.single_line) { @@ -2903,7 +2889,7 @@ pub const Formatter = struct { .hide_global = true, .disable_inspect_custom = this.disable_inspect_custom, }); - this.format(tag, Writer, writer_, data, this.globalThis, enable_ansi_colors); + try this.format(tag, Writer, writer_, data, this.globalThis, enable_ansi_colors); if (this.failed) return; this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable; if (!this.single_line) { @@ -2925,7 +2911,7 @@ pub const Formatter = struct { .hide_global = true, .disable_inspect_custom = this.disable_inspect_custom, }); - this.format(tag, Writer, writer_, error_value, this.globalThis, enable_ansi_colors); + try this.format(tag, Writer, writer_, error_value, this.globalThis, enable_ansi_colors); if (this.failed) return; this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable; if (!this.single_line) { @@ -2999,7 +2985,7 @@ pub const Formatter = struct { this.quote_strings = true; defer this.quote_strings = old_quote_strings; - this.format(Tag.getAdvanced(key_value, this.globalThis, .{ + try this.format(Tag.getAdvanced(key_value, this.globalThis, .{ .hide_global = true, .disable_inspect_custom = this.disable_inspect_custom, }), Writer, writer_, key_value, this.globalThis, enable_ansi_colors); @@ -3053,7 +3039,7 @@ pub const Formatter = struct { } } - this.format(tag, Writer, writer_, property_value, this.globalThis, enable_ansi_colors); + try this.format(tag, Writer, writer_, property_value, this.globalThis, enable_ansi_colors); if (tag.cell.isStringLike()) { if (comptime enable_ansi_colors) { @@ -3116,7 +3102,7 @@ pub const Formatter = struct { this.indent += 1; this.writeIndent(Writer, writer_) catch unreachable; defer this.indent -|= 1; - this.format(Tag.get(children, this.globalThis), Writer, writer_, children, this.globalThis, enable_ansi_colors); + try this.format(Tag.get(children, this.globalThis), Writer, writer_, children, this.globalThis, enable_ansi_colors); } writer.writeAll("\n"); @@ -3139,7 +3125,7 @@ pub const Formatter = struct { var j: usize = 0; while (j < length) : (j += 1) { const child = children.getIndex(this.globalThis, @as(u32, @intCast(j))); - this.format(Tag.getAdvanced(child, this.globalThis, .{ + try this.format(Tag.getAdvanced(child, this.globalThis, .{ .hide_global = true, .disable_inspect_custom = this.disable_inspect_custom, }), Writer, writer_, child, this.globalThis, enable_ansi_colors); @@ -3235,15 +3221,15 @@ pub const Formatter = struct { } if (this.globalThis.hasException()) { - this.failed = true; + return error.JSError; } if (this.failed) return; if (iter.i == 0) { if (value.isClass(this.globalThis)) - this.printAs(.Class, Writer, writer_, value, jsType, enable_ansi_colors) + try this.printAs(.Class, Writer, writer_, value, jsType, enable_ansi_colors) else if (value.isCallable(this.globalThis.vm())) - this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors) + try this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors) else { if (getObjectName(this.globalThis, value)) |name_str| { writer.print("{} ", .{name_str}); @@ -3373,7 +3359,7 @@ pub const Formatter = struct { } // TODO: if (options.showProxy), print like `Proxy { target: ..., handlers: ... }` // this is default off so it is not used. - this.format(ConsoleObject.Formatter.Tag.get(target, this.globalThis), Writer, writer_, target, this.globalThis, enable_ansi_colors); + try this.format(ConsoleObject.Formatter.Tag.get(target, this.globalThis), Writer, writer_, target, this.globalThis, enable_ansi_colors); }, } } @@ -3408,7 +3394,7 @@ pub const Formatter = struct { } } - pub fn format(this: *ConsoleObject.Formatter, result: Tag.Result, comptime Writer: type, writer: Writer, value: JSValue, globalThis: *JSGlobalObject, comptime enable_ansi_colors: bool) void { + pub fn format(this: *ConsoleObject.Formatter, result: Tag.Result, comptime Writer: type, writer: Writer, value: JSValue, globalThis: *JSGlobalObject, comptime enable_ansi_colors: bool) bun.JSError!void { const prevGlobalThis = this.globalThis; defer this.globalThis = prevGlobalThis; this.globalThis = globalThis; @@ -3418,11 +3404,11 @@ pub const Formatter = struct { // it _should_ limit the stack usage because each version of the // function will be relatively small switch (result.tag.tag()) { - inline else => |tag| this.printAs(tag, Writer, writer, value, result.cell, enable_ansi_colors), + inline else => |tag| try this.printAs(tag, Writer, writer, value, result.cell, enable_ansi_colors), .CustomFormattedObject => { this.custom_formatted_object = result.tag.CustomFormattedObject; - this.printAs(.CustomFormattedObject, Writer, writer, value, result.cell, enable_ansi_colors); + try this.printAs(.CustomFormattedObject, Writer, writer, value, result.cell, enable_ansi_colors); }, } } @@ -3566,9 +3552,9 @@ pub fn timeLog( const tag = ConsoleObject.Formatter.Tag.get(arg, global); _ = writer.write(" ") catch 0; if (Output.enable_ansi_colors_stderr) { - fmt.format(tag, Writer, writer, arg, global, true); + fmt.format(tag, Writer, writer, arg, global, true) catch {}; // TODO: } else { - fmt.format(tag, Writer, writer, arg, global, false); + fmt.format(tag, Writer, writer, arg, global, false) catch {}; // TODO: } } _ = writer.write("\n") catch 0; diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index 259e741f33..3d06db4368 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -515,7 +515,7 @@ pub fn inspect(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.J const Writer = @TypeOf(writer); // we buffer this because it'll almost always be < 4096 // when it's under 4096, we want to avoid the dynamic allocation - ConsoleObject.format2( + try ConsoleObject.format2( .Debug, globalThis, @as([*]const JSValue, @ptrCast(&value)), @@ -525,13 +525,8 @@ pub fn inspect(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.J writer, formatOptions, ); - if (globalThis.hasException()) { - return .zero; - } - - buffered_writer.flush() catch { - return globalThis.throwOutOfMemory(); - }; + if (globalThis.hasException()) return error.JSError; + buffered_writer.flush() catch return globalThis.throwOutOfMemory(); // we are going to always clone to keep things simple for now // the common case here will be stack-allocated, so it should be fine @@ -541,6 +536,19 @@ pub fn inspect(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.J return ret; } +export fn Bun__inspect(globalThis: *JSGlobalObject, value: JSValue) ZigString { + // very stable memory address + var array = MutableString.init(getAllocator(globalThis), 0) catch unreachable; + var buffered_writer = MutableString.BufferedWriter{ .context = &array }; + const writer = buffered_writer.writer(); + + var formatter = ConsoleObject.Formatter{ .globalThis = globalThis }; + writer.print("{}", .{value.toFmt(&formatter)}) catch return ZigString.Empty; + buffered_writer.flush() catch return ZigString.Empty; + + return ZigString.init(array.slice()).withEncoding(); +} + pub fn getInspect(globalObject: *JSC.JSGlobalObject, _: *JSC.JSObject) JSC.JSValue { const fun = JSC.createCallback(globalObject, ZigString.static("inspect"), 2, inspect); var str = ZigString.init("nodejs.util.inspect.custom"); diff --git a/src/bun.js/bindings/BunPlugin.cpp b/src/bun.js/bindings/BunPlugin.cpp index 0f56b920d9..1c18382068 100644 --- a/src/bun.js/bindings/BunPlugin.cpp +++ b/src/bun.js/bindings/BunPlugin.cpp @@ -1,5 +1,6 @@ #include "BunPlugin.h" +#include "JavaScriptCore/CallData.h" #include "JavaScriptCore/ExceptionScope.h" #include "JavaScriptCore/JSCast.h" #include "headers-handwritten.h" @@ -465,7 +466,7 @@ JSObject* JSModuleMock::executeOnce(JSC::JSGlobalObject* lexicalGlobalObject) } JSObject* callback = callbackValue.getObject(); - JSC::JSValue result = JSC::call(lexicalGlobalObject, callback, JSC::getCallData(callback), JSC::jsUndefined(), ArgList()); + JSC::JSValue result = JSC::profiledCall(lexicalGlobalObject, ProfilingReason::API, callback, JSC::getCallData(callback), JSC::jsUndefined(), ArgList()); RETURN_IF_EXCEPTION(scope, {}); if (!result.isObject()) { diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index fdc1bf72c7..269e860d07 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -4,6 +4,7 @@ #include #include #include "CommonJSModuleRecord.h" +#include "JavaScriptCore/CallData.h" #include "JavaScriptCore/CatchScope.h" #include "JavaScriptCore/JSCJSValue.h" #include "JavaScriptCore/JSCast.h" @@ -1143,11 +1144,11 @@ JSC_DEFINE_HOST_FUNCTION(Process_emitWarning, (JSGlobalObject * lexicalGlobalObj } WTF::String str = arg0.toWTFString(globalObject); - return createError(globalObject, str); + auto err = createError(globalObject, str); + err->putDirect(vm, vm.propertyNames->name, jsString(vm, String("warn"_s)), JSC::PropertyAttribute::DontEnum | 0); + return err; })(); - errorInstance->putDirect(vm, vm.propertyNames->name, jsString(vm, String("warn"_s)), JSC::PropertyAttribute::DontEnum | 0); - auto ident = Identifier::fromString(vm, "warning"_s); if (process->wrapped().hasEventListeners(ident)) { JSC::MarkedArgumentBuffer args; @@ -1158,8 +1159,8 @@ JSC_DEFINE_HOST_FUNCTION(Process_emitWarning, (JSGlobalObject * lexicalGlobalObj } auto jsArgs = JSValue::encode(errorInstance); - Bun__ConsoleObject__messageWithTypeAndLevel(reinterpret_cast(globalObject->consoleClient().get())->m_client, static_cast(MessageType::Log), - static_cast(MessageLevel::Warning), globalObject, &jsArgs, 1); + Bun__ConsoleObject__messageWithTypeAndLevel(reinterpret_cast(globalObject->consoleClient().get())->m_client, static_cast(MessageType::Log), static_cast(MessageLevel::Warning), globalObject, &jsArgs, 1); + RETURN_IF_EXCEPTION(scope, {}); return JSValue::encode(jsUndefined()); } @@ -1905,7 +1906,7 @@ static JSValue constructStdioWriteStream(JSC::JSGlobalObject* globalObject, int JSC::CallData callData = JSC::getCallData(getStdioWriteStream); NakedPtr returnedException = nullptr; - auto result = JSC::call(globalObject, getStdioWriteStream, callData, globalObject->globalThis(), args, returnedException); + auto result = JSC::profiledCall(globalObject, ProfilingReason::API, getStdioWriteStream, callData, globalObject->globalThis(), args, returnedException); RETURN_IF_EXCEPTION(scope, {}); if (auto* exception = returnedException.get()) { @@ -1958,7 +1959,7 @@ static JSValue constructStdin(VM& vm, JSObject* processObject) JSC::CallData callData = JSC::getCallData(getStdioWriteStream); NakedPtr returnedException = nullptr; - auto result = JSC::call(globalObject, getStdioWriteStream, callData, globalObject, args, returnedException); + auto result = JSC::profiledCall(globalObject, ProfilingReason::API, getStdioWriteStream, callData, globalObject, args, returnedException); RETURN_IF_EXCEPTION(scope, {}); if (auto* exception = returnedException.get()) { @@ -2028,7 +2029,7 @@ static JSValue constructProcessChannel(VM& vm, JSObject* processObject) JSC::CallData callData = JSC::getCallData(getControl); NakedPtr returnedException = nullptr; - auto result = JSC::call(globalObject, getControl, callData, globalObject->globalThis(), args, returnedException); + auto result = JSC::profiledCall(globalObject, ProfilingReason::API, getControl, callData, globalObject->globalThis(), args, returnedException); RETURN_IF_EXCEPTION(scope, {}); if (auto* exception = returnedException.get()) { @@ -2195,7 +2196,7 @@ inline JSValue processBindingUtil(Zig::GlobalObject* globalObject, JSC::VM& vm) auto callData = JSC::getCallData(fn); JSC::MarkedArgumentBuffer args; args.append(jsString(vm, String("util/types"_s))); - return JSC::call(globalObject, fn, callData, globalObject, args); + return JSC::profiledCall(globalObject, ProfilingReason::API, fn, callData, globalObject, args); } inline JSValue processBindingConfig(Zig::GlobalObject* globalObject, JSC::VM& vm) @@ -2322,37 +2323,11 @@ static Structure* constructMemoryUsageStructure(JSC::VM& vm, JSC::JSGlobalObject { JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype(globalObject, globalObject->objectPrototype(), 5); PropertyOffset offset; - structure = structure->addPropertyTransition( - vm, - structure, - JSC::Identifier::fromString(vm, "rss"_s), - 0, - offset); - structure = structure->addPropertyTransition( - vm, - structure, - JSC::Identifier::fromString(vm, "heapTotal"_s), - 0, - offset); - structure = structure->addPropertyTransition( - vm, - structure, - JSC::Identifier::fromString(vm, "heapUsed"_s), - 0, - offset); - structure = structure->addPropertyTransition( - vm, - structure, - JSC::Identifier::fromString(vm, "external"_s), - 0, - offset); - structure = structure->addPropertyTransition( - vm, - structure, - JSC::Identifier::fromString(vm, "arrayBuffers"_s), - 0, - offset); - + structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "rss"_s), 0, offset); + structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "heapTotal"_s), 0, offset); + structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "heapUsed"_s), 0, offset); + structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "external"_s), 0, offset); + structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "arrayBuffers"_s), 0, offset); return structure; } @@ -2639,7 +2614,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionOpenStdin, (JSGlobalObject * globalObje auto callData = getCallData(resumeFunction); MarkedArgumentBuffer args; - JSC::call(globalObject, resumeFunction, callData, stdinValue, args); + JSC::profiledCall(globalObject, ProfilingReason::API, resumeFunction, callData, stdinValue, args); RETURN_IF_EXCEPTION(throwScope, {}); } @@ -2673,11 +2648,9 @@ static JSValue Process_stubEmptySet(VM& vm, JSObject* processObject) static JSValue constructMemoryUsage(VM& vm, JSObject* processObject) { auto* globalObject = processObject->globalObject(); - JSC::JSFunction* memoryUsage = JSC::JSFunction::create(vm, globalObject, 0, - String("memoryUsage"_s), Process_functionMemoryUsage, ImplementationVisibility::Public); + JSC::JSFunction* memoryUsage = JSC::JSFunction::create(vm, globalObject, 0, String("memoryUsage"_s), Process_functionMemoryUsage, ImplementationVisibility::Public); - JSC::JSFunction* rss = JSC::JSFunction::create(vm, globalObject, 0, - String("rss"_s), Process_functionMemoryUsageRSS, ImplementationVisibility::Public); + JSC::JSFunction* rss = JSC::JSFunction::create(vm, globalObject, 0, String("rss"_s), Process_functionMemoryUsageRSS, ImplementationVisibility::Public); memoryUsage->putDirect(vm, JSC::Identifier::fromString(vm, "rss"_s), rss, 0); return memoryUsage; @@ -2758,7 +2731,7 @@ JSValue Process::constructNextTickFn(JSC::VM& vm, Zig::GlobalObject* globalObjec args.append(JSC::JSFunction::create(vm, globalObject, 1, String(), jsFunctionDrainMicrotaskQueue, ImplementationVisibility::Private)); args.append(JSC::JSFunction::create(vm, globalObject, 1, String(), jsFunctionReportUncaughtException, ImplementationVisibility::Private)); - JSValue nextTickFunction = JSC::call(globalObject, initializer, JSC::getCallData(initializer), globalObject->globalThis(), args); + JSValue nextTickFunction = JSC::profiledCall(globalObject, ProfilingReason::API, initializer, JSC::getCallData(initializer), globalObject->globalThis(), args); if (nextTickFunction && nextTickFunction.isObject()) { this->m_nextTickFunction.set(vm, this, nextTickFunction.getObject()); } @@ -2981,7 +2954,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionKill, JSC::CallData callData = JSC::getCallData(_killFn); NakedPtr returnedException = nullptr; - auto result = JSC::call(globalObject, _killFn, callData, globalObject->globalThis(), args, returnedException); + auto result = JSC::profiledCall(globalObject, ProfilingReason::API, _killFn, callData, globalObject->globalThis(), args, returnedException); RETURN_IF_EXCEPTION(scope, {}); if (auto* exception = returnedException.get()) { diff --git a/src/bun.js/bindings/CallSite.cpp b/src/bun.js/bindings/CallSite.cpp index f1a5181265..6d2d15e09d 100644 --- a/src/bun.js/bindings/CallSite.cpp +++ b/src/bun.js/bindings/CallSite.cpp @@ -6,6 +6,7 @@ #include "config.h" #include "CallSite.h" +#include "JavaScriptCore/CallData.h" #include "helpers.h" #include @@ -89,8 +90,7 @@ JSC_DEFINE_HOST_FUNCTION(nativeFrameForTesting, (JSC::JSGlobalObject * globalObj auto scope = DECLARE_THROW_SCOPE(vm); JSC::JSFunction* function = jsCast(callFrame->argument(0)); - return JSValue::encode( - JSC::call(globalObject, function, JSC::ArgList(), "nativeFrameForTesting"_s)); + return JSValue::encode(JSC::call(globalObject, function, JSC::ArgList(), "nativeFrameForTesting"_s)); } JSValue createNativeFrameForTesting(Zig::GlobalObject* globalObject) diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index 6ab63c26cb..9573cfa46a 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -31,6 +31,7 @@ #include "headers.h" +#include "JavaScriptCore/CallData.h" #include "JavaScriptCore/Synchronousness.h" #include "JavaScriptCore/JSCast.h" #include @@ -199,7 +200,7 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj // // fn(exports, require, module, __filename, __dirname) { /* code */ }(exports, require, module, __filename, __dirname) // - JSC::call(globalObject, fn, callData, moduleObject, args, exception); + JSC::profiledCall(globalObject, ProfilingReason::API, fn, callData, moduleObject, args, exception); return exception.get() == nullptr; } diff --git a/src/bun.js/bindings/ConsoleObject.cpp b/src/bun.js/bindings/ConsoleObject.cpp index 1645511c7f..2d4653beef 100644 --- a/src/bun.js/bindings/ConsoleObject.cpp +++ b/src/bun.js/bindings/ConsoleObject.cpp @@ -55,11 +55,7 @@ void ConsoleObject::messageWithTypeAndLevel(MessageType type, MessageLevel level return; } - auto scope = DECLARE_CATCH_SCOPE(vm); - Bun__ConsoleObject__messageWithTypeAndLevel(this->m_client, static_cast(type), - static_cast(level), globalObject, jsArgs, - count); - scope.clearException(); + Bun__ConsoleObject__messageWithTypeAndLevel(this->m_client, static_cast(type), static_cast(level), globalObject, jsArgs, count); } void ConsoleObject::count(JSGlobalObject* globalObject, const String& label) { diff --git a/src/bun.js/bindings/ErrorCode.cpp b/src/bun.js/bindings/ErrorCode.cpp index cd2ad0ee1f..1fc96a4da2 100644 --- a/src/bun.js/bindings/ErrorCode.cpp +++ b/src/bun.js/bindings/ErrorCode.cpp @@ -175,6 +175,10 @@ JSObject* createError(Zig::JSGlobalObject* globalObject, ErrorCode code, JSC::JS return createError(vm, globalObject, code, message); } +// export fn Bun__inspect(globalThis: *JSGlobalObject, value: JSValue) ZigString +extern "C" ZigString Bun__inspect(JSC::JSGlobalObject* globalObject, JSValue value); + +// WTF::String JSValueToStringSafe(JSC::JSGlobalObject* globalObject, JSValue arg) { ASSERT(!arg.isEmpty()); @@ -187,7 +191,6 @@ WTF::String JSValueToStringSafe(JSC::JSGlobalObject* globalObject, JSValue arg) return arg.toWTFStringForConsole(globalObject); } case JSC::JSType::SymbolType: { - auto symbol = jsCast(cell); auto result = symbol->tryGetDescriptiveString(); if (result.has_value()) @@ -201,14 +204,14 @@ WTF::String JSValueToStringSafe(JSC::JSGlobalObject* globalObject, JSValue arg) auto name = JSC::getCalculatedDisplayName(vm, cell->getObject()); if (catchScope.exception()) { catchScope.clearException(); - name = "Function"_s; + name = ""_s; } if (!name.isNull() && name.length() > 0) { return makeString("[Function: "_s, name, ']'); } - return "Function"_s; + return "[Function: (anonymous)]"_s; break; } @@ -217,47 +220,142 @@ WTF::String JSValueToStringSafe(JSC::JSGlobalObject* globalObject, JSValue arg) } } - return arg.toWTFStringForConsole(globalObject); + ZigString zstring = Bun__inspect(globalObject, arg); + BunString bstring(BunStringTag::ZigString, BunStringImpl(zstring)); + return bstring.toWTFString(); +} + +WTF::String determineSpecificType(JSC::JSGlobalObject* globalObject, JSValue value) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + ASSERT(!value.isEmpty()); + + if (value.isNull()) { + return String("null"_s); + } + if (value.isUndefined()) { + return String("undefined"_s); + } + if (value.isNumber()) { + double d = value.asNumber(); + double infinity = std::numeric_limits::infinity(); + if (value == 0) return (1 / d == -infinity) ? String("type number (-0)"_s) : String("type number (0)"_s); + if (d != d) return String("type number (NaN)"_s); + if (d == infinity) return String("type number (Infinity)"_s); + if (d == -infinity) return String("type number (-Infinity)"_s); + auto str = value.toStringOrNull(globalObject); + if (!str) return {}; + return makeString("type number ("_s, str->getString(globalObject), ")"_s); + } + if (value.isBoolean()) { + return value.asBoolean() ? String("type boolean (true)"_s) : String("type boolean (false)"_s); + } + if (value.isBigInt()) { + auto str = value.toString(globalObject); + if (!str) return {}; + return makeString("type bigint ("_s, str->getString(globalObject), "n)"_s); + } + + ASSERT(value.isCell()); + auto cell = value.asCell(); + + if (cell->isSymbol()) { + auto symbol = jsCast(cell); + auto result = symbol->tryGetDescriptiveString(); + auto description = result.has_value() ? result.value() : String("Symbol()"_s); + return makeString("type symbol ("_s, description, ")"_s); + } + if (cell->isCallable()) { + auto name = JSC::getCalculatedDisplayName(vm, cell->getObject()); + if (scope.exception()) { + scope.clearException(); + name = String(""_s); + } + if (!name.isNull() && name.length() > 0) { + return makeString("function "_s, name); + } + return String("function"_s); + } + if (cell->isString()) { + auto str = value.toString(globalObject)->getString(globalObject); + if (str.length() > 28) { + str = str.substring(0, 25); + str = makeString(str, "..."_s); + if (!str.contains('\'')) { + return makeString("type string ('"_s, str, "')"_s); + } + } + // return `type string (${JSONStringify(value)})`; + str = value.toWTFStringForConsole(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + return makeString("type string ("_s, str, ")"_s); + } + if (cell->isObject()) { + auto constructor = value.get(globalObject, vm.propertyNames->constructor); + RETURN_IF_EXCEPTION(scope, {}); + if (constructor.toBoolean(globalObject)) { + auto name = constructor.get(globalObject, vm.propertyNames->name); + RETURN_IF_EXCEPTION(scope, {}); + auto str = name.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + return makeString("an instance of "_s, str->getString(globalObject)); + } + // return `${lazyInternalUtilInspect().inspect(value, { depth: -1 })}`; + auto str = JSValueToStringSafe(globalObject, value); + RETURN_IF_EXCEPTION(scope, {}); + return str; + } + + // value = lazyInternalUtilInspect().inspect(value, { colors: false }); + auto str = JSValueToStringSafe(globalObject, value); + RETURN_IF_EXCEPTION(scope, {}); + return str; } namespace Message { WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, const StringView& expected_type, JSValue actual_value) { - auto actual_value_string = JSValueToStringSafe(globalObject, actual_value); + auto actual_value_string = determineSpecificType(globalObject, actual_value); RETURN_IF_EXCEPTION(scope, {}); - return makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received: "_s, actual_value_string); + return makeString("The \""_s, arg_name, "\" argument must be of type "_s, expected_type, ". Received "_s, actual_value_string); } WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, ArgList expected_types, JSValue actual_value) { WTF::StringBuilder result; - auto actual_value_string = JSValueToStringSafe(globalObject, actual_value); + auto actual_value_string = determineSpecificType(globalObject, actual_value); RETURN_IF_EXCEPTION(scope, {}); - result.append("The \""_s, arg_name, "\" argument must be of type "_s); + result.append("The "_s); + + if (arg_name.contains(' ')) { + result.append(arg_name); + } else { + result.append("\""_s); + result.append(arg_name); + result.append("\" argument"_s); + } + result.append(" must be of type "_s); unsigned length = expected_types.size(); if (length == 1) { result.append(expected_types.at(0).toWTFString(globalObject)); - } else if (length == 2) { - result.append(expected_types.at(0).toWTFString(globalObject)); - result.append(" or "_s); - result.append(expected_types.at(1).toWTFString(globalObject)); } else { for (unsigned i = 0; i < length - 1; i++) { - if (i > 0) - result.append(", "_s); JSValue expected_type = expected_types.at(i); result.append(expected_type.toWTFString(globalObject)); + result.append(", "_s); } - result.append(" or "_s); + result.append("or "_s); result.append(expected_types.at(length - 1).toWTFString(globalObject)); } - result.append(". Received: "_s, actual_value_string); + result.append(". Received "_s, actual_value_string); return result.toString(); } @@ -295,7 +393,7 @@ WTF::String ERR_OUT_OF_RANGE(JSC::ThrowScope& scope, JSC::JSGlobalObject* global auto input = JSValueToStringSafe(globalObject, val_input); RETURN_IF_EXCEPTION(scope, {}); - return makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, range, ". Received: "_s, input); + return makeString("The value of \""_s, arg_name, "\" is out of range. It must be "_s, range, ". Received "_s, input); } } @@ -308,7 +406,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO auto ty_first_char = expected_type[0]; auto ty_kind = ty_first_char >= 'A' && ty_first_char <= 'Z' ? "an instance of"_s : "of type"_s; - auto actual_value = JSValueToStringSafe(globalObject, val_actual_value); + auto actual_value = determineSpecificType(globalObject, val_actual_value); RETURN_IF_EXCEPTION(throwScope, {}); auto message = makeString("The \""_s, arg_name, "\" "_s, arg_kind, " must be "_s, ty_kind, " "_s, expected_type, ". Received "_s, actual_value); @@ -324,7 +422,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO auto ty_first_char = expected_type[0]; auto ty_kind = ty_first_char >= 'A' && ty_first_char <= 'Z' ? "an instance of"_s : "of type"_s; - auto actual_value = JSValueToStringSafe(globalObject, val_actual_value); + auto actual_value = determineSpecificType(globalObject, val_actual_value); RETURN_IF_EXCEPTION(throwScope, {}); auto message = makeString("The \""_s, arg_name, "\" "_s, arg_kind, " must be "_s, ty_kind, " "_s, expected_type, ". Received "_s, actual_value); @@ -600,6 +698,30 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_BUFFER_OUT_OF_BOUNDS, (JSC::JSGlobalObje return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_BUFFER_OUT_OF_BOUNDS, "Attempt to access memory outside buffer bounds"_s)); } +JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_UNHANDLED_ERROR, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + JSC::VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto err = callFrame->argument(0); + + if (err.isUndefined()) { + return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_UNHANDLED_ERROR, "Unhandled error."_s)); + } + if (err.isString()) { + auto err_str = err.getString(globalObject); + return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_UNHANDLED_ERROR, makeString("Unhandled error. ("_s, err_str, ")"_s))); + } + if (err.isCell()) { + auto cell = err.asCell(); + if (cell->inherits()) { + return JSC::JSValue::encode(jsCast(cell)->value()); + } + } + auto err_str = err.toWTFString(globalObject); + return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_UNHANDLED_ERROR, makeString("Unhandled error. ("_s, err_str, ")"_s))); +} + } // namespace Bun JSC::JSValue WebCore::toJS(JSC::JSGlobalObject* globalObject, CommonAbortReason abortReason) diff --git a/src/bun.js/bindings/ErrorCode.h b/src/bun.js/bindings/ErrorCode.h index a3f4f8a67e..6a4387e51c 100644 --- a/src/bun.js/bindings/ErrorCode.h +++ b/src/bun.js/bindings/ErrorCode.h @@ -67,6 +67,7 @@ JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_BROTLI_INVALID_PARAM); JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_BUFFER_TOO_LARGE); JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_ZLIB_INITIALIZATION_FAILED); JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_BUFFER_OUT_OF_BOUNDS); +JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_UNHANDLED_ERROR); enum Bound { LOWER, diff --git a/src/bun.js/bindings/ErrorCode.ts b/src/bun.js/bindings/ErrorCode.ts index a4b5417054..ce57deaac5 100644 --- a/src/bun.js/bindings/ErrorCode.ts +++ b/src/bun.js/bindings/ErrorCode.ts @@ -51,6 +51,7 @@ export default [ ["ERR_INVALID_URI", URIError, "URIError"], ["ERR_SCRIPT_EXECUTION_TIMEOUT", Error, "Error"], ["ERR_SCRIPT_EXECUTION_INTERRUPTED", Error, "Error"], + ["ERR_UNHANDLED_ERROR", Error], // Bun-specific ["ERR_FORMDATA_PARSE_ERROR", TypeError], diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp index 61b64f0229..561ae2d213 100644 --- a/src/bun.js/bindings/ImportMetaObject.cpp +++ b/src/bun.js/bindings/ImportMetaObject.cpp @@ -23,6 +23,7 @@ #include "WebCoreJSClientData.h" #include #include +#include #include #include @@ -325,7 +326,7 @@ extern "C" JSC::EncodedJSValue functionImportMeta__resolveSyncPrivate(JSC::JSGlo auto bunStr = Bun::toString(parentIdStr); args.append(jsBoolean(Bun__isBunMain(lexicalGlobalObject, &bunStr))); - return JSValue::encode(JSC::call(lexicalGlobalObject, overrideHandler, JSC::getCallData(overrideHandler), parentModuleObject, args)); + return JSValue::encode(JSC::profiledCall(lexicalGlobalObject, ProfilingReason::API, overrideHandler, JSC::getCallData(overrideHandler), parentModuleObject, args)); } } } diff --git a/src/bun.js/bindings/JSBundlerPlugin.cpp b/src/bun.js/bindings/JSBundlerPlugin.cpp index fea22a07a4..559023efb6 100644 --- a/src/bun.js/bindings/JSBundlerPlugin.cpp +++ b/src/bun.js/bindings/JSBundlerPlugin.cpp @@ -2,6 +2,7 @@ #include "BunProcess.h" #include "../../../packages/bun-native-bundler-plugin-api/bundler_plugin.h" +#include "JavaScriptCore/CallData.h" #include "headers-handwritten.h" #include #include @@ -618,7 +619,7 @@ extern "C" JSC::EncodedJSValue JSBundlerPlugin__runSetupFunction( arguments.append(JSValue::decode(encodedIsBake)); auto* lexicalGlobalObject = jsCast(JSValue::decode(encodedSetupFunction))->globalObject(); - return JSC::JSValue::encode(JSC::call(lexicalGlobalObject, setupFunction, callData, plugin, arguments)); + return JSC::JSValue::encode(JSC::profiledCall(lexicalGlobalObject, ProfilingReason::API, setupFunction, callData, plugin, arguments)); } extern "C" void JSBundlerPlugin__setConfig(Bun::JSBundlerPlugin* plugin, void* config) diff --git a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp index daac639878..53463a0561 100644 --- a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp +++ b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp @@ -380,7 +380,7 @@ JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject) auto clientData = WebCore::clientData(vm); JSC::CallData callData = JSC::getCallData(getSourceEvent); NakedPtr returnedException = nullptr; - auto result = JSC::call(globalObject, getSourceEvent, callData, globalObject->globalThis(), args, returnedException); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, getSourceEvent, callData, globalObject->globalThis(), args, returnedException); RETURN_IF_EXCEPTION(scope, {}); if (returnedException) { diff --git a/src/bun.js/bindings/JSFFIFunction.cpp b/src/bun.js/bindings/JSFFIFunction.cpp index b58d4ed144..e3a1fc3239 100644 --- a/src/bun.js/bindings/JSFFIFunction.cpp +++ b/src/bun.js/bindings/JSFFIFunction.cpp @@ -30,6 +30,7 @@ #include #include "ZigGlobalObject.h" +#include #include #include "DOMJITIDLConvert.h" #include "DOMJITIDLType.h" @@ -202,7 +203,7 @@ FFI_Callback_call(FFICallbackFunctionWrapper& wrapper, size_t argCount, JSC::Enc for (size_t i = 0; i < argCount; ++i) arguments.appendWithCrashOnOverflow(JSC::JSValue::decode(args[i])); WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -229,7 +230,7 @@ FFI_Callback_threadsafe_call(FFICallbackFunctionWrapper& wrapper, size_t argCoun for (size_t i = 0; i < argsVec.size(); ++i) arguments.appendWithCrashOnOverflow(JSC::JSValue::decode(argsVec[i])); WTF::NakedPtr exception; - JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -248,7 +249,7 @@ FFI_Callback_call_0(FFICallbackFunctionWrapper& wrapper, size_t argCount, JSC::E JSC::MarkedArgumentBuffer arguments; WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -269,7 +270,7 @@ FFI_Callback_call_1(FFICallbackFunctionWrapper& wrapper, size_t argCount, JSC::E arguments.append(JSC::JSValue::decode(args[0])); WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -291,7 +292,7 @@ FFI_Callback_call_2(FFICallbackFunctionWrapper& wrapper, size_t argCount, JSC::E arguments.append(JSC::JSValue::decode(args[1])); WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -313,7 +314,7 @@ extern "C" JSC::EncodedJSValue FFI_Callback_call_3(FFICallbackFunctionWrapper& w arguments.append(JSC::JSValue::decode(args[2])); WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -336,7 +337,7 @@ extern "C" JSC::EncodedJSValue FFI_Callback_call_4(FFICallbackFunctionWrapper& w arguments.append(JSC::JSValue::decode(args[3])); WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -360,7 +361,7 @@ extern "C" JSC::EncodedJSValue FFI_Callback_call_5(FFICallbackFunctionWrapper& w arguments.append(JSC::JSValue::decode(args[4])); WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -386,7 +387,7 @@ FFI_Callback_call_6(FFICallbackFunctionWrapper& wrapper, size_t argCount, JSC::E arguments.append(JSC::JSValue::decode(args[5])); WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); @@ -413,7 +414,7 @@ FFI_Callback_call_7(FFICallbackFunctionWrapper& wrapper, size_t argCount, JSC::E arguments.append(JSC::JSValue::decode(args[6])); WTF::NakedPtr exception; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); + auto result = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, function, JSC::getCallData(function), JSC::jsUndefined(), arguments, exception); if (UNLIKELY(exception)) { auto scope = DECLARE_THROW_SCOPE(vm); scope.throwException(globalObject, exception); diff --git a/src/bun.js/bindings/UtilInspect.cpp b/src/bun.js/bindings/UtilInspect.cpp index 9df5b95ead..5e72a31557 100644 --- a/src/bun.js/bindings/UtilInspect.cpp +++ b/src/bun.js/bindings/UtilInspect.cpp @@ -37,7 +37,6 @@ JSObject* createInspectOptionsObject(VM& vm, Zig::GlobalObject* globalObject, un extern "C" JSC::EncodedJSValue JSC__JSValue__callCustomInspectFunction( Zig::GlobalObject* globalObject, - JSC::JSGlobalObject* lexicalGlobalObject, JSC__JSValue encodedFunctionValue, JSC__JSValue encodedThisValue, unsigned depth, @@ -59,11 +58,10 @@ extern "C" JSC::EncodedJSValue JSC__JSValue__callCustomInspectFunction( arguments.append(options); arguments.append(inspectFn); - auto inspectRet = JSC::call(lexicalGlobalObject, functionToCall, callData, thisValue, arguments); + auto inspectRet = JSC::profiledCall(globalObject, ProfilingReason::API, functionToCall, callData, thisValue, arguments); if (auto exe = scope.exception()) { *is_exception = true; - scope.clearException(); - return JSValue::encode(exe); + return {}; } RELEASE_AND_RETURN(scope, JSValue::encode(inspectRet)); } diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index a8a8ea91ce..fe179e0de3 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1885,7 +1885,7 @@ JSC_DEFINE_HOST_FUNCTION(functionCallback, (JSC::JSGlobalObject * globalObject, { JSFunction* callback = jsCast(callFrame->uncheckedArgument(0)); JSC::CallData callData = JSC::getCallData(callback); - return JSC::JSValue::encode(JSC::call(globalObject, callback, callData, JSC::jsUndefined(), JSC::MarkedArgumentBuffer())); + return JSC::JSValue::encode(JSC::profiledCall(globalObject, ProfilingReason::API, callback, callData, JSC::jsUndefined(), JSC::MarkedArgumentBuffer())); } JSC_DEFINE_CUSTOM_GETTER(noop_getter, (JSGlobalObject*, EncodedJSValue, PropertyName)) @@ -2563,7 +2563,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotask, (JSGlobalObject * globalObj break; } - JSC::call(globalObject, job, callData, jsUndefined(), arguments, exceptionPtr); + JSC::profiledCall(globalObject, ProfilingReason::API, job, callData, jsUndefined(), arguments, exceptionPtr); if (asyncContextData) { asyncContextData->putInternalField(vm, 0, restoreAsyncContext); @@ -2615,7 +2615,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotaskVariadic, (JSGlobalObject * g asyncContextData->putInternalField(vm, 0, setAsyncContext); } - JSC::call(globalObject, job, callData, thisValue, arguments, exceptionPtr); + JSC::profiledCall(globalObject, ProfilingReason::API, job, callData, thisValue, arguments, exceptionPtr); if (asyncContextData) { asyncContextData->putInternalField(vm, 0, restoreAsyncContext); @@ -2852,7 +2852,7 @@ void GlobalObject::finishCreation(VM& vm) auto* function = JSFunction::create(vm, globalObject, static_cast(importMetaObjectCreateRequireCacheCodeGenerator(vm)), globalObject); NakedPtr returnedException = nullptr; - auto result = JSC::call(globalObject, function, JSC::getCallData(function), globalObject, ArgList(), returnedException); + auto result = JSC::profiledCall(globalObject, ProfilingReason::API, function, JSC::getCallData(function), globalObject, ArgList(), returnedException); init.set(result.toObject(globalObject)); }); @@ -2978,7 +2978,7 @@ void GlobalObject::finishCreation(VM& vm) JSC::CallData callData = JSC::getCallData(getStylize); NakedPtr returnedException = nullptr; - auto result = JSC::call(init.owner, getStylize, callData, jsNull(), args, returnedException); + auto result = JSC::profiledCall(init.owner, ProfilingReason::API, getStylize, callData, jsNull(), args, returnedException); // RETURN_IF_EXCEPTION(scope, {}); if (returnedException) { @@ -3431,7 +3431,7 @@ JSC_DEFINE_CUSTOM_GETTER(getConsoleConstructor, (JSGlobalObject * globalObject, args.append(console); JSC::CallData callData = JSC::getCallData(createConsoleConstructor); NakedPtr returnedException = nullptr; - auto result = JSC::call(globalObject, createConsoleConstructor, callData, console, args, returnedException); + auto result = JSC::profiledCall(globalObject, ProfilingReason::API, createConsoleConstructor, callData, console, args, returnedException); if (returnedException) { auto scope = DECLARE_THROW_SCOPE(vm); throwException(globalObject, scope, returnedException.get()); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 94a0698a29..ef989ab0d1 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -4482,33 +4482,6 @@ pub const JSValue = enum(i64) { try buffered_writer.flush(); } - pub fn jestPrettyFormat(this: JSValue, out: *MutableString, globalObject: *JSGlobalObject) !void { - var buffered_writer = MutableString.BufferedWriter{ .context = out }; - const writer = buffered_writer.writer(); - const Writer = @TypeOf(writer); - - const fmt_options = JSC.ConsoleObject.FormatOptions{ - .enable_colors = false, - .add_newline = false, - .flush = false, - .ordered_properties = true, - .quote_strings = true, - }; - - JSC.ConsoleObject.format2( - .Debug, - globalObject, - @as([*]const JSValue, @ptrCast(&this)), - 1, - Writer, - Writer, - writer, - fmt_options, - ); - - try buffered_writer.flush(); - } - extern fn JSBuffer__bufferFromLength(*JSGlobalObject, i64) JSValue; /// Must come from globally-allocated memory if allocator is not null @@ -6803,10 +6776,7 @@ pub const JSHostZigFunction = fn (*JSGlobalObject, *CallFrame) bun.JSError!JSVal pub fn toJSHostFunction(comptime Function: JSHostZigFunction) JSC.JSHostFunctionType { return struct { - pub fn function( - globalThis: *JSC.JSGlobalObject, - callframe: *JSC.CallFrame, - ) callconv(JSC.conv) JSC.JSValue { + pub fn function(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) JSC.JSValue { if (bun.Environment.allow_assert and bun.Environment.is_canary) { const value = Function(globalThis, callframe) catch |err| switch (err) { error.JSError => .zero, @@ -6815,14 +6785,17 @@ pub fn toJSHostFunction(comptime Function: JSHostZigFunction) JSC.JSHostFunction if (comptime bun.Environment.isDebug) { if (value != .zero) { if (globalThis.hasException()) { + var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis }; bun.Output.prettyErrorln( \\Assertion failed: Native function returned a non-zero JSValue while an exception is pending \\ - \\Did you forget to check if an exception is pending? + \\ fn: {s} + \\ value: {} \\ - \\ if (globalThis.hasException()) return .zero; - \\ - , .{}); + , .{ + &Function, // use `(lldb) image lookup --address 0x1ec4` to discover what function failed + value.toFmt(&formatter), + }); Output.flush(); } } diff --git a/src/bun.js/bindings/webcore/JSDOMIterator.h b/src/bun.js/bindings/webcore/JSDOMIterator.h index 4f60337af0..cb3becd313 100644 --- a/src/bun.js/bindings/webcore/JSDOMIterator.h +++ b/src/bun.js/bindings/webcore/JSDOMIterator.h @@ -31,6 +31,7 @@ #include #include #include "ErrorCode.h" +#include "JavaScriptCore/CallData.h" #include "JavaScriptCore/Interpreter.h" namespace WebCore { @@ -228,7 +229,7 @@ template JSC::JSValue iteratorForEach(JSC::JSGlobalObject& throwOutOfMemoryError(&lexicalGlobalObject, scope); return {}; } - JSC::call(&lexicalGlobalObject, callback, callData, thisValue, arguments); + JSC::profiledCall(&lexicalGlobalObject, ProfilingReason::API, callback, callData, thisValue, arguments); if (UNLIKELY(scope.exception())) break; } diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index b5a2aa7048..6c5274dd0a 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -4025,7 +4025,7 @@ pub const VirtualMachine = struct { value, this.global, allow_ansi_color, - ); + ) catch {}; if (allow_side_effects) { // When we're printing errors for a top-level uncaught eception / rejection, suppress further errors here. @@ -4051,7 +4051,7 @@ pub const VirtualMachine = struct { .{ .disable_inspect_custom = true, .hide_global = true }, ); if (tag.tag != .NativeCode) { - formatter.format( + try formatter.format( tag, Writer, writer, diff --git a/src/bun.js/modules/BunJSCModule.h b/src/bun.js/modules/BunJSCModule.h index 55926dde59..557cdc2f6f 100644 --- a/src/bun.js/modules/BunJSCModule.h +++ b/src/bun.js/modules/BunJSCModule.h @@ -1,6 +1,7 @@ #include "_NativeModule.h" #include "ExceptionOr.h" +#include "JavaScriptCore/CallData.h" #include "JavaScriptCore/ArgList.h" #include "JavaScriptCore/ExceptionScope.h" #include "JavaScriptCore/JSCJSValue.h" @@ -693,7 +694,7 @@ JSC_DEFINE_HOST_FUNCTION(functionRunProfiler, (JSGlobalObject * globalObject, Ca samplingProfiler.noticeCurrentThreadAsJSCExecutionThread(); samplingProfiler.start(); - JSValue returnValue = JSC::call(globalObject, function, callData, JSC::jsUndefined(), args); + JSValue returnValue = JSC::profiledCall(globalObject, ProfilingReason::API, function, callData, JSC::jsUndefined(), args); if (returnValue.isEmpty() || throwScope.exception()) { return JSValue::encode(reportFailure(vm)); @@ -976,7 +977,7 @@ DEFINE_NATIVE_MODULE(BunJSC) putNativeFn(Identifier::fromString(vm, "serialize"_s), functionSerialize); putNativeFn(Identifier::fromString(vm, "deserialize"_s), functionDeserialize); putNativeFn(Identifier::fromString(vm, "estimateShallowMemoryUsageOf"_s), functionEstimateDirectMemoryUsageOf); - + // Deprecated putNativeFn(Identifier::fromString(vm, "describe"_s), functionDescribe); putNativeFn(Identifier::fromString(vm, "describeArray"_s), functionDescribeArray); diff --git a/src/bun.js/modules/NodeUtilTypesModule.h b/src/bun.js/modules/NodeUtilTypesModule.h index cc4117701e..219665c958 100644 --- a/src/bun.js/modules/NodeUtilTypesModule.h +++ b/src/bun.js/modules/NodeUtilTypesModule.h @@ -1,6 +1,8 @@ #pragma once #include "BunClientData.h" +#include "JSDOMWrapper.h" +#include "JSEventTarget.h" #include "JavaScriptCore/CatchScope.h" #include "_NativeModule.h" @@ -452,89 +454,67 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionIsCryptoKey, GET_FIRST_CELL return JSValue::encode(jsBoolean(cell->inherits())); } +JSC_DEFINE_HOST_FUNCTION(jsFunctionIsEventTarget, + (JSC::JSGlobalObject * globalObject, + JSC::CallFrame* callframe)) +{ + GET_FIRST_CELL + return JSValue::encode(jsBoolean(cell->inherits())); +} namespace Zig { + +// Hardcoded module "node:util/types" DEFINE_NATIVE_MODULE(NodeUtilTypes) { - INIT_NATIVE_MODULE(43); + INIT_NATIVE_MODULE(44); putNativeFn(Identifier::fromString(vm, "isExternal"_s), jsFunctionIsExternal); putNativeFn(Identifier::fromString(vm, "isDate"_s), jsFunctionIsDate); - putNativeFn(Identifier::fromString(vm, "isArgumentsObject"_s), - jsFunctionIsArgumentsObject); - putNativeFn(Identifier::fromString(vm, "isBigIntObject"_s), - jsFunctionIsBigIntObject); - putNativeFn(Identifier::fromString(vm, "isBooleanObject"_s), - jsFunctionIsBooleanObject); - putNativeFn(Identifier::fromString(vm, "isNumberObject"_s), - jsFunctionIsNumberObject); - putNativeFn(Identifier::fromString(vm, "isStringObject"_s), - jsFunctionIsStringObject); - putNativeFn(Identifier::fromString(vm, "isSymbolObject"_s), - jsFunctionIsSymbolObject); - putNativeFn(Identifier::fromString(vm, "isNativeError"_s), - jsFunctionIsNativeError); + putNativeFn(Identifier::fromString(vm, "isArgumentsObject"_s), jsFunctionIsArgumentsObject); + putNativeFn(Identifier::fromString(vm, "isBigIntObject"_s), jsFunctionIsBigIntObject); + putNativeFn(Identifier::fromString(vm, "isBooleanObject"_s), jsFunctionIsBooleanObject); + putNativeFn(Identifier::fromString(vm, "isNumberObject"_s), jsFunctionIsNumberObject); + putNativeFn(Identifier::fromString(vm, "isStringObject"_s), jsFunctionIsStringObject); + putNativeFn(Identifier::fromString(vm, "isSymbolObject"_s), jsFunctionIsSymbolObject); + putNativeFn(Identifier::fromString(vm, "isNativeError"_s), jsFunctionIsNativeError); putNativeFn(Identifier::fromString(vm, "isRegExp"_s), jsFunctionIsRegExp); - putNativeFn(Identifier::fromString(vm, "isAsyncFunction"_s), - jsFunctionIsAsyncFunction); - putNativeFn(Identifier::fromString(vm, "isGeneratorFunction"_s), - jsFunctionIsGeneratorFunction); - putNativeFn(Identifier::fromString(vm, "isGeneratorObject"_s), - jsFunctionIsGeneratorObject); + putNativeFn(Identifier::fromString(vm, "isAsyncFunction"_s), jsFunctionIsAsyncFunction); + putNativeFn(Identifier::fromString(vm, "isGeneratorFunction"_s), jsFunctionIsGeneratorFunction); + putNativeFn(Identifier::fromString(vm, "isGeneratorObject"_s), jsFunctionIsGeneratorObject); putNativeFn(Identifier::fromString(vm, "isPromise"_s), jsFunctionIsPromise); putNativeFn(Identifier::fromString(vm, "isMap"_s), jsFunctionIsMap); putNativeFn(Identifier::fromString(vm, "isSet"_s), jsFunctionIsSet); - putNativeFn(Identifier::fromString(vm, "isMapIterator"_s), - jsFunctionIsMapIterator); - putNativeFn(Identifier::fromString(vm, "isSetIterator"_s), - jsFunctionIsSetIterator); + putNativeFn(Identifier::fromString(vm, "isMapIterator"_s), jsFunctionIsMapIterator); + putNativeFn(Identifier::fromString(vm, "isSetIterator"_s), jsFunctionIsSetIterator); putNativeFn(Identifier::fromString(vm, "isWeakMap"_s), jsFunctionIsWeakMap); putNativeFn(Identifier::fromString(vm, "isWeakSet"_s), jsFunctionIsWeakSet); - putNativeFn(Identifier::fromString(vm, "isArrayBuffer"_s), - jsFunctionIsArrayBuffer); + putNativeFn(Identifier::fromString(vm, "isArrayBuffer"_s), jsFunctionIsArrayBuffer); putNativeFn(Identifier::fromString(vm, "isDataView"_s), jsFunctionIsDataView); - putNativeFn(Identifier::fromString(vm, "isSharedArrayBuffer"_s), - jsFunctionIsSharedArrayBuffer); + putNativeFn(Identifier::fromString(vm, "isSharedArrayBuffer"_s), jsFunctionIsSharedArrayBuffer); putNativeFn(Identifier::fromString(vm, "isProxy"_s), jsFunctionIsProxy); - putNativeFn(Identifier::fromString(vm, "isModuleNamespaceObject"_s), - jsFunctionIsModuleNamespaceObject); - putNativeFn(Identifier::fromString(vm, "isAnyArrayBuffer"_s), - jsFunctionIsAnyArrayBuffer); - putNativeFn(Identifier::fromString(vm, "isBoxedPrimitive"_s), - jsFunctionIsBoxedPrimitive); - putNativeFn(Identifier::fromString(vm, "isArrayBufferView"_s), - jsFunctionIsArrayBufferView); - putNativeFn(Identifier::fromString(vm, "isTypedArray"_s), - jsFunctionIsTypedArray); - putNativeFn(Identifier::fromString(vm, "isUint8Array"_s), - jsFunctionIsUint8Array); - putNativeFn(Identifier::fromString(vm, "isUint8ClampedArray"_s), - jsFunctionIsUint8ClampedArray); - putNativeFn(Identifier::fromString(vm, "isUint16Array"_s), - jsFunctionIsUint16Array); - putNativeFn(Identifier::fromString(vm, "isUint32Array"_s), - jsFunctionIsUint32Array); - putNativeFn(Identifier::fromString(vm, "isInt8Array"_s), - jsFunctionIsInt8Array); - putNativeFn(Identifier::fromString(vm, "isInt16Array"_s), - jsFunctionIsInt16Array); - putNativeFn(Identifier::fromString(vm, "isInt32Array"_s), - jsFunctionIsInt32Array); - putNativeFn(Identifier::fromString(vm, "isFloat16Array"_s), - jsFunctionIsFloat16Array); - putNativeFn(Identifier::fromString(vm, "isFloat32Array"_s), - jsFunctionIsFloat32Array); - putNativeFn(Identifier::fromString(vm, "isFloat64Array"_s), - jsFunctionIsFloat64Array); - putNativeFn(Identifier::fromString(vm, "isBigInt64Array"_s), - jsFunctionIsBigInt64Array); - putNativeFn(Identifier::fromString(vm, "isBigUint64Array"_s), - jsFunctionIsBigUint64Array); - putNativeFn(Identifier::fromString(vm, "isKeyObject"_s), - jsFunctionIsKeyObject); - putNativeFn(Identifier::fromString(vm, "isCryptoKey"_s), - jsFunctionIsCryptoKey); + putNativeFn(Identifier::fromString(vm, "isModuleNamespaceObject"_s), jsFunctionIsModuleNamespaceObject); + putNativeFn(Identifier::fromString(vm, "isAnyArrayBuffer"_s), jsFunctionIsAnyArrayBuffer); + putNativeFn(Identifier::fromString(vm, "isBoxedPrimitive"_s), jsFunctionIsBoxedPrimitive); + putNativeFn(Identifier::fromString(vm, "isArrayBufferView"_s), jsFunctionIsArrayBufferView); + putNativeFn(Identifier::fromString(vm, "isTypedArray"_s), jsFunctionIsTypedArray); + putNativeFn(Identifier::fromString(vm, "isUint8Array"_s), jsFunctionIsUint8Array); + putNativeFn(Identifier::fromString(vm, "isUint8ClampedArray"_s), jsFunctionIsUint8ClampedArray); + putNativeFn(Identifier::fromString(vm, "isUint16Array"_s), jsFunctionIsUint16Array); + putNativeFn(Identifier::fromString(vm, "isUint32Array"_s), jsFunctionIsUint32Array); + putNativeFn(Identifier::fromString(vm, "isInt8Array"_s), jsFunctionIsInt8Array); + putNativeFn(Identifier::fromString(vm, "isInt16Array"_s), jsFunctionIsInt16Array); + putNativeFn(Identifier::fromString(vm, "isInt32Array"_s), jsFunctionIsInt32Array); + putNativeFn(Identifier::fromString(vm, "isFloat16Array"_s), jsFunctionIsFloat16Array); + putNativeFn(Identifier::fromString(vm, "isFloat32Array"_s), jsFunctionIsFloat32Array); + putNativeFn(Identifier::fromString(vm, "isFloat64Array"_s), jsFunctionIsFloat64Array); + putNativeFn(Identifier::fromString(vm, "isBigInt64Array"_s), jsFunctionIsBigInt64Array); + putNativeFn(Identifier::fromString(vm, "isBigUint64Array"_s), jsFunctionIsBigUint64Array); + putNativeFn(Identifier::fromString(vm, "isKeyObject"_s), jsFunctionIsKeyObject); + putNativeFn(Identifier::fromString(vm, "isCryptoKey"_s), jsFunctionIsCryptoKey); + putNativeFn(Identifier::fromString(vm, "isEventTarget"_s), jsFunctionIsEventTarget); RETURN_NATIVE_MODULE(); } + } // namespace Zig diff --git a/src/bun.js/test/diff_format.zig b/src/bun.js/test/diff_format.zig index fc04a74e33..e198e474cd 100644 --- a/src/bun.js/test/diff_format.zig +++ b/src/bun.js/test/diff_format.zig @@ -111,7 +111,7 @@ pub const DiffFormatter = struct { Writer, buf_writer, fmt_options, - ); + ) catch {}; // TODO: buffered_writer.flush() catch unreachable; buffered_writer_.context = &expected_buf; @@ -125,7 +125,7 @@ pub const DiffFormatter = struct { Writer, buf_writer, fmt_options, - ); + ) catch {}; // TODO: buffered_writer.flush() catch unreachable; } diff --git a/src/bun.js/test/pretty_format.zig b/src/bun.js/test/pretty_format.zig index 7cfeb3e212..2934577d49 100644 --- a/src/bun.js/test/pretty_format.zig +++ b/src/bun.js/test/pretty_format.zig @@ -574,10 +574,10 @@ pub const JestPrettyFormat = struct { const next_value = this.remaining_values[0]; this.remaining_values = this.remaining_values[1..]; switch (token) { - Tag.String => this.printAs(Tag.String, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors), - Tag.Double => this.printAs(Tag.Double, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors), - Tag.Object => this.printAs(Tag.Object, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors), - Tag.Integer => this.printAs(Tag.Integer, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors), + Tag.String => this.printAs(Tag.String, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors) catch {}, // TODO: + Tag.Double => this.printAs(Tag.Double, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors) catch {}, // TODO: + Tag.Object => this.printAs(Tag.Object, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors) catch {}, // TODO: + Tag.Integer => this.printAs(Tag.Integer, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors) catch {}, // TODO: // undefined is overloaded to mean the '%o" field Tag.Undefined => this.format(Tag.get(next_value, globalThis), Writer, writer_, next_value, globalThis, enable_ansi_colors), @@ -899,7 +899,7 @@ pub const JestPrettyFormat = struct { value: JSValue, jsType: JSValue.JSType, comptime enable_ansi_colors: bool, - ) void { + ) error{}!void { if (this.failed) return; var writer = WrappedWriter(Writer){ .ctx = writer_, .estimated_line_length = &this.estimated_line_length }; @@ -1060,7 +1060,7 @@ pub const JestPrettyFormat = struct { }, .Double => { if (value.isCell()) { - this.printAs(.Object, Writer, writer_, value, .Object, enable_ansi_colors); + try this.printAs(.Object, Writer, writer_, value, .Object, enable_ansi_colors); return; } @@ -1240,12 +1240,11 @@ pub const JestPrettyFormat = struct { this.addForNewLine("FormData (entries) ".len); writer.writeAll(comptime Output.prettyFmt("FormData (entries) ", enable_ansi_colors)); - return this.printAs( + return try this.printAs( .Object, Writer, writer_, - toJSONFunction.call(this.globalThis, value, &.{}) catch |err| - this.globalThis.takeException(err), + toJSONFunction.call(this.globalThis, value, &.{}) catch |err| this.globalThis.takeException(err), .Object, enable_ansi_colors, ); @@ -1273,12 +1272,12 @@ pub const JestPrettyFormat = struct { return; } else if (jsType != .DOMWrapper) { if (value.isCallable(this.globalThis.vm())) { - return this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors); + return try this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors); } - return this.printAs(.Object, Writer, writer_, value, jsType, enable_ansi_colors); + return try this.printAs(.Object, Writer, writer_, value, jsType, enable_ansi_colors); } - return this.printAs(.Object, Writer, writer_, value, .Event, enable_ansi_colors); + return try this.printAs(.Object, Writer, writer_, value, .Event, enable_ansi_colors); }, .NativeCode => { this.addForNewLine("[native code]".len); @@ -1293,7 +1292,7 @@ pub const JestPrettyFormat = struct { }, .Boolean => { if (value.isCell()) { - this.printAs(.Object, Writer, writer_, value, .Object, enable_ansi_colors); + try this.printAs(.Object, Writer, writer_, value, .Object, enable_ansi_colors); return; } if (value.toBoolean()) { @@ -1401,7 +1400,7 @@ pub const JestPrettyFormat = struct { const event_type = switch (EventType.map.fromJS(this.globalThis, event_type_value) orelse .unknown) { .MessageEvent, .ErrorEvent => |evt| evt, else => { - return this.printAs(.Object, Writer, writer_, value, .Event, enable_ansi_colors); + return try this.printAs(.Object, Writer, writer_, value, .Event, enable_ansi_colors); }, }; @@ -1962,7 +1961,7 @@ pub const JestPrettyFormat = struct { // comptime var so we have to repeat it here. The rationale there is // it _should_ limit the stack usage because each version of the // function will be relatively small - return switch (result.tag) { + return try switch (result.tag) { .StringPossiblyFormatted => this.printAs(.StringPossiblyFormatted, Writer, writer, value, result.cell, enable_ansi_colors), .String => this.printAs(.String, Writer, writer, value, result.cell, enable_ansi_colors), .Undefined => this.printAs(.Undefined, Writer, writer, value, result.cell, enable_ansi_colors), @@ -2076,7 +2075,7 @@ pub const JestPrettyFormat = struct { this.addForNewLine("ObjectContaining ".len); writer.writeAll("ObjectContaining "); } - this.printAs(.Object, @TypeOf(writer_), writer_, object_value, .Object, enable_ansi_colors); + this.printAs(.Object, @TypeOf(writer_), writer_, object_value, .Object, enable_ansi_colors) catch {}; // TODO: } else if (value.as(expect.ExpectStringContaining)) |matcher| { const substring_value = expect.ExpectStringContaining.stringValueGetCached(value) orelse return true; @@ -2088,7 +2087,7 @@ pub const JestPrettyFormat = struct { this.addForNewLine("StringContaining ".len); writer.writeAll("StringContaining "); } - this.printAs(.String, @TypeOf(writer_), writer_, substring_value, .String, enable_ansi_colors); + this.printAs(.String, @TypeOf(writer_), writer_, substring_value, .String, enable_ansi_colors) catch {}; // TODO: } else if (value.as(expect.ExpectStringMatching)) |matcher| { const test_value = expect.ExpectStringMatching.testValueGetCached(value) orelse return true; @@ -2103,7 +2102,7 @@ pub const JestPrettyFormat = struct { const original_quote_strings = this.quote_strings; if (test_value.isRegExp()) this.quote_strings = false; - this.printAs(.String, @TypeOf(writer_), writer_, test_value, .String, enable_ansi_colors); + this.printAs(.String, @TypeOf(writer_), writer_, test_value, .String, enable_ansi_colors) catch {}; // TODO: this.quote_strings = original_quote_strings; } else if (value.as(expect.ExpectCustomAsymmetricMatcher)) |instance| { const printed = instance.customPrint(value, this.globalThis, writer_, true) catch unreachable; @@ -2121,7 +2120,7 @@ pub const JestPrettyFormat = struct { this.addForNewLine(matcher_name.length() + 1); writer.print("{s}", .{matcher_name}); writer.writeAll(" "); - this.printAs(.Array, @TypeOf(writer_), writer_, args_value, .Array, enable_ansi_colors); + this.printAs(.Array, @TypeOf(writer_), writer_, args_value, .Array, enable_ansi_colors) catch {}; // TODO: } } else { return false; diff --git a/src/bun.js/web_worker.zig b/src/bun.js/web_worker.zig index 506d818dc3..c8ae517d90 100644 --- a/src/bun.js/web_worker.zig +++ b/src/bun.js/web_worker.zig @@ -337,7 +337,7 @@ pub const WebWorker = struct { // Prevent recursion vm.onUnhandledRejection = &JSC.VirtualMachine.onQuietUnhandledRejectionHandlerCaptureValue; - const error_instance = error_instance_or_exception.toError() orelse error_instance_or_exception; + var error_instance = error_instance_or_exception.toError() orelse error_instance_or_exception; var array = bun.MutableString.init(bun.default_allocator, 0) catch unreachable; defer array.deinit(); @@ -364,7 +364,13 @@ pub const WebWorker = struct { .flush = false, .max_depth = 32, }, - ); + ) catch |err| { + switch (err) { + error.JSError => {}, + error.OutOfMemory => globalObject.throwOutOfMemory() catch {}, + } + error_instance = globalObject.tryTakeException().?; + }; buffered_writer.flush() catch { bun.outOfMemory(); }; diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig index 2290def2c9..7b1534091d 100644 --- a/src/bun.js/webcore/body.zig +++ b/src/bun.js/webcore/body.zig @@ -72,7 +72,7 @@ pub const Body = struct { try formatter.writeIndent(Writer, writer); try writer.writeAll(comptime Output.prettyFmt("bodyUsed: ", enable_ansi_colors)); - formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.value == .Used), .BooleanObject, enable_ansi_colors); + try formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.value == .Used), .BooleanObject, enable_ansi_colors); if (this.value == .Blob) { try formatter.printComma(Writer, writer, enable_ansi_colors); @@ -89,7 +89,7 @@ pub const Body = struct { try formatter.printComma(Writer, writer, enable_ansi_colors); try writer.writeAll("\n"); try formatter.writeIndent(Writer, writer); - formatter.printAs(.Object, Writer, writer, stream.value, stream.value.jsType(), enable_ansi_colors); + try formatter.printAs(.Object, Writer, writer, stream.value, stream.value.jsType(), enable_ansi_colors); } } } diff --git a/src/bun.js/webcore/request.zig b/src/bun.js/webcore/request.zig index 45a9f3fec3..7274373be0 100644 --- a/src/bun.js/webcore/request.zig +++ b/src/bun.js/webcore/request.zig @@ -227,7 +227,7 @@ pub const Request = struct { try formatter.writeIndent(Writer, writer); try writer.writeAll(comptime Output.prettyFmt("headers: ", enable_ansi_colors)); - formatter.printAs(.Private, Writer, writer, this.getHeaders(formatter.globalThis), .DOMWrapper, enable_ansi_colors); + try formatter.printAs(.Private, Writer, writer, this.getHeaders(formatter.globalThis), .DOMWrapper, enable_ansi_colors); if (this.body.value == .Blob) { try writer.writeAll("\n"); @@ -247,7 +247,7 @@ pub const Request = struct { if (this.body.value.Locked.readable.get()) |stream| { try writer.writeAll("\n"); try formatter.writeIndent(Writer, writer); - formatter.printAs(.Object, Writer, writer, stream.value, stream.value.jsType(), enable_ansi_colors); + try formatter.printAs(.Object, Writer, writer, stream.value, stream.value.jsType(), enable_ansi_colors); } } } diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 76e6bd4993..13955dbf52 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -143,7 +143,7 @@ pub const Response = struct { try formatter.writeIndent(Writer, writer); try writer.writeAll(comptime Output.prettyFmt("ok: ", enable_ansi_colors)); - formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.isOK()), .BooleanObject, enable_ansi_colors); + try formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.isOK()), .BooleanObject, enable_ansi_colors); formatter.printComma(Writer, writer, enable_ansi_colors) catch bun.outOfMemory(); try writer.writeAll("\n"); @@ -156,7 +156,7 @@ pub const Response = struct { try formatter.writeIndent(Writer, writer); try writer.writeAll(comptime Output.prettyFmt("status: ", enable_ansi_colors)); - formatter.printAs(.Double, Writer, writer, JSC.JSValue.jsNumber(this.init.status_code), .NumberObject, enable_ansi_colors); + try formatter.printAs(.Double, Writer, writer, JSC.JSValue.jsNumber(this.init.status_code), .NumberObject, enable_ansi_colors); formatter.printComma(Writer, writer, enable_ansi_colors) catch bun.outOfMemory(); try writer.writeAll("\n"); @@ -168,13 +168,13 @@ pub const Response = struct { try formatter.writeIndent(Writer, writer); try writer.writeAll(comptime Output.prettyFmt("headers: ", enable_ansi_colors)); - formatter.printAs(.Private, Writer, writer, this.getHeaders(formatter.globalThis), .DOMWrapper, enable_ansi_colors); + try formatter.printAs(.Private, Writer, writer, this.getHeaders(formatter.globalThis), .DOMWrapper, enable_ansi_colors); formatter.printComma(Writer, writer, enable_ansi_colors) catch bun.outOfMemory(); try writer.writeAll("\n"); try formatter.writeIndent(Writer, writer); try writer.writeAll(comptime Output.prettyFmt("redirected: ", enable_ansi_colors)); - formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.redirected), .BooleanObject, enable_ansi_colors); + try formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.redirected), .BooleanObject, enable_ansi_colors); formatter.printComma(Writer, writer, enable_ansi_colors) catch bun.outOfMemory(); try writer.writeAll("\n"); diff --git a/src/js/internal/errors.ts b/src/js/internal/errors.ts index fd5036ec86..739958bf03 100644 --- a/src/js/internal/errors.ts +++ b/src/js/internal/errors.ts @@ -10,4 +10,5 @@ export default { ERR_BUFFER_TOO_LARGE: $newCppFunction("ErrorCode.cpp", "jsFunction_ERR_BUFFER_TOO_LARGE", 0), ERR_ZLIB_INITIALIZATION_FAILED: $newCppFunction("ErrorCode.cpp", "jsFunction_ERR_ZLIB_INITIALIZATION_FAILED", 0), ERR_BUFFER_OUT_OF_BOUNDS: $newCppFunction("ErrorCode.cpp", "jsFunction_ERR_BUFFER_OUT_OF_BOUNDS", 0), + ERR_UNHANDLED_ERROR: $newCppFunction("ErrorCode.cpp", "jsFunction_ERR_UNHANDLED_ERROR", 0), }; diff --git a/src/js/node/domain.ts b/src/js/node/domain.ts index 7bed189e53..6a712a0a3f 100644 --- a/src/js/node/domain.ts +++ b/src/js/node/domain.ts @@ -1,5 +1,8 @@ // Import Events var EventEmitter = require("node:events"); +const { ERR_UNHANDLED_ERROR } = require("internal/errors"); + +const ObjectDefineProperty = Object.defineProperty; // Export Domain var domain: any = {}; @@ -7,6 +10,18 @@ domain.createDomain = domain.create = function () { var d = new EventEmitter(); function emitError(e) { + e ||= ERR_UNHANDLED_ERROR(); + if (typeof e === "object") { + e.domainEmitter = this; + ObjectDefineProperty(e, "domain", { + __proto__: null, + configurable: true, + enumerable: false, + value: domain, + writable: true, + }); + e.domainThrown = false; + } d.emit("error", e); } diff --git a/src/js/node/events.ts b/src/js/node/events.ts index 7759a0d18c..85a5c7707c 100644 --- a/src/js/node/events.ts +++ b/src/js/node/events.ts @@ -23,16 +23,22 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -const { ERR_INVALID_ARG_TYPE } = require("internal/errors"); +const { ERR_INVALID_ARG_TYPE, ERR_UNHANDLED_ERROR } = require("internal/errors"); const { validateObject, validateInteger, validateAbortSignal, validateNumber, validateBoolean, + validateFunction, } = require("internal/validators"); +const { inspect, types } = require("node:util"); + const SymbolFor = Symbol.for; +const ArrayPrototypeSlice = Array.prototype.slice; +const ArrayPrototypeSplice = Array.prototype.splice; +const ReflectOwnKeys = Reflect.ownKeys; const kCapture = Symbol("kCapture"); const kErrorMonitor = SymbolFor("events.errorMonitor"); @@ -42,7 +48,6 @@ const kWatermarkData = SymbolFor("nodejs.watermarkData"); const kRejection = SymbolFor("nodejs.rejection"); const kFirstEventParam = SymbolFor("nodejs.kFirstEventParam"); const captureRejectionSymbol = SymbolFor("nodejs.rejection"); -const ArrayPrototypeSlice = Array.prototype.slice; let FixedQueue; const kEmptyObject = Object.freeze({ __proto__: null }); @@ -77,26 +82,48 @@ Object.defineProperty(EventEmitterPrototype.setMaxListeners, "name", { value: "s EventEmitterPrototype.constructor = EventEmitter; EventEmitterPrototype.getMaxListeners = function getMaxListeners() { - return this?._maxListeners ?? defaultMaxListeners; + return _getMaxListeners(this); }; Object.defineProperty(EventEmitterPrototype.getMaxListeners, "name", { value: "getMaxListeners" }); function emitError(emitter, args) { var { _events: events } = emitter; - args[0] ??= new Error("Unhandled error."); - if (!events) throw args[0]; - var errorMonitor = events[kErrorMonitor]; - if (errorMonitor) { - for (var handler of ArrayPrototypeSlice.$call(errorMonitor)) { - handler.$apply(emitter, args); + + if (events !== undefined) { + const errorMonitor = events[kErrorMonitor]; + if (errorMonitor) { + for (const handler of ArrayPrototypeSlice.$call(errorMonitor)) { + handler.$apply(emitter, args); + } + } + + const handlers = events.error; + if (handlers) { + for (var handler of ArrayPrototypeSlice.$call(handlers)) { + handler.$apply(emitter, args); + } + return true; } } - var handlers = events.error; - if (!handlers) throw args[0]; - for (var handler of ArrayPrototypeSlice.$call(handlers)) { - handler.$apply(emitter, args); + + let er; + if (args.length > 0) er = args[0]; + + if (er instanceof Error) { + throw er; // Unhandled 'error' event } - return true; + + let stringifiedEr; + try { + stringifiedEr = inspect(er); + } catch { + stringifiedEr = er; + } + + // At least give some kind of context to the user + const err = ERR_UNHANDLED_ERROR(stringifiedEr); + err.context = er; + throw err; // Unhandled 'error' event } function addCatch(emitter, promise, type, args) { @@ -215,7 +242,7 @@ EventEmitterPrototype.addListener = function addListener(type, fn) { this._eventsCount++; } else { handlers.push(fn); - var m = this._maxListeners ?? defaultMaxListeners; + var m = _getMaxListeners(this); if (m > 0 && handlers.length > m && !handlers.warned) { overflowWarning(this, type, handlers); } @@ -240,7 +267,7 @@ EventEmitterPrototype.prependListener = function prependListener(type, fn) { this._eventsCount++; } else { handlers.unshift(fn); - var m = this._maxListeners ?? defaultMaxListeners; + var m = _getMaxListeners(this); if (m > 0 && handlers.length > m && !handlers.warned) { overflowWarning(this, type, handlers); } @@ -251,8 +278,7 @@ EventEmitterPrototype.prependListener = function prependListener(type, fn) { function overflowWarning(emitter, type, handlers) { handlers.warned = true; const warn = new Error( - `Possible EventEmitter memory leak detected. ${handlers.length} ${String(type)} listeners ` + - `added to [${emitter.constructor.name}]. Use emitter.setMaxListeners() to increase limit`, + `Possible EventTarget memory leak detected. ${handlers.length} ${String(type)} listeners added to ${inspect(emitter, { depth: -1 })}. MaxListeners is ${emitter._maxListeners}. Use events.setMaxListeners() to increase limit`, ); warn.name = "MaxListenersExceededWarning"; warn.emitter = emitter; @@ -291,45 +317,70 @@ EventEmitterPrototype.prependOnceListener = function prependOnceListener(type, f return this; }; -EventEmitterPrototype.removeListener = function removeListener(type, fn) { - checkListener(fn); - var { _events: events } = this; - if (!events) return this; - var handlers = events[type]; - if (!handlers) return this; - var length = handlers.length; +EventEmitterPrototype.removeListener = function removeListener(type, listener) { + checkListener(listener); + + const events = this._events; + if (events === undefined) return this; + + const list = events[type]; + if (list === undefined) return this; + let position = -1; - for (let i = length - 1; i >= 0; i--) { - if (handlers[i] === fn || handlers[i].listener === fn) { + for (let i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { position = i; break; } } if (position < 0) return this; - if (position === 0) { - handlers.shift(); - } else { - handlers.splice(position, 1); - } - if (handlers.length === 0) { + + if (position === 0) list.shift(); + else ArrayPrototypeSplice.$call(list, position, 1); + + if (list.length === 0) { delete events[type]; this._eventsCount--; } + + if (events.removeListener !== undefined) this.emit("removeListener", type, listener.listener || listener); + return this; }; EventEmitterPrototype.off = EventEmitterPrototype.removeListener; EventEmitterPrototype.removeAllListeners = function removeAllListeners(type) { - var { _events: events } = this; - if (type && events) { - if (events[type]) { - delete events[type]; - this._eventsCount--; + const events = this._events; + if (events === undefined) return this; + + if (events.removeListener === undefined) { + if (type) { + if (events[type]) { + delete events[type]; + this._eventsCount--; + } + } else { + this._events = { __proto__: null }; } - } else { - this._events = { __proto__: null }; + return this; } + + // Emit removeListener for all listeners on all events + if (!type) { + for (const key of ReflectOwnKeys(events)) { + if (key === "removeListener") continue; + this.removeAllListeners(key); + } + this.removeAllListeners("removeListener"); + this._events = { __proto__: null }; + this._eventsCount = 0; + return this; + } + + // emit in LIFO order + const listeners = events[type]; + for (let i = listeners.length - 1; i >= 0; i--) this.removeListener(type, listeners[i]); return this; }; @@ -599,20 +650,20 @@ function getEventListeners(emitter, type) { // https://github.com/nodejs/node/blob/2eff28fb7a93d3f672f80b582f664a7c701569fb/lib/events.js#L315-L339 function setMaxListeners(n = defaultMaxListeners, ...eventTargets) { validateNumber(n, "setMaxListeners", 0); - const length = eventTargets?.length; - if (length) { - for (let eventTargetOrEmitter of eventTargets) { - // TODO: EventTarget setMaxListeners is not implemented yet. - // Only EventEmitter has it. - if ($isCallable(eventTargetOrEmitter?.setMaxListeners)) { - eventTargetOrEmitter.setMaxListeners(n); - } else if ($isObject(eventTargetOrEmitter) && eventTargetOrEmitter instanceof EventTarget) { - // This is a fake number so that the number can be checked against with getMaxListeners() - eventTargetOrEmitter[eventTargetMaxListenersSymbol] = n; + if (eventTargets.length === 0) { + defaultMaxListeners = n; + } else { + for (let i = 0; i < eventTargets.length; i++) { + const target = eventTargets[i]; + if (types.isEventTarget(target)) { + target[kMaxEventTargetListeners] = n; + target[kMaxEventTargetListenersWarned] = false; + } else if (typeof target.setMaxListeners === "function") { + target.setMaxListeners(n); + } else { + throw ERR_INVALID_ARG_TYPE("eventTargets", ["EventEmitter", "EventTarget"], target); } } - } else { - defaultMaxListeners = n; } } Object.defineProperty(setMaxListeners, "name", { value: "setMaxListeners" }); @@ -674,16 +725,23 @@ function ERR_OUT_OF_RANGE(name, range, value) { } function checkListener(listener) { - if (typeof listener !== "function") { - throw new TypeError("The listener must be a function"); - } + validateFunction(listener, "listener"); +} + +function _getMaxListeners(emitter) { + return emitter?._maxListeners ?? defaultMaxListeners; } let AsyncResource = null; -const eventTargetMaxListenersSymbol = Symbol("EventTarget.maxListeners"); function getMaxListeners(emitterOrTarget) { - return emitterOrTarget?.[eventTargetMaxListenersSymbol] ?? emitterOrTarget?._maxListeners ?? defaultMaxListeners; + if (typeof emitterOrTarget?.getMaxListeners === "function") { + return _getMaxListeners(emitterOrTarget); + } else if (types.isEventTarget(emitterOrTarget)) { + emitterOrTarget[kMaxEventTargetListeners] ??= defaultMaxListeners; + return emitterOrTarget[kMaxEventTargetListeners]; + } + throw ERR_INVALID_ARG_TYPE("emitter", ["EventEmitter", "EventTarget"], emitterOrTarget); } Object.defineProperty(getMaxListeners, "name", { value: "getMaxListeners" }); diff --git a/test/js/bun/net/socket.test.ts b/test/js/bun/net/socket.test.ts index c60c267cee..e3735148f3 100644 --- a/test/js/bun/net/socket.test.ts +++ b/test/js/bun/net/socket.test.ts @@ -372,7 +372,7 @@ it("should allow large amounts of data to be sent and received", async () => { it("it should not crash when getting a ReferenceError on client socket open", async () => { using server = Bun.serve({ - port: 8080, + port: 0, hostname: "localhost", fetch() { return new Response("Hello World"); @@ -413,7 +413,7 @@ it("it should not crash when getting a ReferenceError on client socket open", as it("it should not crash when returning a Error on client socket open", async () => { using server = Bun.serve({ - port: 8080, + port: 0, hostname: "localhost", fetch() { return new Response("Hello World"); diff --git a/test/js/node/child_process/child_process-node.test.js b/test/js/node/child_process/child_process-node.test.js index 42931a8dcf..1d4a7a4305 100644 --- a/test/js/node/child_process/child_process-node.test.js +++ b/test/js/node/child_process/child_process-node.test.js @@ -659,7 +659,7 @@ describe("fork", () => { code: "ERR_INVALID_ARG_TYPE", name: "TypeError", message: expect.stringContaining( - `The "modulePath" argument must be of type string, Buffer or URL. Received: `, + `The "modulePath" argument must be of type string, Buffer, or URL. Received `, ), }), ); @@ -718,7 +718,7 @@ describe("fork", () => { expect.objectContaining({ code: "ERR_INVALID_ARG_TYPE", name: "TypeError", - message: expect.stringContaining(`The "options" argument must be of type object. Received: `), + message: expect.stringContaining(`The "options" argument must be of type object. Received `), }), ); }); diff --git a/test/js/node/child_process/child_process.test.ts b/test/js/node/child_process/child_process.test.ts index f70772d421..a259c6897d 100644 --- a/test/js/node/child_process/child_process.test.ts +++ b/test/js/node/child_process/child_process.test.ts @@ -96,7 +96,7 @@ describe("spawn()", () => { it("should disallow invalid filename", () => { // @ts-ignore expect(() => spawn(123)).toThrow({ - message: 'The "file" argument must be of type string. Received 123', + message: 'The "file" argument must be of type string. Received type number (123)', code: "ERR_INVALID_ARG_TYPE", }); }); diff --git a/test/js/node/test/parallel/test-async-hooks-vm-gc.js b/test/js/node/test/parallel/test-async-hooks-vm-gc.js new file mode 100644 index 0000000000..da95e3579d --- /dev/null +++ b/test/js/node/test/parallel/test-async-hooks-vm-gc.js @@ -0,0 +1,15 @@ +// Flags: --expose-gc +'use strict'; + +require('../common'); +const asyncHooks = require('async_hooks'); +const vm = require('vm'); + +// This is a regression test for https://github.com/nodejs/node/issues/39019 +// +// It should not segfault. + +const hook = asyncHooks.createHook({ init() {} }).enable(); +vm.createContext(); +globalThis.gc(); +hook.disable(); diff --git a/test/js/node/test/parallel/test-dgram-send-address-types.js b/test/js/node/test/parallel/test-dgram-send-address-types.js new file mode 100644 index 0000000000..a31e53f903 --- /dev/null +++ b/test/js/node/test/parallel/test-dgram-send-address-types.js @@ -0,0 +1,47 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const dgram = require('dgram'); + +const buf = Buffer.from('test'); + +const defaultCases = ['', null, undefined]; + +const onMessage = common.mustSucceed((bytes) => { + assert.strictEqual(bytes, buf.length); +}, defaultCases.length + 1); + +const client = dgram.createSocket('udp4').bind(0, () => { + const port = client.address().port; + + // Check valid addresses + defaultCases.forEach((address) => { + client.send(buf, port, address, onMessage); + }); + + // Valid address: not provided + client.send(buf, port, onMessage); + + // Check invalid addresses + [ + [], + 0, + 1, + true, + false, + 0n, + 1n, + {}, + Symbol(), + ].forEach((invalidInput) => { + const expectedError = { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "address" argument must be of type string.' + + `${common.invalidArgTypeHelper(invalidInput)}` + }; + assert.throws(() => client.send(buf, port, invalidInput), expectedError); + }); +}); + +client.unref(); diff --git a/test/js/node/test/parallel/test-event-emitter-errors.js b/test/js/node/test/parallel/test-event-emitter-errors.js new file mode 100644 index 0000000000..f22fc3bd58 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-errors.js @@ -0,0 +1,37 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const EventEmitter = require('events'); +const util = require('util'); + +const EE = new EventEmitter(); + +assert.throws( + () => EE.emit('error', 'Accepts a string'), + { + code: 'ERR_UNHANDLED_ERROR', + name: 'Error', + message: "Unhandled error. ('Accepts a string')", + } +); + +assert.throws( + () => EE.emit('error', { message: 'Error!' }), + { + code: 'ERR_UNHANDLED_ERROR', + name: 'Error', + message: "Unhandled error. ({ message: 'Error!' })", + } +); + +assert.throws( + () => EE.emit('error', { + message: 'Error!', + [util.inspect.custom]() { throw new Error(); }, + }), + { + code: 'ERR_UNHANDLED_ERROR', + name: 'Error', + message: 'Unhandled error. ([object Object])', + } +); diff --git a/test/js/node/test/parallel/test-event-emitter-invalid-listener.js b/test/js/node/test/parallel/test-event-emitter-invalid-listener.js new file mode 100644 index 0000000000..f05766c72e --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-invalid-listener.js @@ -0,0 +1,20 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const EventEmitter = require('events'); + +const eventsMethods = ['on', 'once', 'removeListener', 'prependOnceListener']; + +// Verify that the listener must be a function for events methods +for (const method of eventsMethods) { + assert.throws(() => { + const ee = new EventEmitter(); + ee[method]('foo', null); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "listener" argument must be of type function. ' + + 'Received null', + }); +} diff --git a/test/js/node/test/parallel/test-event-emitter-listeners-side-effects.js b/test/js/node/test/parallel/test-event-emitter-listeners-side-effects.js new file mode 100644 index 0000000000..f1a9e659e0 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-listeners-side-effects.js @@ -0,0 +1,60 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +require('../common'); +const assert = require('assert'); + +const EventEmitter = require('events').EventEmitter; + +const e = new EventEmitter(); +let fl; // foo listeners + +fl = e.listeners('foo'); +assert(Array.isArray(fl)); +assert.strictEqual(fl.length, 0); +assert(!(e._events instanceof Object)); +assert.deepStrictEqual(Object.keys(e._events), []); + +e.on('foo', assert.fail); +fl = e.listeners('foo'); +assert.deepEqual(e._events.foo, [assert.fail]); +assert(Array.isArray(fl)); +assert.strictEqual(fl.length, 1); +assert.strictEqual(fl[0], assert.fail); + +e.listeners('bar'); + +e.on('foo', assert.ok); +fl = e.listeners('foo'); + +assert(Array.isArray(e._events.foo)); +assert.strictEqual(e._events.foo.length, 2); +assert.strictEqual(e._events.foo[0], assert.fail); +assert.strictEqual(e._events.foo[1], assert.ok); + +assert(Array.isArray(fl)); +assert.strictEqual(fl.length, 2); +assert.strictEqual(fl[0], assert.fail); +assert.strictEqual(fl[1], assert.ok); + +console.log('ok'); diff --git a/test/js/node/test/parallel/test-event-emitter-max-listeners-warning-for-null.js b/test/js/node/test/parallel/test-event-emitter-max-listeners-warning-for-null.js new file mode 100644 index 0000000000..673b42336e --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-max-listeners-warning-for-null.js @@ -0,0 +1,22 @@ +// Flags: --no-warnings +// The flag suppresses stderr output but the warning event will still emit +'use strict'; + +const common = require('../common'); +const events = require('events'); +const assert = require('assert'); + +const e = new events.EventEmitter(); +e.setMaxListeners(1); + +process.on('warning', common.mustCall((warning) => { + assert.ok(warning instanceof Error); + assert.strictEqual(warning.name, 'MaxListenersExceededWarning'); + assert.strictEqual(warning.emitter, e); + assert.strictEqual(warning.count, 2); + assert.strictEqual(warning.type, null); + assert.ok(warning.message.includes('2 null listeners added to [EventEmitter]. MaxListeners is 1.')); +})); + +e.on(null, () => {}); +e.on(null, () => {}); diff --git a/test/js/node/test/parallel/test-event-emitter-max-listeners-warning-for-symbol.js b/test/js/node/test/parallel/test-event-emitter-max-listeners-warning-for-symbol.js new file mode 100644 index 0000000000..e654b7697c --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-max-listeners-warning-for-symbol.js @@ -0,0 +1,24 @@ +// Flags: --no-warnings +// The flag suppresses stderr output but the warning event will still emit +'use strict'; + +const common = require('../common'); +const events = require('events'); +const assert = require('assert'); + +const symbol = Symbol('symbol'); + +const e = new events.EventEmitter(); +e.setMaxListeners(1); + +process.on('warning', common.mustCall((warning) => { + assert.ok(warning instanceof Error); + assert.strictEqual(warning.name, 'MaxListenersExceededWarning'); + assert.strictEqual(warning.emitter, e); + assert.strictEqual(warning.count, 2); + assert.strictEqual(warning.type, symbol); + assert.ok(warning.message.includes('2 Symbol(symbol) listeners added to [EventEmitter]. MaxListeners is 1.')); +})); + +e.on(symbol, () => {}); +e.on(symbol, () => {}); diff --git a/test/js/node/test/parallel/test-event-emitter-max-listeners-warning.js b/test/js/node/test/parallel/test-event-emitter-max-listeners-warning.js new file mode 100644 index 0000000000..31bd8d0712 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-max-listeners-warning.js @@ -0,0 +1,30 @@ +// Flags: --no-warnings +// The flag suppresses stderr output but the warning event will still emit +'use strict'; + +const common = require('../common'); +const events = require('events'); +const assert = require('assert'); + +class FakeInput extends events.EventEmitter { + resume() {} + pause() {} + write() {} + end() {} +} + +const e = new FakeInput(); +e.setMaxListeners(1); + +process.on('warning', common.mustCall((warning) => { + assert.ok(warning instanceof Error); + assert.strictEqual(warning.name, 'MaxListenersExceededWarning'); + assert.strictEqual(warning.emitter, e); + assert.strictEqual(warning.count, 2); + assert.strictEqual(warning.type, 'event-type'); + assert.ok(warning.message.includes('2 event-type listeners added to [FakeInput]. MaxListeners is 1.')); +})); + +e.on('event-type', () => {}); +e.on('event-type', () => {}); // Trigger warning. +e.on('event-type', () => {}); // Verify that warning is emitted only once. diff --git a/test/js/node/test/parallel/test-event-emitter-max-listeners.js b/test/js/node/test/parallel/test-event-emitter-max-listeners.js new file mode 100644 index 0000000000..9b9c2ad0d5 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-max-listeners.js @@ -0,0 +1,88 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const events = require('events'); +const e = new events.EventEmitter(); + +e.on('maxListeners', common.mustCall()); + +// Should not corrupt the 'maxListeners' queue. +e.setMaxListeners(42); + +const rangeErrorObjs = [NaN, -1]; +const typeErrorObj = 'and even this'; + +for (const obj of rangeErrorObjs) { + assert.throws( + () => e.setMaxListeners(obj), + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + } + ); + + assert.throws( + () => events.defaultMaxListeners = obj, + { + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError', + } + ); +} + +assert.throws( + () => e.setMaxListeners(typeErrorObj), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + } +); + +assert.throws( + () => events.defaultMaxListeners = typeErrorObj, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + } +); + +e.emit('maxListeners'); + +{ + const { EventEmitter, defaultMaxListeners } = events; + for (const obj of rangeErrorObjs) { + assert.throws(() => EventEmitter.setMaxListeners(obj), { + code: 'ERR_OUT_OF_RANGE', + }); + } + + assert.throws(() => EventEmitter.setMaxListeners(typeErrorObj), { + code: 'ERR_INVALID_ARG_TYPE', + }); + + assert.throws( + () => EventEmitter.setMaxListeners(defaultMaxListeners, 'INVALID_EMITTER'), + { code: 'ERR_INVALID_ARG_TYPE' } + ); +} diff --git a/test/js/node/test/parallel/test-event-emitter-no-error-provided-to-error-event.js b/test/js/node/test/parallel/test-event-emitter-no-error-provided-to-error-event.js new file mode 100644 index 0000000000..5c30b54533 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-no-error-provided-to-error-event.js @@ -0,0 +1,56 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const events = require('events'); +const domain = require('domain'); + +{ + const e = new events.EventEmitter(); + const d = domain.create(); + d.add(e); + d.on('error', common.mustCall((er) => { + assert(er instanceof Error, 'error created'); + })); + e.emit('error'); +} + +for (const arg of [false, null, undefined]) { + const e = new events.EventEmitter(); + const d = domain.create(); + d.add(e); + d.on('error', common.mustCall((er) => { + assert(er instanceof Error, 'error created'); + })); + e.emit('error', arg); +} + +for (const arg of [42, 'fortytwo', true]) { + const e = new events.EventEmitter(); + const d = domain.create(); + d.add(e); + d.on('error', common.mustCall((er) => { + assert.strictEqual(er, arg); + })); + e.emit('error', arg); +} diff --git a/test/js/node/test/parallel/test-event-emitter-remove-all-listeners.js b/test/js/node/test/parallel/test-event-emitter-remove-all-listeners.js new file mode 100644 index 0000000000..c62183fd08 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-remove-all-listeners.js @@ -0,0 +1,123 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const events = require('events'); + + +function expect(expected) { + const actual = []; + process.on('exit', function() { + assert.deepStrictEqual(actual.sort(), expected.sort()); + }); + function listener(name) { + actual.push(name); + } + return common.mustCall(listener, expected.length); +} + +{ + const ee = new events.EventEmitter(); + const noop = common.mustNotCall(); + ee.on('foo', noop); + ee.on('bar', noop); + ee.on('baz', noop); + ee.on('baz', noop); + const fooListeners = ee.listeners('foo'); + const barListeners = ee.listeners('bar'); + const bazListeners = ee.listeners('baz'); + ee.on('removeListener', expect(['bar', 'baz', 'baz'])); + ee.removeAllListeners('bar'); + ee.removeAllListeners('baz'); + assert.deepStrictEqual(ee.listeners('foo'), [noop]); + assert.deepStrictEqual(ee.listeners('bar'), []); + assert.deepStrictEqual(ee.listeners('baz'), []); + // After calling removeAllListeners(), + // the old listeners array should stay unchanged. + assert.deepStrictEqual(fooListeners, [noop]); + assert.deepStrictEqual(barListeners, [noop]); + assert.deepStrictEqual(bazListeners, [noop, noop]); + // After calling removeAllListeners(), + // new listeners arrays is different from the old. + assert.notStrictEqual(ee.listeners('bar'), barListeners); + assert.notStrictEqual(ee.listeners('baz'), bazListeners); +} + +{ + const ee = new events.EventEmitter(); + ee.on('foo', common.mustNotCall()); + ee.on('bar', common.mustNotCall()); + // Expect LIFO order + ee.on('removeListener', expect(['foo', 'bar', 'removeListener'])); + ee.on('removeListener', expect(['foo', 'bar'])); + ee.removeAllListeners(); + assert.deepStrictEqual([], ee.listeners('foo')); + assert.deepStrictEqual([], ee.listeners('bar')); +} + +{ + const ee = new events.EventEmitter(); + ee.on('removeListener', common.mustNotCall()); + // Check for regression where removeAllListeners() throws when + // there exists a 'removeListener' listener, but there exists + // no listeners for the provided event type. + ee.removeAllListeners.bind(ee, 'foo'); +} + +{ + const ee = new events.EventEmitter(); + let expectLength = 2; + ee.on('removeListener', function(name, noop) { + assert.strictEqual(expectLength--, this.listeners('baz').length); + }); + ee.on('baz', common.mustNotCall()); + ee.on('baz', common.mustNotCall()); + ee.on('baz', common.mustNotCall()); + assert.strictEqual(ee.listeners('baz').length, expectLength + 1); + ee.removeAllListeners('baz'); + assert.strictEqual(ee.listeners('baz').length, 0); +} + +{ + const ee = new events.EventEmitter(); + assert.deepStrictEqual(ee, ee.removeAllListeners()); +} + +{ + const ee = new events.EventEmitter(); + ee._events = undefined; + assert.strictEqual(ee, ee.removeAllListeners()); +} + +{ + const ee = new events.EventEmitter(); + const symbol = Symbol('symbol'); + const noop = common.mustNotCall(); + ee.on(symbol, noop); + + ee.on('removeListener', common.mustCall((...args) => { + assert.deepStrictEqual(args, [symbol, noop]); + })); + + ee.removeAllListeners(); +} diff --git a/test/js/node/test/parallel/test-event-emitter-remove-listeners.js b/test/js/node/test/parallel/test-event-emitter-remove-listeners.js new file mode 100644 index 0000000000..5ab52b8320 --- /dev/null +++ b/test/js/node/test/parallel/test-event-emitter-remove-listeners.js @@ -0,0 +1,170 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const EventEmitter = require('events'); + +function listener1() {} + +function listener2() {} + +{ + const ee = new EventEmitter(); + ee.on('hello', listener1); + ee.on('removeListener', common.mustCall((name, cb) => { + assert.strictEqual(name, 'hello'); + assert.strictEqual(cb, listener1); + })); + ee.removeListener('hello', listener1); + assert.deepStrictEqual([], ee.listeners('hello')); +} + +{ + const ee = new EventEmitter(); + ee.on('hello', listener1); + ee.on('removeListener', common.mustNotCall()); + ee.removeListener('hello', listener2); + assert.deepStrictEqual([listener1], ee.listeners('hello')); +} + +{ + const ee = new EventEmitter(); + ee.on('hello', listener1); + ee.on('hello', listener2); + ee.once('removeListener', common.mustCall((name, cb) => { + assert.strictEqual(name, 'hello'); + assert.strictEqual(cb, listener1); + assert.deepStrictEqual([listener2], ee.listeners('hello')); + })); + ee.removeListener('hello', listener1); + assert.deepStrictEqual([listener2], ee.listeners('hello')); + ee.once('removeListener', common.mustCall((name, cb) => { + assert.strictEqual(name, 'hello'); + assert.strictEqual(cb, listener2); + assert.deepStrictEqual([], ee.listeners('hello')); + })); + ee.removeListener('hello', listener2); + assert.deepStrictEqual([], ee.listeners('hello')); +} + +{ + const ee = new EventEmitter(); + + function remove1() { + assert.fail('remove1 should not have been called'); + } + + function remove2() { + assert.fail('remove2 should not have been called'); + } + + ee.on('removeListener', common.mustCall(function(name, cb) { + if (cb !== remove1) return; + this.removeListener('quux', remove2); + this.emit('quux'); + }, 2)); + ee.on('quux', remove1); + ee.on('quux', remove2); + ee.removeListener('quux', remove1); +} + +{ + const ee = new EventEmitter(); + ee.on('hello', listener1); + ee.on('hello', listener2); + ee.once('removeListener', common.mustCall((name, cb) => { + assert.strictEqual(name, 'hello'); + assert.strictEqual(cb, listener1); + assert.deepStrictEqual([listener2], ee.listeners('hello')); + ee.once('removeListener', common.mustCall((name, cb) => { + assert.strictEqual(name, 'hello'); + assert.strictEqual(cb, listener2); + assert.deepStrictEqual([], ee.listeners('hello')); + })); + ee.removeListener('hello', listener2); + assert.deepStrictEqual([], ee.listeners('hello')); + })); + ee.removeListener('hello', listener1); + assert.deepStrictEqual([], ee.listeners('hello')); +} + +{ + const ee = new EventEmitter(); + const listener3 = common.mustCall(() => { + ee.removeListener('hello', listener4); + }, 2); + const listener4 = common.mustCall(); + + ee.on('hello', listener3); + ee.on('hello', listener4); + + // listener4 will still be called although it is removed by listener 3. + ee.emit('hello'); + // This is so because the internal listener array at time of emit + // was [listener3,listener4] + + // Internal listener array [listener3] + ee.emit('hello'); +} + +{ + const ee = new EventEmitter(); + + ee.once('hello', listener1); + ee.on('removeListener', common.mustCall((eventName, listener) => { + assert.strictEqual(eventName, 'hello'); + assert.strictEqual(listener, listener1); + })); + ee.emit('hello'); +} + +{ + const ee = new EventEmitter(); + + assert.deepStrictEqual(ee, ee.removeListener('foo', () => {})); +} + +{ + const ee = new EventEmitter(); + const listener = () => {}; + ee._events = undefined; + const e = ee.removeListener('foo', listener); + assert.strictEqual(e, ee); +} + +{ + const ee = new EventEmitter(); + + ee.on('foo', listener1); + ee.on('foo', listener2); + assert.deepStrictEqual(ee.listeners('foo'), [listener1, listener2]); + + ee.removeListener('foo', listener1); + assert.deepEqual(ee._events.foo, [listener2]); + + ee.on('foo', listener1); + assert.deepStrictEqual(ee.listeners('foo'), [listener2, listener1]); + + ee.removeListener('foo', listener1); + assert.deepEqual(ee._events.foo, [listener2]); +} diff --git a/test/js/node/test/parallel/test-require-delete-array-iterator.js b/test/js/node/test/parallel/test-require-delete-array-iterator.js new file mode 100644 index 0000000000..5424ef8b75 --- /dev/null +++ b/test/js/node/test/parallel/test-require-delete-array-iterator.js @@ -0,0 +1,13 @@ +'use strict'; + +const common = require('../common'); + + +const ArrayIteratorPrototype = + Object.getPrototypeOf(Array.prototype[Symbol.iterator]()); + +delete Array.prototype[Symbol.iterator]; +delete ArrayIteratorPrototype.next; + +require('../common/fixtures'); +import('../fixtures/es-modules/test-esm-ok.mjs').then(common.mustCall()); diff --git a/test/js/node/test/parallel/test-stream-readable-setEncoding-null.js b/test/js/node/test/parallel/test-stream-readable-setEncoding-null.js new file mode 100644 index 0000000000..b95b26bb79 --- /dev/null +++ b/test/js/node/test/parallel/test-stream-readable-setEncoding-null.js @@ -0,0 +1,15 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const { Readable } = require('stream'); + + +{ + const readable = new Readable({ encoding: 'hex' }); + assert.strictEqual(readable._readableState.encoding, 'hex'); + + readable.setEncoding(null); + + assert.strictEqual(readable._readableState.encoding, 'utf8'); +} diff --git a/test/js/node/test/parallel/test-stream-readable-unshift.js b/test/js/node/test/parallel/test-stream-readable-unshift.js new file mode 100644 index 0000000000..cccc834fc1 --- /dev/null +++ b/test/js/node/test/parallel/test-stream-readable-unshift.js @@ -0,0 +1,170 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { Readable } = require('stream'); + +{ + // Check that strings are saved as Buffer + const readable = new Readable({ read() {} }); + + const string = 'abc'; + + readable.on('data', common.mustCall((chunk) => { + assert(Buffer.isBuffer(chunk)); + assert.strictEqual(chunk.toString('utf8'), string); + }, 1)); + + readable.unshift(string); + +} + +{ + // Check that data goes at the beginning + const readable = new Readable({ read() {} }); + const unshift = 'front'; + const push = 'back'; + + const expected = [unshift, push]; + readable.on('data', common.mustCall((chunk) => { + assert.strictEqual(chunk.toString('utf8'), expected.shift()); + }, 2)); + + + readable.push(push); + readable.unshift(unshift); +} + +{ + // Check that buffer is saved with correct encoding + const readable = new Readable({ read() {} }); + + const encoding = 'base64'; + const string = Buffer.from('abc').toString(encoding); + + readable.on('data', common.mustCall((chunk) => { + assert.strictEqual(chunk.toString(encoding), string); + }, 1)); + + readable.unshift(string, encoding); + +} + +{ + + const streamEncoding = 'base64'; + + function checkEncoding(readable) { + + // chunk encodings + const encodings = ['utf8', 'binary', 'hex', 'base64']; + const expected = []; + + readable.on('data', common.mustCall((chunk) => { + const { encoding, string } = expected.pop(); + assert.strictEqual(chunk.toString(encoding), string); + }, encodings.length)); + + for (const encoding of encodings) { + const string = 'abc'; + + // If encoding is the same as the state.encoding the string is + // saved as is + const expect = encoding !== streamEncoding ? + Buffer.from(string, encoding).toString(streamEncoding) : string; + + expected.push({ encoding, string: expect }); + + readable.unshift(string, encoding); + } + } + + const r1 = new Readable({ read() {} }); + r1.setEncoding(streamEncoding); + checkEncoding(r1); + + const r2 = new Readable({ read() {}, encoding: streamEncoding }); + checkEncoding(r2); + +} + +{ + // Both .push & .unshift should have the same behaviour + // When setting an encoding, each chunk should be emitted with that encoding + const encoding = 'base64'; + + function checkEncoding(readable) { + const string = 'abc'; + readable.on('data', common.mustCall((chunk) => { + assert.strictEqual(chunk, Buffer.from(string).toString(encoding)); + }, 2)); + + readable.push(string); + readable.unshift(string); + } + + const r1 = new Readable({ read() {} }); + r1.setEncoding(encoding); + checkEncoding(r1); + + const r2 = new Readable({ read() {}, encoding }); + checkEncoding(r2); + +} + +{ + // Check that ObjectMode works + const readable = new Readable({ objectMode: true, read() {} }); + + const chunks = ['a', 1, {}, []]; + + readable.on('data', common.mustCall((chunk) => { + assert.strictEqual(chunk, chunks.pop()); + }, chunks.length)); + + for (const chunk of chunks) { + readable.unshift(chunk); + } +} + +{ + + // Should not throw: https://github.com/nodejs/node/issues/27192 + const highWaterMark = 50; + class ArrayReader extends Readable { + constructor(opt) { + super({ highWaterMark }); + // The error happened only when pushing above hwm + this.buffer = new Array(highWaterMark * 2).fill(0).map(String); + } + _read(size) { + while (this.buffer.length) { + const chunk = this.buffer.shift(); + if (!this.buffer.length) { + this.push(chunk); + this.push(null); + return true; + } + if (!this.push(chunk)) + return; + } + } + } + + function onRead() { + while (null !== (stream.read())) { + // Remove the 'readable' listener before unshifting + stream.removeListener('readable', onRead); + stream.unshift('a'); + stream.on('data', (chunk) => { + console.log(chunk.length); + }); + break; + } + } + + const stream = new ArrayReader(); + stream.once('readable', common.mustCall(onRead)); + stream.on('end', common.mustCall()); + +} diff --git a/test/js/node/test/parallel/test-util-styletext.js b/test/js/node/test/parallel/test-util-styletext.js new file mode 100644 index 0000000000..6baa6a60ea --- /dev/null +++ b/test/js/node/test/parallel/test-util-styletext.js @@ -0,0 +1,43 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const util = require('util'); + +[ + undefined, + null, + false, + 5n, + 5, + Symbol(), + () => {}, + {}, +].forEach((invalidOption) => { + assert.throws(() => { + util.styleText(invalidOption, 'test'); + }, { + code: 'ERR_INVALID_ARG_VALUE', + }); + assert.throws(() => { + util.styleText('red', invalidOption); + }, { + code: 'ERR_INVALID_ARG_TYPE' + }); +}); + +assert.throws(() => { + util.styleText('invalid', 'text'); +}, { + code: 'ERR_INVALID_ARG_VALUE', +}); + +assert.strictEqual(util.styleText('red', 'test'), '\u001b[31mtest\u001b[39m'); + +assert.strictEqual(util.styleText(['bold', 'red'], 'test'), '\u001b[1m\u001b[31mtest\u001b[39m\u001b[22m'); +assert.strictEqual(util.styleText(['bold', 'red'], 'test'), util.styleText('bold', util.styleText('red', 'test'))); + +assert.throws(() => { + util.styleText(['invalid'], 'text'); +}, { + code: 'ERR_INVALID_ARG_VALUE', +}); diff --git a/test/js/node/test/parallel/test-vm-global-property-enumerator.js b/test/js/node/test/parallel/test-vm-global-property-enumerator.js new file mode 100644 index 0000000000..7b37c2af41 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-global-property-enumerator.js @@ -0,0 +1,49 @@ +'use strict'; +require('../common'); +const vm = require('vm'); +const assert = require('assert'); + +// Regression of https://github.com/nodejs/node/issues/53346 + +const cases = [ + { + get key() { + return 'value'; + }, + }, + { + // Intentionally single setter. + // eslint-disable-next-line accessor-pairs + set key(value) {}, + }, + {}, + { + key: 'value', + }, + (new class GetterObject { + get key() { + return 'value'; + } + }()), + (new class SetterObject { + // Intentionally single setter. + // eslint-disable-next-line accessor-pairs + set key(value) { + // noop + } + }()), + [], + [['key', 'value']], + { + __proto__: { + key: 'value', + }, + }, +]; + +for (const [idx, obj] of cases.entries()) { + const ctx = vm.createContext(obj); + const globalObj = vm.runInContext('this', ctx); + const keys = Object.keys(globalObj); + assert.deepStrictEqual(keys, Object.keys(obj), `Case ${idx} failed`); +} diff --git a/test/js/node/test/parallel/test-vm-global-property-prototype.js b/test/js/node/test/parallel/test-vm-global-property-prototype.js new file mode 100644 index 0000000000..fe8abc8be4 --- /dev/null +++ b/test/js/node/test/parallel/test-vm-global-property-prototype.js @@ -0,0 +1,83 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const vm = require('vm'); + +const sandbox = { + onSelf: 'onSelf', +}; + +function onSelfGetter() { + return 'onSelfGetter'; +} + +Object.defineProperty(sandbox, 'onSelfGetter', { + get: onSelfGetter, +}); + +Object.defineProperty(sandbox, 1, { + value: 'onSelfIndexed', + writable: false, + enumerable: false, + configurable: true, +}); + +const ctx = vm.createContext(sandbox); + +const result = vm.runInContext(` +Object.prototype.onProto = 'onProto'; +Object.defineProperty(Object.prototype, 'onProtoGetter', { + get() { + return 'onProtoGetter'; + }, +}); +Object.defineProperty(Object.prototype, 2, { + value: 'onProtoIndexed', + writable: false, + enumerable: false, + configurable: true, +}); + +const resultHasOwn = { + onSelf: Object.hasOwn(this, 'onSelf'), + onSelfGetter: Object.hasOwn(this, 'onSelfGetter'), + onSelfIndexed: Object.hasOwn(this, 1), + onProto: Object.hasOwn(this, 'onProto'), + onProtoGetter: Object.hasOwn(this, 'onProtoGetter'), + onProtoIndexed: Object.hasOwn(this, 2), +}; + +const getDesc = (prop) => Object.getOwnPropertyDescriptor(this, prop); +const resultDesc = { + onSelf: getDesc('onSelf'), + onSelfGetter: getDesc('onSelfGetter'), + onSelfIndexed: getDesc(1), + onProto: getDesc('onProto'), + onProtoGetter: getDesc('onProtoGetter'), + onProtoIndexed: getDesc(2), +}; +({ + resultHasOwn, + resultDesc, +}); +`, ctx); + +// eslint-disable-next-line no-restricted-properties +assert.deepEqual(result, { + resultHasOwn: { + onSelf: true, + onSelfGetter: true, + onSelfIndexed: true, + onProto: false, + onProtoGetter: false, + onProtoIndexed: false, + }, + resultDesc: { + onSelf: { value: 'onSelf', writable: true, enumerable: true, configurable: true }, + onSelfGetter: { get: onSelfGetter, set: undefined, enumerable: false, configurable: false }, + onSelfIndexed: { value: 'onSelfIndexed', writable: false, enumerable: false, configurable: true }, + onProto: undefined, + onProtoGetter: undefined, + onProtoIndexed: undefined, + }, +}); diff --git a/test/js/node/test/parallel/test-weakref.js b/test/js/node/test/parallel/test-weakref.js new file mode 100644 index 0000000000..ca7485aaa6 --- /dev/null +++ b/test/js/node/test/parallel/test-weakref.js @@ -0,0 +1,13 @@ +'use strict'; + +// Flags: --expose-gc + +require('../common'); +const assert = require('assert'); + +const w = new globalThis.WeakRef({}); + +setTimeout(() => { + globalThis.gc(); + assert.strictEqual(w.deref(), undefined); +}, 200); diff --git a/test/js/node/test/parallel/test-worker-message-channel-sharedarraybuffer.js b/test/js/node/test/parallel/test-worker-message-channel-sharedarraybuffer.js new file mode 100644 index 0000000000..220aa978b1 --- /dev/null +++ b/test/js/node/test/parallel/test-worker-message-channel-sharedarraybuffer.js @@ -0,0 +1,28 @@ +// Flags: --expose-gc +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { Worker } = require('worker_threads'); + +{ + const sharedArrayBuffer = new SharedArrayBuffer(12); + const local = Buffer.from(sharedArrayBuffer); + + const w = new Worker(` + const { parentPort } = require('worker_threads'); + parentPort.on('message', ({ sharedArrayBuffer }) => { + const local = Buffer.from(sharedArrayBuffer); + local.write('world!', 6); + parentPort.postMessage('written!'); + }); + `, { eval: true }); + w.on('message', common.mustCall(() => { + assert.strictEqual(local.toString(), 'Hello world!'); + global.gc(); + w.terminate(); + })); + w.postMessage({ sharedArrayBuffer }); + // This would be a race condition if the memory regions were overlapping + local.write('Hello '); +} diff --git a/test/js/node/test/parallel/test-worker-workerdata-sharedarraybuffer.js b/test/js/node/test/parallel/test-worker-workerdata-sharedarraybuffer.js new file mode 100644 index 0000000000..4e3d508ac9 --- /dev/null +++ b/test/js/node/test/parallel/test-worker-workerdata-sharedarraybuffer.js @@ -0,0 +1,32 @@ +// Flags: --expose-gc +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { Worker } = require('worker_threads'); + +{ + const sharedArrayBuffer = new SharedArrayBuffer(12); + const local = Buffer.from(sharedArrayBuffer); + + const w = new Worker(` + const { parentPort, workerData } = require('worker_threads'); + const local = Buffer.from(workerData.sharedArrayBuffer); + + parentPort.on('message', () => { + local.write('world!', 6); + parentPort.postMessage('written!'); + }); + `, { + eval: true, + workerData: { sharedArrayBuffer } + }); + w.on('message', common.mustCall(() => { + assert.strictEqual(local.toString(), 'Hello world!'); + global.gc(); + w.terminate(); + })); + w.postMessage({}); + // This would be a race condition if the memory regions were overlapping + local.write('Hello '); +} diff --git a/test/js/node/test/parallel/test-zlib-deflate-constructors.js b/test/js/node/test/parallel/test-zlib-deflate-constructors.js index 6a5d410086..bf4b6d3374 100644 --- a/test/js/node/test/parallel/test-zlib-deflate-constructors.js +++ b/test/js/node/test/parallel/test-zlib-deflate-constructors.js @@ -19,7 +19,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.chunkSize" property must be of type number. ' + - 'Received "test"' + 'Received type string ("test")' } ); @@ -39,7 +39,7 @@ assert.throws( code: 'ERR_OUT_OF_RANGE', name: 'RangeError', message: 'The value of "options.chunkSize" is out of range. It must ' + - 'be >= 64. Received: 0' + 'be >= 64. Received 0' } ); @@ -53,7 +53,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.windowBits" property must be of type number. ' + - 'Received "test"' + 'Received type string ("test")' } ); @@ -94,7 +94,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.level" property must be of type number. ' + - 'Received "test"' + 'Received type string ("test")' } ); @@ -135,7 +135,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "level" argument must be of type number. ' + - 'Received "test"' + 'Received type string ("test")' } ); @@ -176,7 +176,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.memLevel" property must be of type number. ' + - 'Received "test"' + 'Received type string ("test")' } ); @@ -224,7 +224,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.strategy" property must be of type number. ' + - 'Received "test"' + 'Received type string ("test")' } ); @@ -265,7 +265,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "strategy" argument must be of type number. ' + - 'Received "test"' + 'Received type string ("test")' } ); @@ -306,4 +306,4 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', } -); \ No newline at end of file +); diff --git a/test/js/node/test/parallel/test-zlib-failed-init.js b/test/js/node/test/parallel/test-zlib-failed-init.js index d47b61de66..95f401a371 100644 --- a/test/js/node/test/parallel/test-zlib-failed-init.js +++ b/test/js/node/test/parallel/test-zlib-failed-init.js @@ -11,7 +11,7 @@ assert.throws( code: 'ERR_OUT_OF_RANGE', name: 'RangeError', message: 'The value of "options.chunkSize" is out of range. It must ' + - 'be >= 64. Received: 0' + 'be >= 64. Received 0' } ); @@ -43,4 +43,4 @@ assert.throws( { const stream = zlib.createGzip({ strategy: NaN }); assert.strictEqual(stream._strategy, zlib.constants.Z_DEFAULT_STRATEGY); -} \ No newline at end of file +} diff --git a/test/js/node/test/parallel/test-zlib-flush-flags.js b/test/js/node/test/parallel/test-zlib-flush-flags.js index 1cb552390c..f3392b7a41 100644 --- a/test/js/node/test/parallel/test-zlib-flush-flags.js +++ b/test/js/node/test/parallel/test-zlib-flush-flags.js @@ -11,7 +11,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.flush" property must be of type number. ' + - 'Received "foobar"' + 'Received type string ("foobar")' } ); @@ -33,7 +33,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "options.finishFlush" property must be of type number. ' + - 'Received "foobar"' + 'Received type string ("foobar")' } ); @@ -45,4 +45,4 @@ assert.throws( message: 'The value of "options.finishFlush" is out of range. It must ' + 'be >= 0 and <= 5. Received 10000' } -); \ No newline at end of file +); diff --git a/test/js/node/test/parallel/test-zlib-not-string-or-buffer.js b/test/js/node/test/parallel/test-zlib-not-string-or-buffer.js new file mode 100644 index 0000000000..35e969737f --- /dev/null +++ b/test/js/node/test/parallel/test-zlib-not-string-or-buffer.js @@ -0,0 +1,30 @@ +'use strict'; + +// Check the error condition testing for passing something other than a string +// or buffer. + +const common = require('../common'); +const assert = require('assert'); +const zlib = require('zlib'); + +[ + undefined, + null, + true, + false, + 0, + 1, + [1, 2, 3], + { foo: 'bar' }, +].forEach((input) => { + assert.throws( + () => zlib.deflateSync(input), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "buffer" argument must be of type string, ' + + 'Buffer, TypedArray, DataView, or ArrayBuffer.' + + common.invalidArgTypeHelper(input) + } + ); +}); diff --git a/test/js/node/util/bun-inspect.test.ts b/test/js/node/util/bun-inspect.test.ts index 115ad1c500..65de3b0ed4 100644 --- a/test/js/node/util/bun-inspect.test.ts +++ b/test/js/node/util/bun-inspect.test.ts @@ -3,13 +3,13 @@ import stripAnsi from "strip-ansi"; describe("Bun.inspect", () => { it("reports error instead of [native code]", () => { - expect( + expect(() => Bun.inspect({ [Symbol.for("nodejs.util.inspect.custom")]() { throw new Error("custom inspect"); }, }), - ).toBe("[custom formatter threw an exception]"); + ).toThrow("custom inspect"); }); it("supports colors: false", () => { diff --git a/test/js/node/util/custom-inspect.test.js b/test/js/node/util/custom-inspect.test.js index 040f0abb8d..bc8763b214 100644 --- a/test/js/node/util/custom-inspect.test.js +++ b/test/js/node/util/custom-inspect.test.js @@ -155,11 +155,6 @@ for (const [name, inspect] of process.versions.bun }, }; - if (Bun.inspect === inspect) { - // make sure this doesnt crash - expect(inspect(obj)).toBeString(); - } else { - expect(() => inspect(obj)).toThrow(); - } + expect(() => inspect(obj)).toThrow(); }); } diff --git a/test/js/node/util/test-util-types.test.js b/test/js/node/util/test-util-types.test.js index 031d18ca20..084da3bfac 100644 --- a/test/js/node/util/test-util-types.test.js +++ b/test/js/node/util/test-util-types.test.js @@ -47,6 +47,7 @@ for (const [value, _method] of [ [new DataView(new ArrayBuffer())], [new SharedArrayBuffer()], [new Proxy({}, {}), "isProxy"], + [new EventTarget()], ]) { const method = _method || `is${value.constructor.name}`; test(method, () => { From d8e644fc257c72b7268d40fd69be764c97dc0623 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Fri, 27 Dec 2024 12:58:21 -0500 Subject: [PATCH 101/125] fix(node/path): crash when joining long paths (#16019) --- src/bun.js/node/path.zig | 2 +- test/js/node/path/15704.test.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 test/js/node/path/15704.test.js diff --git a/src/bun.js/node/path.zig b/src/bun.js/node/path.zig index c0ff1d10be..3545f4418d 100644 --- a/src/bun.js/node/path.zig +++ b/src/bun.js/node/path.zig @@ -1237,7 +1237,7 @@ pub inline fn joinWindowsJS_T(comptime T: type, globalObject: *JSC.JSGlobalObjec pub fn joinJS_T(comptime T: type, globalObject: *JSC.JSGlobalObject, allocator: std.mem.Allocator, isWindows: bool, paths: []const []const T) JSC.JSValue { // Adding 8 bytes when Windows for the possible UNC root. var bufLen: usize = if (isWindows) 8 else 0; - for (paths) |path| bufLen += if (bufLen > 0 and path.len > 0) path.len + 1 else path.len; + for (paths) |path| bufLen += if (path.len > 0) path.len + 1 else path.len; bufLen = @max(bufLen, PATH_SIZE(T)); const buf = allocator.alloc(T, bufLen) catch bun.outOfMemory(); defer allocator.free(buf); diff --git a/test/js/node/path/15704.test.js b/test/js/node/path/15704.test.js new file mode 100644 index 0000000000..81c12fb9a7 --- /dev/null +++ b/test/js/node/path/15704.test.js @@ -0,0 +1,10 @@ +import path from "path"; +import assert from "assert"; + +test("too-long path names do not crash when joined", () => { + const length = 4096; + const tooLengthyFolderName = Array.from({ length }).fill("b").join(""); + assert.equal(path.join(tooLengthyFolderName), "b".repeat(length)); + assert.equal(path.win32.join(tooLengthyFolderName), "b".repeat(length)); + assert.equal(path.posix.join(tooLengthyFolderName), "b".repeat(length)); +}); From 7b06872abb9c865f11f9629abed6b67608b052e2 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 27 Dec 2024 14:07:41 -0800 Subject: [PATCH 102/125] Deflake fetch tests (#16000) --- .../bun/http/async-iterator-throws.fixture.js | 1 + test/js/bun/http/big-form-data.fixture.js | 1 + test/js/bun/http/body-leak-test-fixture.ts | 1 + .../http/readable-stream-throws.fixture.js | 2 +- test/js/bun/http/rejected-promise-fixture.js | 1 + test/js/bun/http/serve-body-leak.test.ts | 56 +++++++++---------- .../bun/websocket/websocket-server-fixture.js | 1 + .../js/web/fetch/fetch-leak-test-fixture-3.js | 11 +++- .../js/web/fetch/fetch-leak-test-fixture-4.js | 12 +++- test/js/web/fetch/fetch-leak.test.ts | 14 +++-- test/js/web/fetch/fetch.test.ts | 51 ++++++++++------- 11 files changed, 88 insertions(+), 63 deletions(-) diff --git a/test/js/bun/http/async-iterator-throws.fixture.js b/test/js/bun/http/async-iterator-throws.fixture.js index c35b68ecef..2227f9dccd 100644 --- a/test/js/bun/http/async-iterator-throws.fixture.js +++ b/test/js/bun/http/async-iterator-throws.fixture.js @@ -1,5 +1,6 @@ const server = Bun.serve({ port: 0, + idleTimeout: 0, async fetch(req) { return new Response( diff --git a/test/js/bun/http/big-form-data.fixture.js b/test/js/bun/http/big-form-data.fixture.js index b3ff882004..e91de65867 100644 --- a/test/js/bun/http/big-form-data.fixture.js +++ b/test/js/bun/http/big-form-data.fixture.js @@ -3,6 +3,7 @@ const content = Buffer.alloc(3 * 15360000, "Bun").toString(); const server = Bun.serve({ port: 0, + idleTimeout: 0, fetch: async req => { const data = await req.formData(); return new Response(data.get("name") === content ? "OK" : "NO"); diff --git a/test/js/bun/http/body-leak-test-fixture.ts b/test/js/bun/http/body-leak-test-fixture.ts index 1cc5a28298..5dbc7a1ea8 100644 --- a/test/js/bun/http/body-leak-test-fixture.ts +++ b/test/js/bun/http/body-leak-test-fixture.ts @@ -1,5 +1,6 @@ const server = Bun.serve({ port: 0, + idleTimeout: 0, async fetch(req: Request) { const url = req.url; if (url.endsWith("/report")) { diff --git a/test/js/bun/http/readable-stream-throws.fixture.js b/test/js/bun/http/readable-stream-throws.fixture.js index a1d8d4ec06..ff32f94507 100644 --- a/test/js/bun/http/readable-stream-throws.fixture.js +++ b/test/js/bun/http/readable-stream-throws.fixture.js @@ -1,6 +1,6 @@ const server = Bun.serve({ port: 0, - + idleTimeout: 0, error(err) { return new Response("Failed", { status: 555 }); }, diff --git a/test/js/bun/http/rejected-promise-fixture.js b/test/js/bun/http/rejected-promise-fixture.js index f63f774a2a..3b50761f1a 100644 --- a/test/js/bun/http/rejected-promise-fixture.js +++ b/test/js/bun/http/rejected-promise-fixture.js @@ -1,5 +1,6 @@ const server = Bun.serve({ hostname: "localhost", + idleTimeout: 0, async fetch() { throw new Error("Error"); }, diff --git a/test/js/bun/http/serve-body-leak.test.ts b/test/js/bun/http/serve-body-leak.test.ts index 40f260bea5..ed40ed810d 100644 --- a/test/js/bun/http/serve-body-leak.test.ts +++ b/test/js/bun/http/serve-body-leak.test.ts @@ -9,15 +9,9 @@ const totalCount = 10_000; const zeroCopyPayload = new Blob([payload]); const zeroCopyJSONPayload = new Blob([JSON.stringify({ bun: payload })]); -let url: URL; -let process: Subprocess<"ignore", "pipe", "inherit"> | null = null; -beforeEach(async () => { - if (process) { - process?.kill(); - } - - let defer = Promise.withResolvers(); - process = Bun.spawn([bunExe(), "--smol", join(import.meta.dirname, "body-leak-test-fixture.ts")], { +async function getURL() { + let defer = Promise.withResolvers(); + const process = Bun.spawn([bunExe(), "--smol", join(import.meta.dirname, "body-leak-test-fixture.ts")], { env: bunEnv, stdout: "inherit", stderr: "inherit", @@ -26,19 +20,17 @@ beforeEach(async () => { defer.resolve(message); }, }); - url = new URL(await defer.promise); + const url: URL = new URL(await defer.promise); process.unref(); - await warmup(); -}); -afterEach(() => { - process?.kill(); -}); + await warmup(url); + return { url, process }; +} -async function getMemoryUsage(): Promise { +async function getMemoryUsage(url: URL): Promise { return (await fetch(`${url.origin}/report`).then(res => res.json())) as number; } -async function warmup() { +async function warmup(url: URL) { var remaining = totalCount; while (remaining > 0) { @@ -54,17 +46,17 @@ async function warmup() { remaining -= batchSize; } // clean up memory before first test - await getMemoryUsage(); + await getMemoryUsage(url); } -async function callBuffering() { +async function callBuffering(url: URL) { const result = await fetch(`${url.origin}/buffering`, { method: "POST", body: zeroCopyPayload, }).then(res => res.text()); expect(result).toBe("Ok"); } -async function callJSONBuffering() { +async function callJSONBuffering(url: URL) { const result = await fetch(`${url.origin}/json-buffering`, { method: "POST", body: zeroCopyJSONPayload, @@ -72,35 +64,35 @@ async function callJSONBuffering() { expect(result).toBe("Ok"); } -async function callBufferingBodyGetter() { +async function callBufferingBodyGetter(url: URL) { const result = await fetch(`${url.origin}/buffering+body-getter`, { method: "POST", body: zeroCopyPayload, }).then(res => res.text()); expect(result).toBe("Ok"); } -async function callStreaming() { +async function callStreaming(url: URL) { const result = await fetch(`${url.origin}/streaming`, { method: "POST", body: zeroCopyPayload, }).then(res => res.text()); expect(result).toBe("Ok"); } -async function callIncompleteStreaming() { +async function callIncompleteStreaming(url: URL) { const result = await fetch(`${url.origin}/incomplete-streaming`, { method: "POST", body: zeroCopyPayload, }).then(res => res.text()); expect(result).toBe("Ok"); } -async function callStreamingEcho() { +async function callStreamingEcho(url: URL) { const result = await fetch(`${url.origin}/streaming-echo`, { method: "POST", body: zeroCopyPayload, }).then(res => res.text()); expect(result).toBe(payload); } -async function callIgnore() { +async function callIgnore(url: URL) { const result = await fetch(url, { method: "POST", body: zeroCopyPayload, @@ -108,8 +100,8 @@ async function callIgnore() { expect(result).toBe("Ok"); } -async function calculateMemoryLeak(fn: () => Promise) { - const start_memory = await getMemoryUsage(); +async function calculateMemoryLeak(fn: (url: URL) => Promise, url: URL) { + const start_memory = await getMemoryUsage(url); const memory_examples: Array = []; let peak_memory = start_memory; @@ -117,14 +109,14 @@ async function calculateMemoryLeak(fn: () => Promise) { while (remaining > 0) { const batch = new Array(batchSize); for (let j = 0; j < batchSize; j++) { - batch[j] = fn(); + batch[j] = fn(url); } await Promise.all(batch); remaining -= batchSize; // garbage collect and check memory usage every 1000 requests if (remaining > 0 && remaining % 1000 === 0) { - const report = await getMemoryUsage(); + const report = await getMemoryUsage(url); if (report > peak_memory) { peak_memory = report; } @@ -133,7 +125,7 @@ async function calculateMemoryLeak(fn: () => Promise) { } // wait for the last memory usage to be stable - const end_memory = await getMemoryUsage(); + const end_memory = await getMemoryUsage(url); if (end_memory > peak_memory) { peak_memory = end_memory; } @@ -160,7 +152,9 @@ for (const test_info of [ it.todoIf(skip)( testName, async () => { - const report = await calculateMemoryLeak(fn); + const { url, process } = await getURL(); + await using processHandle = process; + const report = await calculateMemoryLeak(fn, url); // peak memory is too high expect(report.peak_memory).not.toBeGreaterThan(report.start_memory * 2.5); // acceptable memory leak diff --git a/test/js/bun/websocket/websocket-server-fixture.js b/test/js/bun/websocket/websocket-server-fixture.js index 8e140b4b1f..23d5bb55ed 100644 --- a/test/js/bun/websocket/websocket-server-fixture.js +++ b/test/js/bun/websocket/websocket-server-fixture.js @@ -9,6 +9,7 @@ let pending = []; using server = Bun.serve({ port: 0, + idleTimeout: 0, websocket: { open(ws) { globalThis.sockets ??= []; diff --git a/test/js/web/fetch/fetch-leak-test-fixture-3.js b/test/js/web/fetch/fetch-leak-test-fixture-3.js index 3e75027ebf..33796c1667 100644 --- a/test/js/web/fetch/fetch-leak-test-fixture-3.js +++ b/test/js/web/fetch/fetch-leak-test-fixture-3.js @@ -1,8 +1,15 @@ -const payload = Buffer.alloc(64 * 64 * 1024, "X"); +// Reduce memory pressure by not cloning the buffer each Response. +const payload = new Blob([Buffer.alloc(64 * 64 * 1024, "X")]); + const server = Bun.serve({ port: 0, + idleTimeout: 0, async fetch(req) { return new Response(payload); }, }); -console.log(server.url.href); +if (process.send) { + process.send(server.url.href); +} else { + console.log(server.url.href); +} diff --git a/test/js/web/fetch/fetch-leak-test-fixture-4.js b/test/js/web/fetch/fetch-leak-test-fixture-4.js index 73c8ccd5d6..c25971c462 100644 --- a/test/js/web/fetch/fetch-leak-test-fixture-4.js +++ b/test/js/web/fetch/fetch-leak-test-fixture-4.js @@ -23,8 +23,16 @@ try { Bun.gc(true); await Bun.sleep(10); const stats = getHeapStats(); - expect(stats.Response || 0).toBeLessThanOrEqual(threshold); - expect(stats.Promise || 0).toBeLessThanOrEqual(threshold); + let { Response, Promise } = stats; + Response ||= 0; + Promise ||= 0; + console.log({ + rss: ((process.memoryUsage.rss() / 1024 / 1024) | 0) + " MB", + Response, + Promise, + }); + expect(Response).toBeLessThanOrEqual(threshold); + expect(Promise).toBeLessThanOrEqual(threshold); } } process.exit(0); diff --git a/test/js/web/fetch/fetch-leak.test.ts b/test/js/web/fetch/fetch-leak.test.ts index bf90582a79..b3b288b3ab 100644 --- a/test/js/web/fetch/fetch-leak.test.ts +++ b/test/js/web/fetch/fetch-leak.test.ts @@ -10,7 +10,7 @@ describe("fetch doesn't leak", () => { var count = 0; using server = Bun.serve({ port: 0, - + idleTimeout: 0, fetch(req) { count++; return new Response(body); @@ -20,7 +20,7 @@ describe("fetch doesn't leak", () => { const proc = Bun.spawn({ env: { ...bunEnv, - SERVER: `http://${server.hostname}:${server.port}`, + SERVER: server.url.href, COUNT: "200", }, stderr: "inherit", @@ -49,6 +49,7 @@ describe("fetch doesn't leak", () => { const serveOptions = { port: 0, + idleTimeout: 0, fetch(req) { return new Response(body, { headers }); }, @@ -62,8 +63,8 @@ describe("fetch doesn't leak", () => { const env = { ...bunEnv, - SERVER: `${tls ? "https" : "http"}://${server.hostname}:${server.port}`, - BUN_JSC_forceRAMSize: (1024 * 1024 * 64).toString("10"), + SERVER: server.url.href, + BUN_JSC_forceRAMSize: (1024 * 1024 * 64).toString(10), NAME: name, }; @@ -105,6 +106,7 @@ describe.each(["FormData", "Blob", "Buffer", "String", "URLSearchParams", "strea async () => { using server = Bun.serve({ port: 0, + idleTimeout: 0, fetch(req) { return new Response(); }, @@ -151,7 +153,7 @@ test("do not leak", async () => { let url; let isDone = false; - server.listen(0, function attack() { + server.listen(0, "127.0.0.1", function attack() { if (isDone) { return; } @@ -165,7 +167,7 @@ test("do not leak", async () => { let prev = Infinity; let count = 0; - const interval = setInterval(() => { + var interval = setInterval(() => { isDone = true; gc(); const next = process.memoryUsage().heapUsed; diff --git a/test/js/web/fetch/fetch.test.ts b/test/js/web/fetch/fetch.test.ts index 02ff359eea..6c67d63859 100644 --- a/test/js/web/fetch/fetch.test.ts +++ b/test/js/web/fetch/fetch.test.ts @@ -17,6 +17,7 @@ const fetchFixture4 = join(import.meta.dir, "fetch-leak-test-fixture-4.js"); let server: Server; function startServer({ fetch, ...options }: ServeOptions) { server = serve({ + idleTimeout: 0, ...options, fetch, port: 0, @@ -1314,9 +1315,16 @@ describe("Response", () => { method: "POST", body: await Bun.file(import.meta.dir + "/fixtures/file.txt").arrayBuffer(), }); - var input = await response.arrayBuffer(); + const input = await response.bytes(); var output = await Bun.file(import.meta.dir + "/fixtures/file.txt").stream(); - expect(new Uint8Array(input)).toEqual((await output.getReader().read()).value); + let chunks: Uint8Array[] = []; + const reader = output.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done) break; + chunks.push(value); + } + expect(input).toEqual(Buffer.concat(chunks)); }); }); @@ -2018,35 +2026,31 @@ describe("http/1.1 response body length", () => { }); describe("fetch Response life cycle", () => { it("should not keep Response alive if not consumed", async () => { - const serverProcess = Bun.spawn({ + let deferred = Promise.withResolvers(); + + await using serverProcess = Bun.spawn({ cmd: [bunExe(), "--smol", fetchFixture3], stderr: "inherit", - stdout: "pipe", - stdin: "ignore", + stdout: "inherit", + stdin: "inherit", env: bunEnv, + ipc(message) { + deferred.resolve(message); + }, }); - async function getServerUrl() { - const reader = serverProcess.stdout.getReader(); - const { done, value } = await reader.read(); - return new TextDecoder().decode(value); - } - const serverUrl = await getServerUrl(); - const clientProcess = Bun.spawn({ + const serverUrl = await deferred.promise; + await using clientProcess = Bun.spawn({ cmd: [bunExe(), "--smol", fetchFixture4, serverUrl], stderr: "inherit", - stdout: "pipe", - stdin: "ignore", + stdout: "inherit", + stdin: "inherit", env: bunEnv, }); - try { - expect(await clientProcess.exited).toBe(0); - } finally { - serverProcess.kill(); - } + expect(await clientProcess.exited).toBe(0); }); it("should allow to get promise result after response is GC'd", async () => { - const server = Bun.serve({ + using server = Bun.serve({ port: 0, async fetch(request: Request) { return new Response( @@ -2235,6 +2239,7 @@ describe("fetch should allow duplex", () => { it("should work in redirects .manual when using duplex", async () => { using server = Bun.serve({ port: 0, + idleTimeout: 0, async fetch(req) { if (req.url.indexOf("/redirect") === -1) { return Response.redirect("/"); @@ -2298,7 +2303,11 @@ it("should allow to follow redirect if connection is closed, abort should work e await once(server.listen(0), "listening"); try { - const response = await fetch(`http://localhost:${(server.address() as AddressInfo).port}/redirect`, { + let { address, port } = server.address() as AddressInfo; + if (address === "::") { + address = "[::]"; + } + const response = await fetch(`http://${address}:${port}/redirect`, { signal: AbortSignal.timeout(150), }); if (type === "delay") { From dd243a06a5400853c6aa89861a48b3d3a70b5c93 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 28 Dec 2024 01:31:30 -0800 Subject: [PATCH 103/125] Log slow lifecycle scripts (#16027) --- src/bun.js/event_loop.zig | 7 +++ src/install/install.zig | 68 ++++++++++++++++++++----- src/install/lifecycle_script_runner.zig | 31 +++++++++++ 3 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 03e24fe55b..1b4c3a1b78 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -2051,6 +2051,13 @@ pub const AnyEventLoop = union(enum) { pub const Task = AnyTaskWithExtraContext; + pub fn iterationNumber(this: *const AnyEventLoop) u64 { + return switch (this.*) { + .js => this.js.usocketsLoop().iterationNumber(), + .mini => this.mini.loop.iterationNumber(), + }; + } + pub fn wakeup(this: *AnyEventLoop) void { this.loop().wakeup(); } diff --git a/src/install/install.zig b/src/install/install.zig index 5ba0da5b3a..07bc1a8955 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -2757,6 +2757,44 @@ pub const PackageManager = struct { patched_dependencies_to_remove: std.ArrayHashMapUnmanaged(PackageNameAndVersionHash, void, ArrayIdentityContext.U64, false) = .{}, + active_lifecycle_scripts: LifecycleScriptSubprocess.List, + last_reported_slow_lifecycle_script_at: u64 = 0, + cached_tick_for_slow_lifecycle_script_logging: u64 = 0, + + pub fn reportSlowLifecycleScripts(this: *PackageManager, log_level: Options.LogLevel) void { + if (log_level == .silent) return; + if (bun.getRuntimeFeatureFlag("BUN_DISABLE_SLOW_LIFECYCLE_SCRIPT_LOGGING")) { + return; + } + + if (this.active_lifecycle_scripts.peek()) |active_lifecycle_script_running_for_the_longest_amount_of_time| { + if (this.cached_tick_for_slow_lifecycle_script_logging == this.event_loop.iterationNumber()) { + return; + } + this.cached_tick_for_slow_lifecycle_script_logging = this.event_loop.iterationNumber(); + const current_time = bun.timespec.now().ns(); + const time_running = current_time -| active_lifecycle_script_running_for_the_longest_amount_of_time.started_at; + const interval: u64 = if (log_level.isVerbose()) std.time.ns_per_s * 5 else std.time.ns_per_s * 30; + if (time_running > interval and current_time -| this.last_reported_slow_lifecycle_script_at > interval) { + this.last_reported_slow_lifecycle_script_at = current_time; + const package_name = active_lifecycle_script_running_for_the_longest_amount_of_time.package_name; + + if (!(package_name.len > 1 and package_name[package_name.len - 1] == 's')) { + Output.warn("{s}'s postinstall has costed you {}\n", .{ + package_name, + bun.fmt.fmtDurationOneDecimal(time_running), + }); + } else { + Output.warn("{s}' postinstall has costed you {}\n", .{ + package_name, + bun.fmt.fmtDurationOneDecimal(time_running), + }); + } + Output.flush(); + } + } + } + pub const PackageUpdateInfo = struct { original_version_literal: string, is_alias: bool, @@ -3116,6 +3154,7 @@ pub const PackageManager = struct { } fn hasNoMorePendingLifecycleScripts(this: *PackageManager) bool { + this.reportSlowLifecycleScripts(this.options.log_level); return this.pending_lifecycle_script_tasks.load(.monotonic) == 0; } @@ -3129,6 +3168,7 @@ pub const PackageManager = struct { } pub fn sleep(this: *PackageManager) void { + this.reportSlowLifecycleScripts(this.options.log_level); Output.flush(); this.event_loop.tick(this, hasNoMorePendingLifecycleScripts); } @@ -8789,6 +8829,9 @@ pub const PackageManager = struct { // var node = progress.start(name: []const u8, estimated_total_items: usize) manager.* = PackageManager{ .options = options, + .active_lifecycle_scripts = .{ + .context = manager, + }, .network_task_fifo = NetworkQueue.init(), .patch_task_fifo = PatchTaskFifo.init(), .allocator = ctx.allocator, @@ -8955,6 +8998,9 @@ pub const PackageManager = struct { .options = .{ .max_concurrent_lifecycle_scripts = cli.concurrent_scripts orelse cpu_count * 2, }, + .active_lifecycle_scripts = .{ + .context = manager, + }, .network_task_fifo = NetworkQueue.init(), .allocator = allocator, .log = log, @@ -12574,10 +12620,6 @@ pub const PackageManager = struct { for (this.pending_lifecycle_scripts.items) |entry| { const package_name = entry.list.package_name; while (LifecycleScriptSubprocess.alive_count.load(.monotonic) >= this.manager.options.max_concurrent_lifecycle_scripts) { - if (PackageManager.verbose_install) { - if (PackageManager.hasEnoughTimePassedBetweenWaitingMessages()) Output.prettyErrorln("[PackageManager] waiting for {d} scripts\n", .{LifecycleScriptSubprocess.alive_count.load(.monotonic)}); - } - this.manager.sleep(); } @@ -12609,9 +12651,7 @@ pub const PackageManager = struct { } while (this.manager.pending_lifecycle_script_tasks.load(.monotonic) > 0) { - if (PackageManager.verbose_install) { - if (PackageManager.hasEnoughTimePassedBetweenWaitingMessages()) Output.prettyErrorln("[PackageManager] waiting for {d} scripts\n", .{LifecycleScriptSubprocess.alive_count.load(.monotonic)}); - } + this.manager.reportSlowLifecycleScripts(log_level); if (comptime log_level.showProgress()) { if (this.manager.scripts_node) |scripts_node| { @@ -14003,8 +14043,8 @@ pub const PackageManager = struct { ); if (!installer.options.do.install_packages) return error.InstallFailed; } - this.tickLifecycleScripts(); + this.reportSlowLifecycleScripts(log_level); } for (remaining) |dependency_id| { @@ -14027,6 +14067,7 @@ pub const PackageManager = struct { if (!installer.options.do.install_packages) return error.InstallFailed; this.tickLifecycleScripts(); + this.reportSlowLifecycleScripts(log_level); } while (this.pendingTaskCount() > 0 and installer.options.do.install_packages) { @@ -14056,6 +14097,8 @@ pub const PackageManager = struct { return true; } + closure.manager.reportSlowLifecycleScripts(log_level); + if (PackageManager.verbose_install and closure.manager.pendingTaskCount() > 0) { const pending_task_count = closure.manager.pendingTaskCount(); if (pending_task_count > 0 and PackageManager.hasEnoughTimePassedBetweenWaitingMessages()) { @@ -14082,6 +14125,7 @@ pub const PackageManager = struct { } } else { this.tickLifecycleScripts(); + this.reportSlowLifecycleScripts(log_level); } for (installer.trees) |tree| { @@ -14107,9 +14151,7 @@ pub const PackageManager = struct { installer.completeRemainingScripts(log_level); while (this.pending_lifecycle_script_tasks.load(.monotonic) > 0) { - if (PackageManager.verbose_install) { - if (PackageManager.hasEnoughTimePassedBetweenWaitingMessages()) Output.prettyErrorln("[PackageManager] waiting for {d} scripts\n", .{this.pending_lifecycle_script_tasks.load(.monotonic)}); - } + this.reportSlowLifecycleScripts(log_level); this.sleep(); } @@ -14972,9 +15014,7 @@ pub const PackageManager = struct { try manager.spawnPackageLifecycleScripts(ctx, scripts, optional, log_level, output_in_foreground); while (manager.pending_lifecycle_script_tasks.load(.monotonic) > 0) { - if (PackageManager.verbose_install) { - if (PackageManager.hasEnoughTimePassedBetweenWaitingMessages()) Output.prettyErrorln("[PackageManager] waiting for {d} scripts\n", .{manager.pending_lifecycle_script_tasks.load(.monotonic)}); - } + manager.reportSlowLifecycleScripts(log_level); manager.sleep(); } diff --git a/src/install/lifecycle_script_runner.zig b/src/install/lifecycle_script_runner.zig index c2b2a089e5..6b054644a0 100644 --- a/src/install/lifecycle_script_runner.zig +++ b/src/install/lifecycle_script_runner.zig @@ -35,6 +35,15 @@ pub const LifecycleScriptSubprocess = struct { foreground: bool = false, optional: bool = false, + started_at: u64 = 0, + + heap: bun.io.heap.IntrusiveField(LifecycleScriptSubprocess) = .{}, + + pub const List = bun.io.heap.Intrusive(LifecycleScriptSubprocess, *PackageManager, sortByStartedAt); + + fn sortByStartedAt(_: *PackageManager, a: *LifecycleScriptSubprocess, b: *LifecycleScriptSubprocess) bool { + return a.started_at < b.started_at; + } pub usingnamespace bun.New(@This()); @@ -92,6 +101,12 @@ pub const LifecycleScriptSubprocess = struct { // This is only used on the main thread. var cwd_z_buf: bun.PathBuffer = undefined; + fn ensureNotInHeap(this: *LifecycleScriptSubprocess) void { + if (this.heap.child != null or this.heap.next != null or this.heap.prev != null or this.manager.active_lifecycle_scripts.root == this) { + this.manager.active_lifecycle_scripts.remove(this); + } + } + pub fn spawnNextScript(this: *LifecycleScriptSubprocess, next_script_index: u8) !void { bun.Analytics.Features.lifecycle_scripts += 1; @@ -105,6 +120,8 @@ pub const LifecycleScriptSubprocess = struct { this.has_incremented_alive_count = false; _ = alive_count.fetchSub(1, .monotonic); } + + this.ensureNotInHeap(); } const manager = this.manager; @@ -114,6 +131,8 @@ pub const LifecycleScriptSubprocess = struct { this.stdout.setParent(this); this.stderr.setParent(this); + this.ensureNotInHeap(); + this.current_script_index = next_script_index; this.has_called_process_exit = false; @@ -197,6 +216,8 @@ pub const LifecycleScriptSubprocess = struct { }; this.remaining_fds = 0; + this.started_at = bun.timespec.now().ns(); + this.manager.active_lifecycle_scripts.insert(this); var spawned = try (try bun.spawn.spawnProcess(&spawn_options, @ptrCast(&argv), this.envp)).unwrap(); if (comptime Environment.isPosix) { @@ -299,6 +320,8 @@ pub const LifecycleScriptSubprocess = struct { _ = alive_count.fetchSub(1, .monotonic); } + this.ensureNotInHeap(); + switch (status) { .exited => |exit| { const maybe_duration = if (this.timer) |*t| t.read() else null; @@ -355,8 +378,15 @@ pub const LifecycleScriptSubprocess = struct { } } + if (PackageManager.verbose_install) { + Output.prettyErrorln("[Scripts] Finished scripts for {}", .{ + bun.fmt.quote(this.package_name), + }); + } + // the last script finished _ = this.manager.pending_lifecycle_script_tasks.fetchSub(1, .monotonic); + this.deinit(); }, .signaled => |signal| { @@ -426,6 +456,7 @@ pub const LifecycleScriptSubprocess = struct { pub fn deinit(this: *LifecycleScriptSubprocess) void { this.resetPolls(); + this.ensureNotInHeap(); if (!this.manager.options.log_level.isVerbose()) { this.stdout.deinit(); From ed0980cf94d2ac4a159afc77e04daf5935ba97de Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 28 Dec 2024 01:32:32 -0800 Subject: [PATCH 104/125] Make creating errors slightly faster (#16023) --- cmake/tools/SetupWebKit.cmake | 2 +- src/bun.js/bindings/BunCommonStrings.cpp | 8 ++++++++ src/bun.js/bindings/BunCommonStrings.h | 10 +++++++++- src/bun.js/bindings/BunProcess.cpp | 16 ++++++++++++---- src/bun.js/bindings/bindings.cpp | 22 ++++++++++++---------- src/bun.js/modules/BunJSCModule.h | 22 +++++++++++++++++++++- test/js/node/process/process.test.js | 7 +++++++ 7 files changed, 70 insertions(+), 17 deletions(-) diff --git a/cmake/tools/SetupWebKit.cmake b/cmake/tools/SetupWebKit.cmake index b876c54da5..2799048375 100644 --- a/cmake/tools/SetupWebKit.cmake +++ b/cmake/tools/SetupWebKit.cmake @@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use") option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading") if(NOT WEBKIT_VERSION) - set(WEBKIT_VERSION 3845bf370ff4e9a5c0b96036255142c7904be963) + set(WEBKIT_VERSION 00e2b186fd25e79cea4cb4d63d9fd388192327f6) endif() if(WEBKIT_LOCAL) diff --git a/src/bun.js/bindings/BunCommonStrings.cpp b/src/bun.js/bindings/BunCommonStrings.cpp index c0327ca6e7..6cbeefaf53 100644 --- a/src/bun.js/bindings/BunCommonStrings.cpp +++ b/src/bun.js/bindings/BunCommonStrings.cpp @@ -20,17 +20,25 @@ using namespace JSC; init.set(jsOwnedString(init.vm, name.string())); \ }); +#define BUN_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION_NOT_BUILTIN_NAMES(jsName) \ + this->m_commonString_##jsName.initLater( \ + [](const JSC::LazyProperty::Initializer& init) { \ + init.set(jsOwnedString(init.vm, #jsName##_s)); \ + }); + #define BUN_COMMON_STRINGS_LAZY_PROPERTY_VISITOR(name) this->m_commonString_##name.visit(visitor); void CommonStrings::initialize() { BUN_COMMON_STRINGS_EACH_NAME(BUN_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION) + BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION_NOT_BUILTIN_NAMES) } template void CommonStrings::visit(Visitor& visitor) { BUN_COMMON_STRINGS_EACH_NAME(BUN_COMMON_STRINGS_LAZY_PROPERTY_VISITOR) + BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_LAZY_PROPERTY_VISITOR) } template void CommonStrings::visit(JSC::AbstractSlotVisitor&); diff --git a/src/bun.js/bindings/BunCommonStrings.h b/src/bun.js/bindings/BunCommonStrings.h index 667ee5b21b..0abd69c1db 100644 --- a/src/bun.js/bindings/BunCommonStrings.h +++ b/src/bun.js/bindings/BunCommonStrings.h @@ -1,10 +1,17 @@ #pragma once // clang-format off +// The items in this list must also be present in BunBuiltinNames.h +// If we use it as an identifier name in hot code, we should put it in this list. #define BUN_COMMON_STRINGS_EACH_NAME(macro) \ macro(require) \ macro(resolve) \ macro(mockedFunction) + +// These ones don't need to be in BunBuiltinNames.h +// If we don't use it as an identifier name, but we want to avoid allocating the string frequently, put it in this list. +#define BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(macro) \ + macro(SystemError) // clang-format on #define BUN_COMMON_STRINGS_ACCESSOR_DEFINITION(name) \ @@ -21,7 +28,7 @@ namespace Bun { class CommonStrings { public: BUN_COMMON_STRINGS_EACH_NAME(BUN_COMMON_STRINGS_ACCESSOR_DEFINITION) - + BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_ACCESSOR_DEFINITION) void initialize(); template @@ -29,6 +36,7 @@ public: private: BUN_COMMON_STRINGS_EACH_NAME(BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION) + BUN_COMMON_STRINGS_EACH_NAME_NOT_BUILTIN_NAMES(BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION) }; } // namespace Bun diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 269e860d07..d18b1b4fc3 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -2565,10 +2565,18 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionMemoryUsage, result->putDirectOffset(vm, 3, JSC::jsDoubleNumber(vm.heap.extraMemorySize() + vm.heap.externalMemorySize())); - // We report 0 for this because m_arrayBuffers in JSC::Heap is private and we need to add a binding - // If we use objectTypeCounts(), it's hideously slow because it loops through every single object in the heap - // TODO: add a binding for m_arrayBuffers, registerWrapper() in TypedArrayController doesn't work - result->putDirectOffset(vm, 4, JSC::jsNumber(0)); + // JSC won't count this number until vm.heap.addReference() is called. + // That will only happen in cases like: + // - new ArrayBuffer() + // - new Uint8Array(42).buffer + // - fs.readFile(path, "utf-8") (sometimes) + // - ... + // + // But it won't happen in cases like: + // - new Uint8Array(42) + // - Buffer.alloc(42) + // - new Uint8Array(42).slice() + result->putDirectOffset(vm, 4, JSC::jsDoubleNumber(vm.heap.arrayBufferSize())); RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(result)); } diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 45fb786707..7840f0acf0 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -1,6 +1,8 @@ + #include "root.h" +#include "JavaScriptCore/ErrorType.h" #include "JavaScriptCore/CatchScope.h" #include "JavaScriptCore/Exception.h" #include "ErrorCode+List.h" @@ -1941,45 +1943,45 @@ JSC__JSValue SystemError__toErrorInstance(const SystemError* arg0, message = Bun::toJS(globalObject, err.message); } + auto& names = WebCore::builtinNames(vm); + JSC::JSValue options = JSC::jsUndefined(); - JSC::JSObject* result - = JSC::ErrorInstance::create(globalObject, JSC::ErrorInstance::createStructure(vm, globalObject, globalObject->errorPrototype()), message, options); - - auto clientData = WebCore::clientData(vm); + JSC::JSObject* result = JSC::ErrorInstance::create(globalObject, globalObject->errorStructureWithErrorType(), message, options); if (err.code.tag != BunStringTag::Empty) { JSC::JSValue code = Bun::toJS(globalObject, err.code); - result->putDirect(vm, clientData->builtinNames().codePublicName(), code, + result->putDirect(vm, names.codePublicName(), code, JSC::PropertyAttribute::DontDelete | 0); result->putDirect(vm, vm.propertyNames->name, code, JSC::PropertyAttribute::DontEnum | 0); } else { + auto* domGlobalObject = defaultGlobalObject(globalObject); result->putDirect( vm, vm.propertyNames->name, - JSC::JSValue(jsString(vm, String("SystemError"_s))), + JSC::JSValue(domGlobalObject->commonStrings().SystemErrorString(domGlobalObject)), JSC::PropertyAttribute::DontEnum | 0); } if (err.path.tag != BunStringTag::Empty) { JSC::JSValue path = Bun::toJS(globalObject, err.path); - result->putDirect(vm, clientData->builtinNames().pathPublicName(), path, + result->putDirect(vm, names.pathPublicName(), path, JSC::PropertyAttribute::DontDelete | 0); } if (err.fd != -1) { JSC::JSValue fd = JSC::JSValue(jsNumber(err.fd)); - result->putDirect(vm, JSC::Identifier::fromString(vm, "fd"_s), fd, + result->putDirect(vm, names.fdPublicName(), fd, JSC::PropertyAttribute::DontDelete | 0); } if (err.syscall.tag != BunStringTag::Empty) { JSC::JSValue syscall = Bun::toJS(globalObject, err.syscall); - result->putDirect(vm, clientData->builtinNames().syscallPublicName(), syscall, + result->putDirect(vm, names.syscallPublicName(), syscall, JSC::PropertyAttribute::DontDelete | 0); } - result->putDirect(vm, clientData->builtinNames().errnoPublicName(), JSC::JSValue(err.errno_), + result->putDirect(vm, names.errnoPublicName(), JSC::JSValue(err.errno_), JSC::PropertyAttribute::DontDelete | 0); RETURN_IF_EXCEPTION(scope, {}); diff --git a/src/bun.js/modules/BunJSCModule.h b/src/bun.js/modules/BunJSCModule.h index 557cdc2f6f..562d795cfe 100644 --- a/src/bun.js/modules/BunJSCModule.h +++ b/src/bun.js/modules/BunJSCModule.h @@ -903,6 +903,24 @@ JSC_DEFINE_HOST_FUNCTION(functionEstimateDirectMemoryUsageOf, (JSGlobalObject * return JSValue::encode(jsNumber(0)); } +#if USE(BMALLOC_MEMORY_FOOTPRINT_API) + +#include + +JSC_DEFINE_HOST_FUNCTION(functionPercentAvailableMemoryInUse, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + return JSValue::encode(jsDoubleNumber(bmalloc::api::percentAvailableMemoryInUse())); +} + +#else + +JSC_DEFINE_HOST_FUNCTION(functionPercentAvailableMemoryInUse, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + return JSValue::encode(jsNull()); +} + +#endif + // clang-format off /* Source for BunJSCModuleTable.lut.h @begin BunJSCModuleTable @@ -937,13 +955,14 @@ JSC_DEFINE_HOST_FUNCTION(functionEstimateDirectMemoryUsageOf, (JSGlobalObject * serialize functionSerialize Function 0 deserialize functionDeserialize Function 0 estimateShallowMemoryUsageOf functionEstimateDirectMemoryUsageOf Function 1 + percentAvailableMemoryInUse functionPercentAvailableMemoryInUse Function 0 @end */ namespace Zig { DEFINE_NATIVE_MODULE(BunJSC) { - INIT_NATIVE_MODULE(35); + INIT_NATIVE_MODULE(36); putNativeFn(Identifier::fromString(vm, "callerSourceOrigin"_s), functionCallerSourceOrigin); putNativeFn(Identifier::fromString(vm, "jscDescribe"_s), functionDescribe); @@ -977,6 +996,7 @@ DEFINE_NATIVE_MODULE(BunJSC) putNativeFn(Identifier::fromString(vm, "serialize"_s), functionSerialize); putNativeFn(Identifier::fromString(vm, "deserialize"_s), functionDeserialize); putNativeFn(Identifier::fromString(vm, "estimateShallowMemoryUsageOf"_s), functionEstimateDirectMemoryUsageOf); + putNativeFn(Identifier::fromString(vm, "percentAvailableMemoryInUse"_s), functionPercentAvailableMemoryInUse); // Deprecated putNativeFn(Identifier::fromString(vm, "describe"_s), functionDescribe); diff --git a/test/js/node/process/process.test.js b/test/js/node/process/process.test.js index 811abfb4bb..7055550847 100644 --- a/test/js/node/process/process.test.js +++ b/test/js/node/process/process.test.js @@ -1056,3 +1056,10 @@ describe("process.exitCode", () => { it("process._exiting", () => { expect(process._exiting).toBe(false); }); + +it("process.memoryUsage.arrayBuffers", () => { + const initial = process.memoryUsage().arrayBuffers; + const array = new ArrayBuffer(1024 * 1024 * 16); + array.buffer; + expect(process.memoryUsage().arrayBuffers).toBeGreaterThanOrEqual(initial + 16 * 1024 * 1024); +}); From fe4176e4032d5945637742bbe61d14d036ded7d7 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Sat, 28 Dec 2024 17:46:22 -0800 Subject: [PATCH 105/125] feat(s3) s3 client (#15740) Co-authored-by: Jarred Sumner Co-authored-by: cirospaciari --- misctools/fetch.zig | 234 --- packages/bun-types/bun.d.ts | 218 ++- packages/bun-types/globals.d.ts | 6 + src/baby_list.zig | 2 + src/bun.js/Strong.zig | 2 +- src/bun.js/api/BunObject.zig | 5 + src/bun.js/bindings/BunObject+exports.h | 2 + src/bun.js/bindings/BunObject.cpp | 2 + src/bun.js/bindings/ErrorCode.ts | 7 + src/bun.js/bindings/JSS3File.cpp | 125 ++ src/bun.js/bindings/JSS3File.h | 7 + src/bun.js/bindings/ZigGlobalObject.cpp | 54 + src/bun.js/bindings/ZigGlobalObject.h | 10 +- src/bun.js/bindings/bindings.cpp | 34 + src/bun.js/bindings/bindings.zig | 19 + src/bun.js/bindings/headers.h | 7 + src/bun.js/event_loop.zig | 15 + src/bun.js/rare_data.zig | 53 + src/bun.js/webcore/blob.zig | 1481 ++++++++++++++- src/bun.js/webcore/blob/WriteFile.zig | 2 +- src/bun.js/webcore/body.zig | 4 +- src/bun.js/webcore/response.classes.ts | 10 + src/bun.js/webcore/response.zig | 314 +++- src/bun.js/webcore/streams.zig | 160 +- src/cli/create_command.zig | 8 +- src/cli/upgrade_command.zig | 4 +- src/compile_target.zig | 2 +- src/env_loader.zig | 62 +- src/http.zig | 10 +- src/install/install.zig | 2 +- src/s3.zig | 2182 ++++++++++++++++++++++ src/url.zig | 10 + test/js/bun/s3/bun-write-leak-fixture.js | 31 + test/js/bun/s3/s3-stream-leak-fixture.js | 40 + test/js/bun/s3/s3-text-leak-fixture.js | 35 + test/js/bun/s3/s3-write-leak-fixture.js | 31 + test/js/bun/s3/s3-writer-leak-fixture.js | 39 + test/js/bun/s3/s3.leak.test.ts | 172 ++ test/js/bun/s3/s3.test.ts | 617 ++++++ 39 files changed, 5638 insertions(+), 380 deletions(-) delete mode 100644 misctools/fetch.zig create mode 100644 src/bun.js/bindings/JSS3File.cpp create mode 100644 src/bun.js/bindings/JSS3File.h create mode 100644 src/s3.zig create mode 100644 test/js/bun/s3/bun-write-leak-fixture.js create mode 100644 test/js/bun/s3/s3-stream-leak-fixture.js create mode 100644 test/js/bun/s3/s3-text-leak-fixture.js create mode 100644 test/js/bun/s3/s3-write-leak-fixture.js create mode 100644 test/js/bun/s3/s3-writer-leak-fixture.js create mode 100644 test/js/bun/s3/s3.leak.test.ts create mode 100644 test/js/bun/s3/s3.test.ts diff --git a/misctools/fetch.zig b/misctools/fetch.zig deleted file mode 100644 index 5d0b9f1e52..0000000000 --- a/misctools/fetch.zig +++ /dev/null @@ -1,234 +0,0 @@ -const std = @import("std"); -const bun = @import("root").bun; -const string = bun.string; -const Output = bun.Output; -const Global = bun.Global; -const Environment = bun.Environment; -const strings = bun.strings; -const MutableString = bun.MutableString; -const stringZ = bun.stringZ; -const default_allocator = bun.default_allocator; -const C = bun.C; -pub usingnamespace @import("root").bun; - -const clap = bun.clap; - -const URL = @import("../src/url.zig").URL; -const Headers = bun.http.Headers; -const Method = @import("../src/http/method.zig").Method; -const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType; -const HeadersTuple = ColonListType(string, noop_resolver); -const path_handler = @import("../src/resolver/resolve_path.zig"); -const HTTPThread = bun.http.HTTPThread; -const HTTP = bun.http; -fn noop_resolver(in: string) !string { - return in; -} - -const VERSION = "0.0.0"; - -const params = [_]clap.Param(clap.Help){ - clap.parseParam("-v, --verbose Show headers & status code") catch unreachable, - clap.parseParam("-H, --header ... Add a header") catch unreachable, - clap.parseParam("-r, --max-redirects Maximum number of redirects to follow (default: 128)") catch unreachable, - clap.parseParam("-b, --body HTTP request body as a string") catch unreachable, - clap.parseParam("-f, --file File path to load as body") catch unreachable, - clap.parseParam("-q, --quiet Quiet mode") catch unreachable, - clap.parseParam("--no-gzip Disable gzip") catch unreachable, - clap.parseParam("--no-deflate Disable deflate") catch unreachable, - clap.parseParam("--no-compression Disable gzip & deflate") catch unreachable, - clap.parseParam("--version Print the version and exit") catch unreachable, - clap.parseParam("--turbo Skip sending TLS shutdown signals") catch unreachable, - clap.parseParam("... ") catch unreachable, -}; - -const MethodNames = std.ComptimeStringMap(Method, .{ - .{ "GET", Method.GET }, - .{ "get", Method.GET }, - - .{ "POST", Method.POST }, - .{ "post", Method.POST }, - - .{ "PUT", Method.PUT }, - .{ "put", Method.PUT }, - - .{ "PATCH", Method.PATCH }, - .{ "patch", Method.PATCH }, - - .{ "OPTIONS", Method.OPTIONS }, - .{ "options", Method.OPTIONS }, - - .{ "HEAD", Method.HEAD }, - .{ "head", Method.HEAD }, -}); - -var file_path_buf: bun.PathBuffer = undefined; -var cwd_buf: bun.PathBuffer = undefined; - -pub const Arguments = struct { - url: URL, - method: Method, - verbose: bool = false, - headers: Headers.Entries, - headers_buf: string, - body: string = "", - turbo: bool = false, - quiet: bool = false, - - pub fn parse(allocator: std.mem.Allocator) !Arguments { - var diag = clap.Diagnostic{}; - - var args = clap.parse(clap.Help, ¶ms, .{ - .diagnostic = &diag, - .allocator = allocator, - }) catch |err| { - // Report useful error and exit - diag.report(Output.errorWriter(), err) catch {}; - return err; - }; - - var positionals = args.positionals(); - var raw_args: std.ArrayListUnmanaged(string) = undefined; - - if (positionals.len > 0) { - raw_args = .{ .capacity = positionals.len, .items = @as([*][]const u8, @ptrFromInt(@intFromPtr(positionals.ptr)))[0..positionals.len] }; - } else { - raw_args = .{}; - } - - if (args.flag("--version")) { - try Output.writer().writeAll(VERSION); - Global.exit(0); - } - - var method = Method.GET; - var url: URL = .{}; - var body_string: string = args.option("--body") orelse ""; - - if (args.option("--file")) |file_path| { - if (file_path.len > 0) { - var cwd = try std.process.getCwd(&cwd_buf); - var parts = [_]string{file_path}; - var absolute_path = path_handler.joinAbsStringBuf(cwd, &file_path_buf, &parts, .auto); - file_path_buf[absolute_path.len] = 0; - file_path_buf[absolute_path.len + 1] = 0; - var absolute_path_len = absolute_path.len; - var absolute_path_ = file_path_buf[0..absolute_path_len :0]; - - var body_file = std.fs.openFileAbsoluteZ(absolute_path_, .{ .mode = .read_only }) catch |err| { - Output.printErrorln("{s} opening file {s}", .{ @errorName(err), absolute_path }); - Global.exit(1); - }; - - var file_contents = body_file.readToEndAlloc(allocator, try body_file.getEndPos()) catch |err| { - Output.printErrorln("{s} reading file {s}", .{ @errorName(err), absolute_path }); - Global.exit(1); - }; - body_string = file_contents; - } - } - - { - var raw_arg_i: usize = 0; - while (raw_arg_i < raw_args.items.len) : (raw_arg_i += 1) { - const arg = raw_args.items[raw_arg_i]; - if (MethodNames.get(arg[0..])) |method_| { - method = method_; - _ = raw_args.swapRemove(raw_arg_i); - } - } - - if (raw_args.items.len == 0) { - Output.prettyErrorln("error: Missing URL\n\nExample:\nfetch GET https://example.com\n\nfetch example.com/foo\n\n", .{}); - Global.exit(1); - } - - const url_position = raw_args.items.len - 1; - url = URL.parse(raw_args.swapRemove(url_position)); - if (!url.isAbsolute()) { - Output.prettyErrorln("error: Invalid URL\n\nExample:\nfetch GET https://example.com\n\nfetch example.com/foo\n\n", .{}); - Global.exit(1); - } - } - - return Arguments{ - .url = url, - .method = method, - .verbose = args.flag("--verbose"), - .headers = .{}, - .headers_buf = "", - .body = body_string, - .turbo = args.flag("--turbo"), - .quiet = args.flag("--quiet"), - }; - } -}; - -pub fn main() anyerror!void { - var stdout_ = std.io.getStdOut(); - var stderr_ = std.io.getStdErr(); - var output_source = Output.Source.init(stdout_, stderr_); - Output.Source.set(&output_source); - defer Output.flush(); - - var args = try Arguments.parse(default_allocator); - - var body_out_str = try MutableString.init(default_allocator, 1024); - var channel = try default_allocator.create(HTTP.HTTPChannel); - channel.* = HTTP.HTTPChannel.init(); - - var response_body_string = try default_allocator.create(MutableString); - response_body_string.* = body_out_str; - - try channel.buffer.ensureTotalCapacity(1); - - HTTPThread.init(); - - var ctx = try default_allocator.create(HTTP.HTTPChannelContext); - ctx.* = .{ - .channel = channel, - .http = try HTTP.AsyncHTTP.init( - default_allocator, - args.method, - args.url, - args.headers, - args.headers_buf, - response_body_string, - args.body, - HTTP.FetchRedirect.follow, - ), - }; - ctx.http.callback = HTTP.HTTPChannelContext.callback; - var batch = HTTPThread.Batch{}; - ctx.http.schedule(default_allocator, &batch); - ctx.http.client.verbose = args.verbose; - - ctx.http.verbose = args.verbose; - HTTPThread.global.schedule(batch); - - while (true) { - while (channel.tryReadItem() catch null) |http| { - var response = http.response orelse { - Output.prettyErrorln("error: HTTP response missing", .{}); - Global.exit(1); - }; - - switch (response.status_code) { - 200, 302 => {}, - else => { - if (args.verbose) { - Output.prettyErrorln("{}", .{response}); - } - }, - } - - if (!args.quiet) { - Output.flush(); - Output.disableBuffering(); - try Output.writer().writeAll(response_body_string.list.items); - Output.enableBuffering(); - } - return; - } - } -} diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 7cb2e45190..96e6cbf5ae 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -529,7 +529,7 @@ declare module "bun" { */ // tslint:disable-next-line:unified-signatures function write( - destination: BunFile | Bun.PathLike, + destination: BunFile | S3File | Bun.PathLike, input: Blob | NodeJS.TypedArray | ArrayBufferLike | string | Bun.BlobPart[], options?: { /** If writing to a PathLike, set the permissions of the file. */ @@ -1210,6 +1210,207 @@ declare module "bun" { * For empty Blob, this always returns true. */ exists(): Promise; + + /** + * Write data to the file. This is equivalent to using {@link Bun.write} with a {@link BunFile}. + * @param data - The data to write. + * @param options - The options to use for the write. + */ + write( + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer | Request | Response | BunFile, + options?: { highWaterMark?: number }, + ): Promise; + + /** + * Deletes the file. + */ + unlink(): Promise; + } + + interface S3FileOptions extends BlobPropertyBag { + /** + * The bucket to use for the S3 client. by default will use the `S3_BUCKET` and `AWS_BUCKET` environment variable, or deduce as first part of the path. + */ + bucket?: string; + /** + * The region to use for the S3 client. By default, it will use the `S3_REGION` and `AWS_REGION` environment variable. + */ + region?: string; + /** + * The access key ID to use for the S3 client. By default, it will use the `S3_ACCESS_KEY_ID` and `AWS_ACCESS_KEY_ID` environment variable. + */ + accessKeyId?: string; + /** + * The secret access key to use for the S3 client. By default, it will use the `S3_SECRET_ACCESS_KEY and `AWS_SECRET_ACCESS_KEY` environment variable. + */ + secretAccessKey?: string; + + /** + * The endpoint to use for the S3 client. Defaults to `https://s3.{region}.amazonaws.com`, it will also use the `S3_ENDPOINT` and `AWS_ENDPOINT` environment variable. + */ + endpoint?: string; + + /** + * The size of each part in MiB. Minimum and Default is 5 MiB and maximum is 5120 MiB. + */ + partSize?: number; + /** + * The number of parts to upload in parallel. Default is 5 and maximum is 255. This can speed up the upload of large files but will also use more memory. + */ + queueSize?: number; + /** + * The number of times to retry the upload if it fails. Default is 3 and maximum is 255. + */ + retry?: number; + + /** + * The Content-Type of the file. If not provided, it is automatically set based on the file extension when possible. + */ + type?: string; + + /** + * @deprecated The size of the internal buffer in bytes. Defaults to 5 MiB. use `partSize` and `queueSize` instead. + */ + highWaterMark?: number; + } + + interface S3FilePresignOptions extends S3FileOptions { + /** + * The number of seconds the presigned URL will be valid for. Defaults to 86400 (1 day). + */ + expiresIn?: number; + /** + * The HTTP method to use for the presigned URL. Defaults to GET. + */ + method?: string; + } + + interface S3File extends BunFile { + /** + * @param path - The path to the file. If bucket options is not provided or set in the path, it will be deduced from the path. + * @param options - The options to use for the S3 client. + */ + new (path: string | URL, options?: S3FileOptions): S3File; + /** + * The size of the file in bytes. + */ + size: Promise; + /** + * Offset any operation on the file starting at `begin` and ending at `end`. `end` is relative to 0 + * + * Similar to [`TypedArray.subarray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray). Does not copy the file, open the file, or modify the file. + * + * It will use [`range`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range) to download only the bytes you need. + * + * @param begin - start offset in bytes + * @param end - absolute offset in bytes (relative to 0) + * @param contentType - MIME type for the new S3File + */ + slice(begin?: number, end?: number, contentType?: string): S3File; + + /** */ + /** + * Offset any operation on the file starting at `begin` + * + * Similar to [`TypedArray.subarray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray). Does not copy the file, open the file, or modify the file. + * + * It will use [`range`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range) to download only the bytes you need. + * + * @param begin - start offset in bytes + * @param contentType - MIME type for the new S3File + */ + slice(begin?: number, contentType?: string): S3File; + + /** + * @param contentType - MIME type for the new S3File + */ + slice(contentType?: string): S3File; + + /** + * Incremental writer to stream writes to S3, this is equivalent of using MultipartUpload and is suitable for large files. + */ + writer(options?: S3FileOptions): FileSink; + + /** + * The readable stream of the file. + */ + readonly readable: ReadableStream; + + /** + * Get a readable stream of the file. + */ + stream(): ReadableStream; + + /** + * The name or path of the file, as specified in the constructor. + */ + readonly name?: string; + + /** + * The bucket name of the file. + */ + readonly bucket?: string; + + /** + * Does the file exist? + * It will use [`head`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD) to check if the file exists. + */ + exists(): Promise; + + /** + * Uploads the data to S3. This is equivalent of using {@link S3File.upload} with a {@link S3File}. + * @param data - The data to write. + * @param options - The options to use for the S3 client. + */ + write( + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer | Request | Response | BunFile | S3File | Blob, + options?: S3FileOptions, + ): Promise; + + /** + * Returns a presigned URL for the file. + * @param options - The options to use for the presigned URL. + */ + presign(options?: S3FilePresignOptions): string; + + /** + * Deletes the file from S3. + */ + unlink(): Promise; + } + + namespace S3File { + /** + * Uploads the data to S3. + * @param data - The data to write. + * @param options - The options to use for the S3 client. + */ + function upload( + path: string | S3File, + data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer | Request | Response | BunFile | S3File, + options?: S3FileOptions, + ): Promise; + + /** + * Returns a presigned URL for the file. + * @param options - The options to use for the presigned URL. + */ + function presign(path: string | S3File, options?: S3FilePresignOptions): string; + + /** + * Deletes the file from S3. + */ + function unlink(path: string | S3File, options?: S3FileOptions): Promise; + + /** + * The size of the file in bytes. + */ + function size(path: string | S3File, options?: S3FileOptions): Promise; + + /** + * The size of the file in bytes. + */ + function exists(path: string | S3File, options?: S3FileOptions): Promise; } /** @@ -3014,7 +3215,7 @@ declare module "bun" { * "Hello, world!" * ); * ``` - * @param path The path to the file (lazily loaded) + * @param path The path to the file (lazily loaded) if the path starts with `s3://` it will behave like {@link S3File} */ // tslint:disable-next-line:unified-signatures function file(path: string | URL, options?: BlobPropertyBag): BunFile; @@ -3040,7 +3241,7 @@ declare module "bun" { * console.log(file.type); // "application/json" * ``` * - * @param path The path to the file as a byte buffer (the buffer is copied) + * @param path The path to the file as a byte buffer (the buffer is copied) if the path starts with `s3://` it will behave like {@link S3File} */ // tslint:disable-next-line:unified-signatures function file(path: ArrayBufferLike | Uint8Array, options?: BlobPropertyBag): BunFile; @@ -3062,6 +3263,17 @@ declare module "bun" { // tslint:disable-next-line:unified-signatures function file(fileDescriptor: number, options?: BlobPropertyBag): BunFile; + /** + * Lazily load/upload a file from S3. + * @param path - The path to the file. If bucket options is not provided or set in the path, it will be deduced from the path. + * @param options - The options to use for the S3 client. + */ + function s3(path: string | URL, options?: S3FileOptions): S3File; + /** + * The S3 file class. + */ + const S3: typeof S3File; + /** * Allocate a new [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) without zeroing the bytes. * diff --git a/packages/bun-types/globals.d.ts b/packages/bun-types/globals.d.ts index 7b84579817..74eaa1239c 100644 --- a/packages/bun-types/globals.d.ts +++ b/packages/bun-types/globals.d.ts @@ -135,6 +135,7 @@ type _Body = typeof globalThis extends { onerror: any } readonly text: () => Promise; }; +import { S3FileOptions } from "bun"; import type { TextDecoder as NodeTextDecoder, TextEncoder as NodeTextEncoder } from "util"; import type { MessagePort } from "worker_threads"; import type { WebSocket as _WebSocket } from "ws"; @@ -815,6 +816,11 @@ declare global { rejectUnauthorized?: boolean | undefined; // Defaults to true checkServerIdentity?: any; // TODO: change `any` to `checkServerIdentity` }; + + /** + * Override the default S3 options + */ + s3?: S3FileOptions; } /** diff --git a/src/baby_list.zig b/src/baby_list.zig index adf41b1620..fea5af650d 100644 --- a/src/baby_list.zig +++ b/src/baby_list.zig @@ -304,6 +304,8 @@ pub fn BabyList(comptime Type: type) type { var list__ = this.listManaged(allocator); const writer = list__.writer(); try writer.print(fmt, args); + + this.update(list__); } pub fn append(this: *@This(), allocator: std.mem.Allocator, value: []const Type) !void { diff --git a/src/bun.js/Strong.zig b/src/bun.js/Strong.zig index 2756ac0149..0866f0d236 100644 --- a/src/bun.js/Strong.zig +++ b/src/bun.js/Strong.zig @@ -84,7 +84,7 @@ pub const Strong = struct { return result; } - pub fn has(this: *Strong) bool { + pub fn has(this: *const Strong) bool { var ref = this.ref orelse return false; return ref.get() != .zero; } diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index 3d06db4368..4a3afe2313 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -31,6 +31,7 @@ pub const BunObject = struct { pub const registerMacro = toJSCallback(Bun.registerMacro); pub const resolve = toJSCallback(Bun.resolve); pub const resolveSync = toJSCallback(Bun.resolveSync); + pub const s3 = toJSCallback(WebCore.Blob.constructS3File); pub const serve = toJSCallback(Bun.serve); pub const sha = toJSCallback(JSC.wrapStaticMethod(Crypto.SHA512_256, "hash_", true)); pub const shellEscape = toJSCallback(Bun.shellEscape); @@ -56,6 +57,7 @@ pub const BunObject = struct { pub const SHA384 = toJSGetter(Crypto.SHA384.getter); pub const SHA512 = toJSGetter(Crypto.SHA512.getter); pub const SHA512_256 = toJSGetter(Crypto.SHA512_256.getter); + pub const S3 = toJSGetter(JSC.WebCore.Blob.getJSS3FileConstructor); pub const TOML = toJSGetter(Bun.getTOMLObject); pub const Transpiler = toJSGetter(Bun.getTranspilerConstructor); pub const argv = toJSGetter(Bun.getArgv); @@ -108,12 +110,14 @@ pub const BunObject = struct { @export(BunObject.FileSystemRouter, .{ .name = getterName("FileSystemRouter") }); @export(BunObject.MD4, .{ .name = getterName("MD4") }); @export(BunObject.MD5, .{ .name = getterName("MD5") }); + @export(BunObject.S3, .{ .name = getterName("S3") }); @export(BunObject.SHA1, .{ .name = getterName("SHA1") }); @export(BunObject.SHA224, .{ .name = getterName("SHA224") }); @export(BunObject.SHA256, .{ .name = getterName("SHA256") }); @export(BunObject.SHA384, .{ .name = getterName("SHA384") }); @export(BunObject.SHA512, .{ .name = getterName("SHA512") }); @export(BunObject.SHA512_256, .{ .name = getterName("SHA512_256") }); + @export(BunObject.TOML, .{ .name = getterName("TOML") }); @export(BunObject.Glob, .{ .name = getterName("Glob") }); @export(BunObject.Transpiler, .{ .name = getterName("Transpiler") }); @@ -155,6 +159,7 @@ pub const BunObject = struct { @export(BunObject.resolve, .{ .name = callbackName("resolve") }); @export(BunObject.resolveSync, .{ .name = callbackName("resolveSync") }); @export(BunObject.serve, .{ .name = callbackName("serve") }); + @export(BunObject.s3, .{ .name = callbackName("s3") }); @export(BunObject.sha, .{ .name = callbackName("sha") }); @export(BunObject.shellEscape, .{ .name = callbackName("shellEscape") }); @export(BunObject.shrink, .{ .name = callbackName("shrink") }); diff --git a/src/bun.js/bindings/BunObject+exports.h b/src/bun.js/bindings/BunObject+exports.h index 374af28774..d4f267b822 100644 --- a/src/bun.js/bindings/BunObject+exports.h +++ b/src/bun.js/bindings/BunObject+exports.h @@ -17,6 +17,7 @@ macro(SHA512_256) \ macro(TOML) \ macro(Transpiler) \ + macro(S3) \ macro(argv) \ macro(assetPrefix) \ macro(cwd) \ @@ -57,6 +58,7 @@ macro(registerMacro) \ macro(resolve) \ macro(resolveSync) \ + macro(s3) \ macro(serve) \ macro(sha) \ macro(shrink) \ diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index 225f422e4b..502e8cf796 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -576,6 +576,7 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj Glob BunObject_getter_wrap_Glob DontDelete|PropertyCallback MD4 BunObject_getter_wrap_MD4 DontDelete|PropertyCallback MD5 BunObject_getter_wrap_MD5 DontDelete|PropertyCallback + S3 BunObject_getter_wrap_S3 DontDelete|PropertyCallback SHA1 BunObject_getter_wrap_SHA1 DontDelete|PropertyCallback SHA224 BunObject_getter_wrap_SHA224 DontDelete|PropertyCallback SHA256 BunObject_getter_wrap_SHA256 DontDelete|PropertyCallback @@ -637,6 +638,7 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj resolveSync BunObject_callback_resolveSync DontDelete|Function 1 revision constructBunRevision ReadOnly|DontDelete|PropertyCallback semver BunObject_getter_wrap_semver ReadOnly|DontDelete|PropertyCallback + s3 BunObject_callback_s3 DontDelete|Function 1 sql constructBunSQLObject DontDelete|PropertyCallback serve BunObject_callback_serve DontDelete|Function 1 sha BunObject_callback_sha DontDelete|Function 1 diff --git a/src/bun.js/bindings/ErrorCode.ts b/src/bun.js/bindings/ErrorCode.ts index ce57deaac5..bb72e160d2 100644 --- a/src/bun.js/bindings/ErrorCode.ts +++ b/src/bun.js/bindings/ErrorCode.ts @@ -99,4 +99,11 @@ export default [ // Postgres ["ERR_POSTGRES_ERROR_RESPONSE", Error, "PostgresError"], + + // AWS + ["ERR_AWS_MISSING_CREDENTIALS", Error], + ["ERR_AWS_INVALID_METHOD", Error], + ["ERR_AWS_INVALID_PATH", Error], + ["ERR_AWS_INVALID_ENDPOINT", Error], + ["ERR_AWS_INVALID_SIGNATURE", Error], ] as ErrorCodeMapping; diff --git a/src/bun.js/bindings/JSS3File.cpp b/src/bun.js/bindings/JSS3File.cpp new file mode 100644 index 0000000000..418c449f57 --- /dev/null +++ b/src/bun.js/bindings/JSS3File.cpp @@ -0,0 +1,125 @@ +#include "root.h" +#include "ZigGeneratedClasses.h" +#include +#include +#include +#include "JSS3File.h" +#include "JavaScriptCore/JSCJSValue.h" + +using namespace JSC; + +extern "C" SYSV_ABI void* JSS3File__construct(JSC::JSGlobalObject*, JSC::CallFrame* callframe); +extern "C" SYSV_ABI bool JSS3File__hasInstance(EncodedJSValue, JSC::JSGlobalObject*, EncodedJSValue); + +extern "C" { + +JSC::EncodedJSValue BUN__createJSS3FileConstructor(JSGlobalObject* lexicalGlobalObject) +{ + Zig::GlobalObject* globalObject = reinterpret_cast(lexicalGlobalObject); + + return JSValue::encode(globalObject->JSS3FileConstructor()); +} +} + +// TODO: make this inehrit from JSBlob instead of InternalFunction +// That will let us remove this hack for [Symbol.hasInstance] and fix the prototype chain. +class JSS3File : public JSC::InternalFunction { + using Base = JSC::InternalFunction; + +public: + JSS3File(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure, call, construct) + { + } + + DECLARE_INFO; + + static constexpr unsigned StructureFlags = (Base::StructureFlags & ~ImplementsDefaultHasInstance) | ImplementsHasInstance; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return &vm.internalFunctionSpace(); + } + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(InternalFunctionType, StructureFlags), info()); + } + + void finishCreation(JSC::VM& vm) + { + Base::finishCreation(vm, 2, "S3"_s); + } + + static JSS3File* create(JSC::VM& vm, JSGlobalObject* globalObject) + { + auto* zigGlobal = reinterpret_cast(globalObject); + auto structure = createStructure(vm, globalObject, zigGlobal->functionPrototype()); + auto* object = new (NotNull, JSC::allocateCell(vm)) JSS3File(vm, structure); + object->finishCreation(vm); + + // This is not quite right. But we'll fix it if someone files an issue about it. + object->putDirect(vm, vm.propertyNames->prototype, zigGlobal->JSBlobPrototype(), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | 0); + + return object; + } + + static bool customHasInstance(JSObject* object, JSGlobalObject* globalObject, JSValue value) + { + if (!value.isObject()) + return false; + + // Note: this breaks [Symbol.hasInstance] + // We must do this for now until we update the code generator to export classes + return JSS3File__hasInstance(JSValue::encode(object), globalObject, JSValue::encode(value)); + } + + static JSC_HOST_CALL_ATTRIBUTES JSC::EncodedJSValue construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) + { + Zig::GlobalObject* globalObject = reinterpret_cast(lexicalGlobalObject); + JSC::VM& vm = globalObject->vm(); + JSObject* newTarget = asObject(callFrame->newTarget()); + auto* constructor = globalObject->JSS3FileConstructor(); + + Structure* structure = globalObject->JSBlobStructure(); + if (constructor != newTarget) { + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* functionGlobalObject = reinterpret_cast( + // ShadowRealm functions belong to a different global object. + getFunctionRealm(globalObject, newTarget)); + RETURN_IF_EXCEPTION(scope, {}); + structure = InternalFunction::createSubclassStructure( + globalObject, + newTarget, + functionGlobalObject->JSBlobStructure()); + } + + void* ptr = JSS3File__construct(globalObject, callFrame); + + if (UNLIKELY(!ptr)) { + return JSValue::encode(JSC::jsUndefined()); + } + + return JSValue::encode( + WebCore::JSBlob::create(vm, globalObject, structure, ptr)); + } + + static JSC_HOST_CALL_ATTRIBUTES EncodedJSValue call(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) + { + auto scope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm()); + throwTypeError(lexicalGlobalObject, scope, "Class constructor S3 cannot be invoked without 'new'"_s); + return {}; + } +}; + +const JSC::ClassInfo JSS3File::s_info = { "S3"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSS3File) }; + +namespace Bun { + +JSC::JSObject* createJSS3FileConstructor(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + return JSS3File::create(vm, globalObject); +} + +} diff --git a/src/bun.js/bindings/JSS3File.h b/src/bun.js/bindings/JSS3File.h new file mode 100644 index 0000000000..63b8170b06 --- /dev/null +++ b/src/bun.js/bindings/JSS3File.h @@ -0,0 +1,7 @@ +#pragma once + +#include "root.h" + +namespace Bun { +JSC::JSObject* createJSS3FileConstructor(JSC::VM&, JSC::JSGlobalObject*); +} diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index fe179e0de3..e08044c7c1 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1,4 +1,5 @@ #include "root.h" +#include "JavaScriptCore/PropertySlot.h" #include "ZigGlobalObject.h" #include "helpers.h" #include "JavaScriptCore/ArgList.h" @@ -83,6 +84,7 @@ #include "JSDOMConvertUnion.h" #include "JSDOMException.h" #include "JSDOMFile.h" +#include "JSS3File.h" #include "JSDOMFormData.h" #include "JSDOMURL.h" #include "JSEnvironmentVariableMap.h" @@ -2810,6 +2812,37 @@ JSC_DEFINE_CUSTOM_SETTER(moduleNamespacePrototypeSetESModuleMarker, (JSGlobalObj return true; } +extern "C" JSC::EncodedJSValue JSS3File__upload(JSGlobalObject*, JSC::CallFrame*); +extern "C" JSC::EncodedJSValue JSS3File__presign(JSGlobalObject*, JSC::CallFrame*); +extern "C" JSC::EncodedJSValue JSS3File__unlink(JSGlobalObject*, JSC::CallFrame*); +extern "C" JSC::EncodedJSValue JSS3File__exists(JSGlobalObject*, JSC::CallFrame*); +extern "C" JSC::EncodedJSValue JSS3File__size(JSGlobalObject*, JSC::CallFrame*); + +JSC_DEFINE_HOST_FUNCTION(jsS3Upload, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) +{ + return JSS3File__upload(lexicalGlobalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(jsS3Presign, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) +{ + return JSS3File__presign(lexicalGlobalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(jsS3Unlink, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) +{ + return JSS3File__unlink(lexicalGlobalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(jsS3Exists, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) +{ + return JSS3File__exists(lexicalGlobalObject, callFrame); +} + +JSC_DEFINE_HOST_FUNCTION(jsS3Size, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) +{ + return JSS3File__size(lexicalGlobalObject, callFrame); +} + void GlobalObject::finishCreation(VM& vm) { Base::finishCreation(vm); @@ -2831,6 +2864,18 @@ void GlobalObject::finishCreation(VM& vm) init.set(fileConstructor); }); + m_JSS3FileConstructor.initLater( + [](const Initializer& init) { + JSObject* s3Constructor = Bun::createJSS3FileConstructor(init.vm, init.owner); + s3Constructor->putDirectNativeFunction(init.vm, init.owner, JSC::Identifier::fromString(init.vm, "upload"_s), 3, jsS3Upload, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | 0); + s3Constructor->putDirectNativeFunction(init.vm, init.owner, JSC::Identifier::fromString(init.vm, "unlink"_s), 3, jsS3Unlink, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | 0); + s3Constructor->putDirectNativeFunction(init.vm, init.owner, JSC::Identifier::fromString(init.vm, "presign"_s), 3, jsS3Presign, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | 0); + s3Constructor->putDirectNativeFunction(init.vm, init.owner, JSC::Identifier::fromString(init.vm, "exists"_s), 3, jsS3Exists, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | 0); + s3Constructor->putDirectNativeFunction(init.vm, init.owner, JSC::Identifier::fromString(init.vm, "size"_s), 3, jsS3Size, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | 0); + + init.set(s3Constructor); + }); + m_cryptoObject.initLater( [](const Initializer& init) { JSC::JSGlobalObject* globalObject = init.owner; @@ -3805,6 +3850,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_JSCryptoKey.visit(visitor); thisObject->m_lazyStackCustomGetterSetter.visit(visitor); thisObject->m_JSDOMFileConstructor.visit(visitor); + thisObject->m_JSS3FileConstructor.visit(visitor); thisObject->m_JSFFIFunctionStructure.visit(visitor); thisObject->m_JSFileSinkClassStructure.visit(visitor); thisObject->m_JSFileSinkControllerPrototype.visit(visitor); @@ -4357,6 +4403,14 @@ GlobalObject::PromiseFunctions GlobalObject::promiseHandlerID(Zig::FFIFunction h return GlobalObject::PromiseFunctions::Bun__FetchTasklet__onResolveRequestStream; } else if (handler == Bun__FetchTasklet__onRejectRequestStream) { return GlobalObject::PromiseFunctions::Bun__FetchTasklet__onRejectRequestStream; + } else if (handler == Bun__S3UploadStream__onResolveRequestStream) { + return GlobalObject::PromiseFunctions::Bun__S3UploadStream__onResolveRequestStream; + } else if (handler == Bun__S3UploadStream__onRejectRequestStream) { + return GlobalObject::PromiseFunctions::Bun__S3UploadStream__onRejectRequestStream; + } else if (handler == Bun__FileStreamWrapper__onResolveRequestStream) { + return GlobalObject::PromiseFunctions::Bun__FileStreamWrapper__onResolveRequestStream; + } else if (handler == Bun__FileStreamWrapper__onRejectRequestStream) { + return GlobalObject::PromiseFunctions::Bun__FileStreamWrapper__onRejectRequestStream; } else { RELEASE_ASSERT_NOT_REACHED(); } diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index c2dca678fc..33beb34c7e 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -336,8 +336,12 @@ public: Bun__onRejectEntryPointResult, Bun__FetchTasklet__onRejectRequestStream, Bun__FetchTasklet__onResolveRequestStream, + Bun__S3UploadStream__onRejectRequestStream, + Bun__S3UploadStream__onResolveRequestStream, + Bun__FileStreamWrapper__onRejectRequestStream, + Bun__FileStreamWrapper__onResolveRequestStream, }; - static constexpr size_t promiseFunctionsSize = 26; + static constexpr size_t promiseFunctionsSize = 30; static PromiseFunctions promiseHandlerID(SYSV_ABI EncodedJSValue (*handler)(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1)); @@ -476,6 +480,8 @@ public: JSObject* cryptoObject() const { return m_cryptoObject.getInitializedOnMainThread(this); } JSObject* JSDOMFileConstructor() const { return m_JSDOMFileConstructor.getInitializedOnMainThread(this); } + JSObject* JSS3FileConstructor() const { return m_JSS3FileConstructor.getInitializedOnMainThread(this); } + Bun::CommonStrings& commonStrings() { return m_commonStrings; } Bun::Http2CommonStrings& http2CommonStrings() { return m_http2_commongStrings; } #include "ZigGeneratedClasses+lazyStructureHeader.h" @@ -568,6 +574,8 @@ public: LazyProperty m_importMetaObjectStructure; LazyProperty m_asyncBoundFunctionStructure; LazyProperty m_JSDOMFileConstructor; + LazyProperty m_JSS3FileConstructor; + LazyProperty m_JSCryptoKey; LazyProperty m_NapiExternalStructure; LazyProperty m_NapiPrototypeStructure; diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 7840f0acf0..244e7cc9e9 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -6009,6 +6009,40 @@ extern "C" int JSC__JSValue__toISOString(JSC::JSGlobalObject* globalObject, Enco return charactersWritten; } +extern "C" int JSC__JSValue__DateNowISOString(JSC::JSGlobalObject* globalObject, char* buf) +{ + char buffer[29]; + JSC::DateInstance* thisDateObj = JSC::DateInstance::create(globalObject->vm(), globalObject->dateStructure(), globalObject->jsDateNow()); + + if (!std::isfinite(thisDateObj->internalNumber())) + return -1; + + auto& vm = globalObject->vm(); + + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm.dateCache); + if (!gregorianDateTime) + return -1; + + // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1). + int ms = static_cast(fmod(thisDateObj->internalNumber(), msPerSecond)); + if (ms < 0) + ms += msPerSecond; + + int charactersWritten; + if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0) + charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms); + else + charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms); + + memcpy(buf, buffer, charactersWritten); + + ASSERT(charactersWritten > 0 && static_cast(charactersWritten) < sizeof(buffer)); + if (static_cast(charactersWritten) >= sizeof(buffer)) + return -1; + + return charactersWritten; +} + #pragma mark - WebCore::DOMFormData CPP_DECL void WebCore__DOMFormData__append(WebCore__DOMFormData* arg0, ZigString* arg1, ZigString* arg2) diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index ef989ab0d1..b143919289 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -2460,6 +2460,14 @@ pub const JSPromise = extern struct { return this.strong.get() orelse .zero; } + pub fn hasValue(this: *const Strong) bool { + return this.strong.has(); + } + + pub fn globalObject(this: *const Strong) ?*JSC.JSGlobalObject { + return this.strong.globalThis; + } + pub fn swap(this: *Strong) *JSC.JSPromise { const prom = this.strong.swap().asPromise().?; this.strong.deinit(); @@ -4337,6 +4345,15 @@ pub const JSValue = enum(i64) { return buf[0..@as(usize, @intCast(count))]; } + extern fn JSC__JSValue__DateNowISOString(*JSGlobalObject, f64) JSValue; + pub fn getDateNowISOString(globalObject: *JSC.JSGlobalObject, buf: *[28]u8) []const u8 { + const count = JSC__JSValue__DateNowISOString(globalObject, buf); + if (count < 0) { + return ""; + } + + return buf[0..@as(usize, @intCast(count))]; + } /// Return the pointer to the wrapped object only if it is a direct instance of the type. /// If the object does not match the type, return null. @@ -4396,6 +4413,7 @@ pub const JSValue = enum(i64) { } extern fn JSC__JSValue__dateInstanceFromNumber(*JSGlobalObject, f64) JSValue; + pub fn fromDateNumber(globalObject: *JSGlobalObject, value: f64) JSValue { JSC.markBinding(@src()); return JSC__JSValue__dateInstanceFromNumber(globalObject, value); @@ -5620,6 +5638,7 @@ pub const JSValue = enum(i64) { } return JSC.Node.validators.throwErrInvalidArgType(global, property_name, .{}, "string", prop); }, + i32 => return prop.coerce(i32, global), else => @compileError("TODO:" ++ @typeName(T)), } } diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index 405c835e56..9bdf332b16 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -869,4 +869,11 @@ BUN_DECLARE_HOST_FUNCTION(Bun__onRejectEntryPointResult); BUN_DECLARE_HOST_FUNCTION(Bun__FetchTasklet__onResolveRequestStream); BUN_DECLARE_HOST_FUNCTION(Bun__FetchTasklet__onRejectRequestStream); +BUN_DECLARE_HOST_FUNCTION(Bun__S3UploadStream__onResolveRequestStream); +BUN_DECLARE_HOST_FUNCTION(Bun__S3UploadStream__onRejectRequestStream); + +BUN_DECLARE_HOST_FUNCTION(Bun__FileStreamWrapper__onResolveRequestStream); +BUN_DECLARE_HOST_FUNCTION(Bun__FileStreamWrapper__onRejectRequestStream); + + #endif \ No newline at end of file diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 1b4c3a1b78..21e6393b89 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -18,6 +18,10 @@ const ReadFileTask = WebCore.Blob.ReadFile.ReadFileTask; const WriteFileTask = WebCore.Blob.WriteFile.WriteFileTask; const napi_async_work = JSC.napi.napi_async_work; const FetchTasklet = Fetch.FetchTasklet; +const AWS = @import("../s3.zig").AWSCredentials; +const S3HttpSimpleTask = AWS.S3HttpSimpleTask; +const S3HttpDownloadStreamingTask = AWS.S3HttpDownloadStreamingTask; + const JSValue = JSC.JSValue; const js = JSC.C; const Waker = bun.Async.Waker; @@ -407,6 +411,8 @@ const ServerAllConnectionsClosedTask = @import("./api/server.zig").ServerAllConn // Task.get(ReadFileTask) -> ?ReadFileTask pub const Task = TaggedPointerUnion(.{ FetchTasklet, + S3HttpSimpleTask, + S3HttpDownloadStreamingTask, PosixSignalTask, AsyncGlobWalkTask, AsyncTransformTask, @@ -1006,6 +1012,15 @@ pub const EventLoop = struct { var fetch_task: *Fetch.FetchTasklet = task.get(Fetch.FetchTasklet).?; fetch_task.onProgressUpdate(); }, + .S3HttpSimpleTask => { + var s3_task: *S3HttpSimpleTask = task.get(S3HttpSimpleTask).?; + s3_task.onResponse(); + }, + .S3HttpDownloadStreamingTask => { + var s3_task: *S3HttpDownloadStreamingTask = task.get(S3HttpDownloadStreamingTask).?; + s3_task.onResponse(); + }, + @field(Task.Tag, @typeName(AsyncGlobWalkTask)) => { var globWalkTask: *AsyncGlobWalkTask = task.get(AsyncGlobWalkTask).?; globWalkTask.*.runFromJS(); diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig index 45ebac3282..5bad28c278 100644 --- a/src/bun.js/rare_data.zig +++ b/src/bun.js/rare_data.zig @@ -48,7 +48,58 @@ listening_sockets_for_watch_mode_lock: bun.Lock = .{}, temp_pipe_read_buffer: ?*PipeReadBuffer = null, +aws_signature_cache: AWSSignatureCache = .{}, + const PipeReadBuffer = [256 * 1024]u8; +const DIGESTED_HMAC_256_LEN = 32; +pub const AWSSignatureCache = struct { + cache: bun.StringArrayHashMap([DIGESTED_HMAC_256_LEN]u8) = bun.StringArrayHashMap([DIGESTED_HMAC_256_LEN]u8).init(bun.default_allocator), + date: u64 = 0, + lock: bun.Lock = .{}, + + pub fn clean(this: *@This()) void { + for (this.cache.keys()) |cached_key| { + bun.default_allocator.free(cached_key); + } + this.cache.clearRetainingCapacity(); + } + + pub fn get(this: *@This(), numeric_day: u64, key: []const u8) ?[]const u8 { + this.lock.lock(); + defer this.lock.unlock(); + if (this.date == 0) { + return null; + } + if (this.date == numeric_day) { + if (this.cache.getKey(key)) |cached| { + return cached; + } + } + return null; + } + + pub fn set(this: *@This(), numeric_day: u64, key: []const u8, value: [DIGESTED_HMAC_256_LEN]u8) void { + this.lock.lock(); + defer this.lock.unlock(); + if (this.date == 0) { + this.cache = bun.StringArrayHashMap([DIGESTED_HMAC_256_LEN]u8).init(bun.default_allocator); + } else if (this.date != numeric_day) { + // day changed so we clean the old cache + this.clean(); + } + this.date = numeric_day; + this.cache.put(bun.default_allocator.dupe(u8, key) catch bun.outOfMemory(), value) catch bun.outOfMemory(); + } + pub fn deinit(this: *@This()) void { + this.date = 0; + this.clean(); + this.cache.deinit(); + } +}; + +pub fn awsCache(this: *RareData) *AWSSignatureCache { + return &this.aws_signature_cache; +} pub fn pipeReadBuffer(this: *RareData) *PipeReadBuffer { return this.temp_pipe_read_buffer orelse { @@ -389,6 +440,8 @@ pub fn deinit(this: *RareData) void { bun.default_allocator.destroy(pipe); } + this.aws_signature_cache.deinit(); + if (this.boring_ssl_engine) |engine| { _ = bun.BoringSSL.ENGINE_free(engine); } diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index beb6b1f8f6..a154a8cb75 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -19,7 +19,6 @@ const default_allocator = bun.default_allocator; const FeatureFlags = bun.FeatureFlags; const ArrayBuffer = @import("../base.zig").ArrayBuffer; const Properties = @import("../base.zig").Properties; - const getAllocator = @import("../base.zig").getAllocator; const Environment = @import("../../env.zig"); @@ -44,6 +43,10 @@ const Request = JSC.WebCore.Request; const libuv = bun.windows.libuv; +const AWSCredentials = @import("../../s3.zig").AWSCredentials; +const S3MultiPartUpload = @import("../../s3.zig").MultiPartUpload; +const AWS = AWSCredentials; + const PathOrBlob = union(enum) { path: JSC.Node.PathOrFileDescriptor, blob: Blob, @@ -134,7 +137,25 @@ pub const Blob = struct { } pub fn hasContentTypeFromUser(this: *const Blob) bool { - return this.content_type_was_set or (this.store != null and this.store.?.data == .file); + return this.content_type_was_set or (this.store != null and (this.store.?.data == .file or this.store.?.data == .s3)); + } + + pub fn contentTypeOrMimeType(this: *const Blob) ?[]const u8 { + if (this.content_type.len > 0) { + return this.content_type; + } + if (this.store) |store| { + switch (store.data) { + .file => |file| { + return file.mime_type.value; + }, + .s3 => |s3| { + return s3.mime_type.value; + }, + else => return null, + } + } + return null; } pub fn isBunFile(this: *const Blob) bool { @@ -144,7 +165,16 @@ pub const Blob = struct { } const ReadFileUV = @import("./blob/ReadFile.zig").ReadFileUV; + pub fn doReadFromS3(this: *Blob, comptime Function: anytype, global: *JSGlobalObject) JSValue { + bloblog("doReadFromS3", .{}); + const WrappedFn = struct { + pub fn wrapped(b: *Blob, g: *JSGlobalObject, by: []u8) JSC.JSValue { + return JSC.toJSHostValue(g, Function(b, g, by, .clone)); + } + }; + return S3BlobDownloadTask.init(global, this, WrappedFn.wrapped); + } pub fn doReadFile(this: *Blob, comptime Function: anytype, global: *JSGlobalObject) JSValue { bloblog("doReadFile", .{}); @@ -263,6 +293,10 @@ pub const Blob = struct { blob.resolveSize(); } switch (store.data) { + .s3 => |_| { + // TODO: s3 + // we need to make this async and use s3Download/s3DownloadSlice + }, .file => |file| { // TODO: make this async + lazy @@ -464,6 +498,7 @@ pub const Blob = struct { const blob = Blob.new(Blob.findOrCreateFileFromPath( &path_or_fd, globalThis, + true, )); break :file blob; @@ -480,6 +515,7 @@ pub const Blob = struct { const blob = Blob.new(Blob.findOrCreateFileFromPath( &dest, globalThis, + true, )); break :file blob; @@ -682,6 +718,15 @@ pub const Blob = struct { { const store = this.store.?; switch (store.data) { + .s3 => |s3| { + try writer.writeAll(comptime Output.prettyFmt("S3Ref", enable_ansi_colors)); + try writer.print( + comptime Output.prettyFmt(" (\"{s}\")", enable_ansi_colors), + .{ + s3.pathlike.slice(), + }, + ); + }, .file => |file| { try writer.writeAll(comptime Output.prettyFmt("FileRef", enable_ansi_colors)); switch (file.pathlike) { @@ -839,7 +884,7 @@ pub const Blob = struct { ctx: JSC.C.JSContextRef, source_blob: *Blob, destination_blob: *Blob, - mkdirp_if_not_exists: bool, + options: WriteFileOptions, ) JSC.JSValue { const destination_type = std.meta.activeTag(destination_blob.store.?.data); @@ -867,6 +912,44 @@ pub const Blob = struct { return JSC.JSPromise.rejectedPromiseValue(ctx, result.toJS(ctx)); } + } else if (destination_type == .s3) { + + // create empty file + const s3 = &destination_blob.store.?.data.s3; + var aws_options = s3.getCredentialsWithOptions(options.extra_options, ctx) catch |err| { + return JSC.JSPromise.rejectedPromiseValue(ctx, ctx.takeException(err)); + }; + defer aws_options.deinit(); + + const Wrapper = struct { + promise: JSC.JSPromise.Strong, + pub usingnamespace bun.New(@This()); + + pub fn resolve(result: AWS.S3UploadResult, this: *@This()) void { + if (this.promise.globalObject()) |globalObject| { + switch (result) { + .success => this.promise.resolve(globalObject, JSC.jsNumber(0)), + .failure => |err| { + this.promise.rejectOnNextTick(globalObject, err.toJS(globalObject)); + }, + } + } + this.deinit(); + } + + fn deinit(this: *@This()) void { + this.promise.deinit(); + } + }; + + const promise = JSC.JSPromise.Strong.init(ctx); + const promise_value = promise.value(); + const proxy = ctx.bunVM().transpiler.env.getHttpProxy(true, null); + const proxy_url = if (proxy) |p| p.href else null; + aws_options.credentials.s3Upload(s3.path(), "", destination_blob.contentTypeOrMimeType(), proxy_url, @ptrCast(&Wrapper.resolve), Wrapper.new(.{ + .promise = promise, + })); + return promise_value; } return JSC.JSPromise.resolvedPromiseValue(ctx, JSC.JSValue.jsNumber(0)); @@ -891,7 +974,7 @@ pub const Blob = struct { *WriteFilePromise, write_file_promise, &WriteFilePromise.run, - mkdirp_if_not_exists, + options.mkdirp_if_not_exists orelse true, ); return promise_value; } @@ -902,7 +985,7 @@ pub const Blob = struct { *WriteFilePromise, write_file_promise, WriteFilePromise.run, - mkdirp_if_not_exists, + options.mkdirp_if_not_exists orelse true, ) catch unreachable; var task = WriteFile.WriteFileTask.createOnJSThread(bun.default_allocator, ctx, file_copier) catch bun.outOfMemory(); // Defer promise creation until we're just about to schedule the task @@ -920,7 +1003,7 @@ pub const Blob = struct { destination_blob.store.?, source_blob.store.?, ctx.bunVM().eventLoop(), - mkdirp_if_not_exists, + options.mkdirp_if_not_exists orelse true, destination_blob.size, ); } @@ -932,10 +1015,21 @@ pub const Blob = struct { destination_blob.offset, destination_blob.size, ctx, - mkdirp_if_not_exists, + options.mkdirp_if_not_exists orelse true, ) catch unreachable; file_copier.schedule(); return file_copier.promise.value(); + } else if (destination_type == .file and source_type == .s3) { + const s3 = &source_blob.store.?.data.s3; + if (JSC.WebCore.ReadableStream.fromJS(JSC.WebCore.ReadableStream.fromBlob( + ctx, + source_blob, + @truncate(s3.options.partSize * S3MultiPartUpload.OneMiB), + ), ctx)) |stream| { + return destination_blob.pipeReadableStreamToBlob(ctx, stream, options.extra_options); + } else { + return JSC.JSPromise.rejectedPromiseValue(ctx, ctx.createErrorInstance("Failed to stream bytes from s3 bucket", .{})); + } } else if (destination_type == .bytes and source_type == .bytes) { // If this is bytes <> bytes, we can just duplicate it // this is an edgecase @@ -946,41 +1040,95 @@ pub const Blob = struct { const cloned = Blob.new(clone); cloned.allocator = bun.default_allocator; return JSPromise.resolvedPromiseValue(ctx, cloned.toJS(ctx)); - } else if (destination_type == .bytes and source_type == .file) { - var fake_call_frame: [8]JSC.JSValue = undefined; - @memset(@as([*]u8, @ptrCast(&fake_call_frame))[0..@sizeOf(@TypeOf(fake_call_frame))], 0); - const blob_value = source_blob.getSlice(ctx, @as(*JSC.CallFrame, @ptrCast(&fake_call_frame))) catch .zero; // TODO: + } else if (destination_type == .bytes and (source_type == .file or source_type == .s3)) { + const blob_value = source_blob.getSliceFrom(ctx, 0, 0, "", false); return JSPromise.resolvedPromiseValue( ctx, blob_value, ); + } else if (destination_type == .s3) { + const s3 = &destination_blob.store.?.data.s3; + var aws_options = s3.getCredentialsWithOptions(options.extra_options, ctx) catch |err| { + return JSC.JSPromise.rejectedPromiseValue(ctx, ctx.takeException(err)); + }; + defer aws_options.deinit(); + const store = source_blob.store.?; + const proxy = ctx.bunVM().transpiler.env.getHttpProxy(true, null); + const proxy_url = if (proxy) |p| p.href else null; + switch (store.data) { + .bytes => |bytes| { + if (bytes.len > S3MultiPartUpload.MAX_SINGLE_UPLOAD_SIZE) { + if (JSC.WebCore.ReadableStream.fromJS(JSC.WebCore.ReadableStream.fromBlob( + ctx, + source_blob, + @truncate(s3.options.partSize * S3MultiPartUpload.OneMiB), + ), ctx)) |stream| { + return (if (options.extra_options != null) aws_options.credentials.dupe() else s3.getCredentials()).s3UploadStream(s3.path(), stream, ctx, aws_options.options, destination_blob.contentTypeOrMimeType(), proxy_url, null, undefined); + } else { + return JSC.JSPromise.rejectedPromiseValue(ctx, ctx.createErrorInstance("Failed to stream bytes to s3 bucket", .{})); + } + } else { + const Wrapper = struct { + store: *Store, + promise: JSC.JSPromise.Strong, + pub usingnamespace bun.New(@This()); + + pub fn resolve(result: AWS.S3UploadResult, this: *@This()) void { + if (this.promise.globalObject()) |globalObject| { + switch (result) { + .success => this.promise.resolve(globalObject, JSC.jsNumber(this.store.data.bytes.len)), + .failure => |err| { + this.promise.rejectOnNextTick(globalObject, err.toJS(globalObject)); + }, + } + } + this.deinit(); + } + + fn deinit(this: *@This()) void { + this.promise.deinit(); + this.store.deref(); + } + }; + store.ref(); + const promise = JSC.JSPromise.Strong.init(ctx); + const promise_value = promise.value(); + + aws_options.credentials.s3Upload(s3.path(), bytes.slice(), destination_blob.contentTypeOrMimeType(), proxy_url, @ptrCast(&Wrapper.resolve), Wrapper.new(.{ + .store = store, + .promise = promise, + })); + return promise_value; + } + }, + .file, .s3 => { + // stream + if (JSC.WebCore.ReadableStream.fromJS(JSC.WebCore.ReadableStream.fromBlob( + ctx, + source_blob, + @truncate(s3.options.partSize * S3MultiPartUpload.OneMiB), + ), ctx)) |stream| { + return (if (options.extra_options != null) aws_options.credentials.dupe() else s3.getCredentials()).s3UploadStream(s3.path(), stream, ctx, s3.options, destination_blob.contentTypeOrMimeType(), proxy_url, null, undefined); + } else { + return JSC.JSPromise.rejectedPromiseValue(ctx, ctx.createErrorInstance("Failed to stream bytes to s3 bucket", .{})); + } + }, + } } unreachable; } - pub fn writeFile(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { - const arguments = callframe.arguments_old(3).slice(); - var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); - defer args.deinit(); - - // accept a path or a blob - var path_or_blob = try PathOrBlob.fromJSNoCopy(globalThis, &args); - defer { - if (path_or_blob == .path) { - path_or_blob.path.deinit(); - } - } - - var data = args.nextEat() orelse { - return globalThis.throwInvalidArguments("Bun.write(pathOrFdOrBlob, blob) expects a Blob-y thing to write", .{}); - }; - + const WriteFileOptions = struct { + mkdirp_if_not_exists: ?bool = null, + extra_options: ?JSValue = null, + }; + pub fn writeFileInternal(globalThis: *JSC.JSGlobalObject, path_or_blob_: *PathOrBlob, data: JSC.JSValue, options: WriteFileOptions) bun.JSError!JSC.JSValue { if (data.isEmptyOrUndefinedOrNull()) { return globalThis.throwInvalidArguments("Bun.write(pathOrFdOrBlob, blob) expects a Blob-y thing to write", .{}); } - + var path_or_blob = path_or_blob_.*; if (path_or_blob == .blob) { if (path_or_blob.blob.store == null) { return globalThis.throwInvalidArguments("Blob is detached", .{}); @@ -1000,22 +1148,7 @@ pub const Blob = struct { var needs_async = false; - var mkdirp_if_not_exists: ?bool = null; - - if (args.nextEat()) |options_object| { - if (options_object.isObject()) { - if (try options_object.getTruthy(globalThis, "createPath")) |create_directory| { - if (!create_directory.isBoolean()) { - return globalThis.throwInvalidArgumentType("write", "options.createPath", "boolean"); - } - mkdirp_if_not_exists = create_directory.toBoolean(); - } - } else if (!options_object.isEmptyOrUndefinedOrNull()) { - return globalThis.throwInvalidArgumentType("write", "options", "object"); - } - } - - if (mkdirp_if_not_exists) |mkdir| { + if (options.mkdirp_if_not_exists) |mkdir| { if (mkdir and path_or_blob == .blob and path_or_blob.blob.store != null and @@ -1033,7 +1166,7 @@ pub const Blob = struct { if (comptime !Environment.isWindows) { if (path_or_blob == .path or // If they try to set an offset, its a little more complicated so let's avoid that - (path_or_blob.blob.offset == 0 and + (path_or_blob.blob.offset == 0 and !path_or_blob.blob.isS3() and // Is this a file that is known to be a pipe? Let's avoid blocking the main thread on it. !(path_or_blob.blob.store != null and path_or_blob.blob.store.?.data == .file and @@ -1115,7 +1248,7 @@ pub const Blob = struct { // if path_or_blob is a path, convert it into a file blob var destination_blob: Blob = if (path_or_blob == .path) brk: { - break :brk Blob.findOrCreateFileFromPath(&path_or_blob.path, globalThis); + break :brk Blob.findOrCreateFileFromPath(&path_or_blob_.path, globalThis, true); } else path_or_blob.blob.dupe(); if (destination_blob.store == null) { @@ -1140,12 +1273,30 @@ pub const Blob = struct { _ = response.body.value.use(); return JSC.JSPromise.rejectedPromiseValue(globalThis, err_ref.toJS(globalThis)); }, - .Locked => { + .Locked => |*locked| { + if (destination_blob.isS3()) { + const s3 = &destination_blob.store.?.data.s3; + var aws_options = try s3.getCredentialsWithOptions(options.extra_options, globalThis); + defer aws_options.deinit(); + _ = response.body.value.toReadableStream(globalThis); + if (locked.readable.get()) |readable| { + if (readable.isDisturbed(globalThis)) { + destination_blob.detach(); + return globalThis.throwInvalidArguments("ReadableStream has already been used", .{}); + } + const proxy = globalThis.bunVM().transpiler.env.getHttpProxy(true, null); + const proxy_url = if (proxy) |p| p.href else null; + + return (if (options.extra_options != null) aws_options.credentials.dupe() else s3.getCredentials()).s3UploadStream(s3.path(), readable, globalThis, aws_options.options, destination_blob.contentTypeOrMimeType(), proxy_url, null, undefined); + } + destination_blob.detach(); + return globalThis.throwInvalidArguments("ReadableStream has already been used", .{}); + } var task = bun.new(WriteFileWaitFromLockedValueTask, .{ .globalThis = globalThis, .file_blob = destination_blob, .promise = JSC.JSPromise.Strong.init(globalThis), - .mkdirp_if_not_exists = mkdirp_if_not_exists orelse true, + .mkdirp_if_not_exists = options.mkdirp_if_not_exists orelse true, }); response.body.value.Locked.task = task; @@ -1171,12 +1322,29 @@ pub const Blob = struct { _ = request.body.value.use(); return JSC.JSPromise.rejectedPromiseValue(globalThis, err_ref.toJS(globalThis)); }, - .Locked => { + .Locked => |locked| { + if (destination_blob.isS3()) { + const s3 = &destination_blob.store.?.data.s3; + var aws_options = try s3.getCredentialsWithOptions(options.extra_options, globalThis); + defer aws_options.deinit(); + _ = request.body.value.toReadableStream(globalThis); + if (locked.readable.get()) |readable| { + if (readable.isDisturbed(globalThis)) { + destination_blob.detach(); + return globalThis.throwInvalidArguments("ReadableStream has already been used", .{}); + } + const proxy = globalThis.bunVM().transpiler.env.getHttpProxy(true, null); + const proxy_url = if (proxy) |p| p.href else null; + return (if (options.extra_options != null) aws_options.credentials.dupe() else s3.getCredentials()).s3UploadStream(s3.path(), readable, globalThis, aws_options.options, destination_blob.contentTypeOrMimeType(), proxy_url, null, undefined); + } + destination_blob.detach(); + return globalThis.throwInvalidArguments("ReadableStream has already been used", .{}); + } var task = bun.new(WriteFileWaitFromLockedValueTask, .{ .globalThis = globalThis, .file_blob = destination_blob, .promise = JSC.JSPromise.Strong.init(globalThis), - .mkdirp_if_not_exists = mkdirp_if_not_exists orelse true, + .mkdirp_if_not_exists = options.mkdirp_if_not_exists orelse true, }); request.body.value.Locked.task = task; @@ -1212,7 +1380,42 @@ pub const Blob = struct { } } - return writeFileWithSourceDestination(globalThis, &source_blob, &destination_blob, mkdirp_if_not_exists orelse true); + return writeFileWithSourceDestination(globalThis, &source_blob, &destination_blob, options); + } + pub fn writeFile(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { + const arguments = callframe.arguments_old(3).slice(); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args.deinit(); + + // accept a path or a blob + var path_or_blob = try PathOrBlob.fromJSNoCopy(globalThis, &args); + defer { + if (path_or_blob == .path) { + path_or_blob.path.deinit(); + } + } + + const data = args.nextEat() orelse { + return globalThis.throwInvalidArguments("Bun.write(pathOrFdOrBlob, blob) expects a Blob-y thing to write", .{}); + }; + var mkdirp_if_not_exists: ?bool = null; + const options = args.nextEat(); + if (options) |options_object| { + if (options_object.isObject()) { + if (try options_object.getTruthy(globalThis, "createPath")) |create_directory| { + if (!create_directory.isBoolean()) { + return globalThis.throwInvalidArgumentType("write", "options.createPath", "boolean"); + } + mkdirp_if_not_exists = create_directory.toBoolean(); + } + } else if (!options_object.isEmptyOrUndefinedOrNull()) { + return globalThis.throwInvalidArgumentType("write", "options", "object"); + } + } + return writeFileInternal(globalThis, &path_or_blob, data, .{ + .mkdirp_if_not_exists = mkdirp_if_not_exists, + .extra_options = options, + }); } const write_permissions = 0o664; @@ -1391,12 +1594,268 @@ pub const Blob = struct { return JSC.JSPromise.resolvedPromiseValue(globalThis, JSC.JSValue.jsNumber(written)); } + pub fn JSS3File_upload_(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { + const arguments = callframe.arguments_old(3).slice(); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args.deinit(); + + // accept a path or a blob + var path_or_blob = try PathOrBlob.fromJSNoCopy(globalThis, &args); + errdefer { + if (path_or_blob == .path) { + path_or_blob.path.deinit(); + } + } + + if (path_or_blob == .blob and (path_or_blob.blob.store == null or path_or_blob.blob.store.?.data != .s3)) { + return globalThis.throwInvalidArguments("S3.upload(pathOrS3, blob) expects a S3 or path to upload", .{}); + } + + const data = args.nextEat() orelse { + return globalThis.throwInvalidArguments("S3.upload(pathOrS3, blob) expects a Blob-y thing to upload", .{}); + }; + + switch (path_or_blob) { + .path => |path| { + const options = args.nextEat(); + if (path == .fd) { + return globalThis.throwInvalidArguments("S3.upload(pathOrS3, blob) expects a S3 or path to upload", .{}); + } + var blob = try constructS3FileInternalStore(globalThis, path.path, options); + defer blob.deinit(); + + var blob_internal: PathOrBlob = .{ .blob = blob }; + return try writeFileInternal(globalThis, &blob_internal, data, .{ + .mkdirp_if_not_exists = false, + .extra_options = options, + }); + }, + .blob => return try writeFileInternal(globalThis, &path_or_blob, data, .{ + .mkdirp_if_not_exists = false, + .extra_options = args.nextEat(), + }), + } + } + + pub fn JSS3File_size_(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { + const arguments = callframe.arguments_old(3).slice(); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args.deinit(); + + // accept a path or a blob + var path_or_blob = try PathOrBlob.fromJSNoCopy(globalThis, &args); + errdefer { + if (path_or_blob == .path) { + path_or_blob.path.deinit(); + } + } + + if (path_or_blob == .blob and (path_or_blob.blob.store == null or path_or_blob.blob.store.?.data != .s3)) { + return globalThis.throwInvalidArguments("S3.size(pathOrS3) expects a S3 or path to get size", .{}); + } + + switch (path_or_blob) { + .path => |path| { + const options = args.nextEat(); + if (path == .fd) { + return globalThis.throwInvalidArguments("S3.size(pathOrS3) expects a S3 or path to get size", .{}); + } + var blob = try constructS3FileInternalStore(globalThis, path.path, options); + defer blob.deinit(); + + return S3BlobStatTask.size(globalThis, &blob); + }, + .blob => |*blob| { + return getSize(blob, globalThis); + }, + } + } + pub fn JSS3File_exists_(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { + const arguments = callframe.arguments_old(3).slice(); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args.deinit(); + + // accept a path or a blob + var path_or_blob = try PathOrBlob.fromJSNoCopy(globalThis, &args); + errdefer { + if (path_or_blob == .path) { + path_or_blob.path.deinit(); + } + } + + if (path_or_blob == .blob and (path_or_blob.blob.store == null or path_or_blob.blob.store.?.data != .s3)) { + return globalThis.throwInvalidArguments("S3.exists(pathOrS3) expects a S3 or path to check if it exists", .{}); + } + + switch (path_or_blob) { + .path => |path| { + const options = args.nextEat(); + if (path == .fd) { + return globalThis.throwInvalidArguments("S3.exists(pathOrS3) expects a S3 or path to check if it exists", .{}); + } + var blob = try constructS3FileInternalStore(globalThis, path.path, options); + defer blob.deinit(); + + return S3BlobStatTask.exists(globalThis, &blob); + }, + .blob => |*blob| { + return getExists(blob, globalThis, callframe); + }, + } + } + + pub export fn JSS3File__exists(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) JSValue { + return JSS3File_exists_(globalThis, callframe) catch |err| switch (err) { + error.JSError => .zero, + error.OutOfMemory => { + globalThis.throwOutOfMemory() catch {}; + return .zero; + }, + }; + } + pub export fn JSS3File__size(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) JSValue { + return JSS3File_size_(globalThis, callframe) catch |err| switch (err) { + error.JSError => .zero, + error.OutOfMemory => { + globalThis.throwOutOfMemory() catch {}; + return .zero; + }, + }; + } + pub export fn JSS3File__upload(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) JSValue { + return JSS3File_upload_(globalThis, callframe) catch |err| switch (err) { + error.JSError => .zero, + error.OutOfMemory => { + globalThis.throwOutOfMemory() catch {}; + return .zero; + }, + }; + } + pub fn JSS3File_presign_(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { + const arguments = callframe.arguments_old(3).slice(); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args.deinit(); + + // accept a path or a blob + var path_or_blob = try PathOrBlob.fromJSNoCopy(globalThis, &args); + errdefer { + if (path_or_blob == .path) { + path_or_blob.path.deinit(); + } + } + + if (path_or_blob == .blob and (path_or_blob.blob.store == null or path_or_blob.blob.store.?.data != .s3)) { + return globalThis.throwInvalidArguments("S3.presign(pathOrS3, options) expects a S3 or path to presign", .{}); + } + + switch (path_or_blob) { + .path => |path| { + if (path == .fd) { + return globalThis.throwInvalidArguments("S3.presign(pathOrS3, options) expects a S3 or path to presign", .{}); + } + const options = args.nextEat(); + var blob = try constructS3FileInternalStore(globalThis, path.path, options); + defer blob.deinit(); + return try getPresignUrlFrom(&blob, globalThis, options); + }, + .blob => return try getPresignUrlFrom(&path_or_blob.blob, globalThis, args.nextEat()), + } + } + + pub export fn JSS3File__presign(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) JSValue { + return JSS3File_presign_(globalThis, callframe) catch |err| switch (err) { + error.JSError => .zero, + error.OutOfMemory => { + globalThis.throwOutOfMemory() catch {}; + return .zero; + }, + }; + } + pub fn JSS3File_unlink_(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { + const arguments = callframe.arguments_old(3).slice(); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args.deinit(); + + // accept a path or a blob + var path_or_blob = try PathOrBlob.fromJSNoCopy(globalThis, &args); + errdefer { + if (path_or_blob == .path) { + path_or_blob.path.deinit(); + } + } + if (path_or_blob == .blob and (path_or_blob.blob.store == null or path_or_blob.blob.store.?.data != .s3)) { + return globalThis.throwInvalidArguments("S3.unlink(pathOrS3) expects a S3 or path to delete", .{}); + } + + switch (path_or_blob) { + .path => |path| { + if (path == .fd) { + return globalThis.throwInvalidArguments("S3.unlink(pathOrS3) expects a S3 or path to delete", .{}); + } + const options = args.nextEat(); + var blob = try constructS3FileInternalStore(globalThis, path.path, options); + defer blob.deinit(); + return try blob.store.?.data.s3.unlink(globalThis, options); + }, + .blob => |blob| { + return try blob.store.?.data.s3.unlink(globalThis, args.nextEat()); + }, + } + } + + pub export fn JSS3File__unlink(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) JSValue { + return JSS3File_unlink_(globalThis, callframe) catch |err| switch (err) { + error.JSError => .zero, + error.OutOfMemory => { + globalThis.throwOutOfMemory() catch {}; + return .zero; + }, + }; + } + pub export fn JSS3File__hasInstance(_: JSC.JSValue, _: *JSC.JSGlobalObject, value: JSC.JSValue) callconv(JSC.conv) bool { + JSC.markBinding(@src()); + const blob = value.as(Blob) orelse return false; + return blob.isS3(); + } + pub export fn JSDOMFile__hasInstance(_: JSC.JSValue, _: *JSC.JSGlobalObject, value: JSC.JSValue) callconv(JSC.conv) bool { JSC.markBinding(@src()); const blob = value.as(Blob) orelse return false; return blob.is_jsdom_file; } + extern fn BUN__createJSS3FileConstructor(*JSC.JSGlobalObject) JSValue; + pub fn getJSS3FileConstructor( + globalObject: *JSC.JSGlobalObject, + _: *JSC.JSObject, + ) callconv(JSC.conv) JSValue { + return BUN__createJSS3FileConstructor(globalObject); + } + export fn JSS3File__construct(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) ?*Blob { + const vm = globalThis.bunVM(); + const arguments = callframe.arguments_old(2).slice(); + var args = JSC.Node.ArgumentsSlice.init(vm, arguments); + defer args.deinit(); + + const path_or_fd = (JSC.Node.PathLike.fromJS(globalThis, &args)) catch |err| switch (err) { + error.JSError => null, + error.OutOfMemory => { + globalThis.throwOutOfMemory() catch {}; + return null; + }, + }; + if (path_or_fd == null) { + globalThis.throwInvalidArguments("Expected file path string", .{}) catch return null; + return null; + } + return constructS3FileInternal(globalThis, path_or_fd.?, args.nextEat()) catch |err| switch (err) { + error.JSError => null, + error.OutOfMemory => { + globalThis.throwOutOfMemory() catch {}; + return null; + }, + }; + } export fn JSDOMFile__construct(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) ?*Blob { return JSDOMFile__construct_(globalThis, callframe) catch |err| switch (err) { error.JSError => null, @@ -1431,7 +1890,6 @@ pub const Blob = struct { return globalThis.throwInvalidArguments("new Blob() expects an Array", .{}); }, }; - if (blob.store) |store_| { switch (store_.data) { .bytes => |*bytes| { @@ -1439,7 +1897,7 @@ pub const Blob = struct { (name_value_str.toUTF8WithoutRef(bun.default_allocator).clone(bun.default_allocator) catch unreachable).slice(), ); }, - .file => { + .s3, .file => { blob.name = name_value_str.dupeRef(); }, } @@ -1516,6 +1974,7 @@ pub const Blob = struct { store.data.bytes.len; }, .file => size += store.data.file.pathlike.estimatedSize(), + .s3 => size += store.data.s3.estimatedSize(), } } @@ -1532,6 +1991,63 @@ pub const Blob = struct { } } + fn constructS3FileInternalStore( + globalObject: *JSC.JSGlobalObject, + path: JSC.Node.PathLike, + options: ?JSC.JSValue, + ) bun.JSError!Blob { + + // get ENV config + var aws_options = try AWS.getCredentialsWithOptions(globalObject.bunVM().transpiler.env.getAWSCredentials(), options, globalObject); + defer aws_options.deinit(); + const store = Blob.Store.initS3(path, null, aws_options.credentials, bun.default_allocator) catch bun.outOfMemory(); + errdefer store.deinit(); + store.data.s3.options = aws_options.options; + + var blob = Blob.initWithStore(store, globalObject); + if (options) |opts| { + if (try opts.getTruthy(globalObject, "type")) |file_type| { + inner: { + if (file_type.isString()) { + var allocator = bun.default_allocator; + var str = file_type.toSlice(globalObject, bun.default_allocator); + defer str.deinit(); + const slice = str.slice(); + if (!strings.isAllASCII(slice)) { + break :inner; + } + blob.content_type_was_set = true; + if (globalObject.bunVM().mimeType(str.slice())) |entry| { + blob.content_type = entry.value; + break :inner; + } + const content_type_buf = allocator.alloc(u8, slice.len) catch bun.outOfMemory(); + blob.content_type = strings.copyLowercase(slice, content_type_buf); + blob.content_type_allocated = true; + } + } + } + } + return blob; + } + fn constructS3FileInternal( + globalObject: *JSC.JSGlobalObject, + path: JSC.Node.PathLike, + options: ?JSC.JSValue, + ) bun.JSError!*Blob { + var ptr = Blob.new(try constructS3FileInternalStore(globalObject, path, options)); + ptr.allocator = bun.default_allocator; + return ptr; + } + fn constructS3FileInternalJS( + globalObject: *JSC.JSGlobalObject, + path: JSC.Node.PathLike, + options: ?JSC.JSValue, + ) bun.JSError!JSC.JSValue { + var ptr = try constructS3FileInternal(globalObject, path, options); + return ptr.toJS(globalObject); + } + pub fn constructBunFile( globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, @@ -1544,13 +2060,18 @@ pub const Blob = struct { var path = (try JSC.Node.PathOrFileDescriptor.fromJS(globalObject, &args, bun.default_allocator)) orelse { return globalObject.throwInvalidArguments("Expected file path string or file descriptor", .{}); }; + const options = if (arguments.len >= 2) arguments[1] else null; + + if (path == .path) { + if (strings.startsWith(path.path.slice(), "s3://")) { + return try constructS3FileInternalJS(globalObject, path.path, options); + } + } defer path.deinitAndUnprotect(); - var blob = Blob.findOrCreateFileFromPath(&path, globalObject); - - if (arguments.len >= 2) { - const opts = arguments[1]; + var blob = Blob.findOrCreateFileFromPath(&path, globalObject, false); + if (options) |opts| { if (opts.isObject()) { if (try opts.getTruthy(globalObject, "type")) |file_type| { inner: { @@ -1584,10 +2105,34 @@ pub const Blob = struct { return ptr.toJS(globalObject); } - pub fn findOrCreateFileFromPath(path_or_fd: *JSC.Node.PathOrFileDescriptor, globalThis: *JSGlobalObject) Blob { + pub fn constructS3File( + globalObject: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, + ) bun.JSError!JSC.JSValue { + const vm = globalObject.bunVM(); + const arguments = callframe.arguments_old(2).slice(); + var args = JSC.Node.ArgumentsSlice.init(vm, arguments); + defer args.deinit(); + + const path = (try JSC.Node.PathLike.fromJS(globalObject, &args)) orelse { + return globalObject.throwInvalidArguments("Expected file path string", .{}); + }; + return constructS3FileInternalJS(globalObject, path, args.nextEat()); + } + + pub fn findOrCreateFileFromPath(path_or_fd: *JSC.Node.PathOrFileDescriptor, globalThis: *JSGlobalObject, comptime check_s3: bool) Blob { var vm = globalThis.bunVM(); const allocator = bun.default_allocator; - + if (check_s3) { + if (path_or_fd.* == .path) { + if (strings.startsWith(path_or_fd.path.slice(), "s3://")) { + const credentials = globalThis.bunVM().transpiler.env.getAWSCredentials(); + const copy = path_or_fd.*; + path_or_fd.* = .{ .path = .{ .string = bun.PathString.empty } }; + return Blob.initWithStore(Blob.Store.initS3(copy.path, null, credentials, allocator) catch bun.outOfMemory(), globalThis); + } + } + } const path: JSC.Node.PathOrFileDescriptor = brk: { switch (path_or_fd.*) { .path => { @@ -1659,13 +2204,14 @@ pub const Blob = struct { return if (this.hasOneRef()) @sizeOf(@This()) + switch (this.data) { .bytes => this.data.bytes.len, .file => 0, + .s3 => |s3| s3.estimatedSize(), } else 0; } pub fn size(this: *const Store) SizeType { return switch (this.data) { .bytes => this.data.bytes.len, - .file => Blob.max_size, + .s3, .file => Blob.max_size, }; } @@ -1674,6 +2220,7 @@ pub const Blob = struct { pub const Data = union(enum) { bytes: ByteStore, file: FileStore, + s3: S3Store, }; pub fn ref(this: *Store) void { @@ -1702,6 +2249,34 @@ pub const Blob = struct { this.deref(); } + pub fn initS3(pathlike: JSC.Node.PathLike, mime_type: ?http.MimeType, credentials: AWSCredentials, allocator: std.mem.Allocator) !*Store { + var path = pathlike; + // this actually protects/refs the pathlike + path.toThreadSafe(); + + const store = Blob.Store.new(.{ + .data = .{ + .s3 = S3Store.init( + path, + mime_type orelse brk: { + const sliced = path.slice(); + if (sliced.len > 0) { + var extname = std.fs.path.extension(sliced); + extname = std.mem.trim(u8, extname, "."); + if (http.MimeType.byExtensionNoDefault(extname)) |mime| { + break :brk mime; + } + } + break :brk null; + }, + credentials, + ), + }, + .allocator = allocator, + .ref_count = std.atomic.Value(u32).init(1), + }); + return store; + } pub fn initFile(pathlike: JSC.Node.PathOrFileDescriptor, mime_type: ?http.MimeType, allocator: std.mem.Allocator) !*Store { const store = Blob.Store.new(.{ .data = .{ @@ -1771,6 +2346,9 @@ pub const Blob = struct { } } }, + .s3 => |*s3| { + s3.deinit(allocator); + }, } this.destroy(); @@ -1799,6 +2377,14 @@ pub const Blob = struct { }, } }, + .s3 => |s3| { + const pathlike_tag: JSC.Node.PathOrFileDescriptor.SerializeTag = .path; + try writer.writeInt(u8, @intFromEnum(pathlike_tag), .little); + + const path_slice = s3.pathlike.slice(); + try writer.writeInt(u32, @as(u32, @truncate(path_slice.len)), .little); + try writer.writeAll(path_slice); + }, .bytes => |bytes| { const slice = bytes.slice(); try writer.writeInt(u32, @truncate(slice.len), .little); @@ -3153,6 +3739,17 @@ pub const Blob = struct { // milliseconds since ECMAScript epoch last_modified: JSC.JSTimeType = JSC.init_timestamp, + pub fn unlink(this: *const FileStore, globalThis: *JSC.JSGlobalObject) JSValue { + return switch (this.pathlike) { + .path => switch (globalThis.bunVM().nodeFS().unlink(.{ + .path = this.pathlike.path, + }, .sync)) { + .err => |err| JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)), + else => JSC.JSPromise.resolvedPromiseValue(globalThis, .true), + }, + .fd => JSC.JSPromise.resolvedPromiseValue(globalThis, globalThis.createInvalidArgs("Is not possible to unlink a file descriptor", .{})), + }; + } pub fn isSeekable(this: *const FileStore) ?bool { if (this.seekable) |seekable| { return seekable; @@ -3170,6 +3767,105 @@ pub const Blob = struct { } }; + pub const S3Store = struct { + pathlike: JSC.Node.PathLike, + mime_type: http.MimeType = http.MimeType.other, + credentials: ?*AWSCredentials, + options: S3MultiPartUpload.MultiPartUploadOptions = .{}, + pub fn isSeekable(_: *const @This()) ?bool { + return true; + } + + pub fn getCredentials(this: *const @This()) *AWSCredentials { + bun.assert(this.credentials != null); + return this.credentials.?; + } + + pub fn getCredentialsWithOptions(this: *const @This(), options: ?JSValue, globalObject: *JSC.JSGlobalObject) bun.JSError!AWS.AWSCredentialsWithOptions { + return AWS.getCredentialsWithOptions(this.getCredentials().*, options, globalObject); + } + + pub fn path(this: *@This()) []const u8 { + var path_name = bun.URL.parse(this.pathlike.slice()).s3Path(); + // normalize start and ending + if (strings.endsWith(path_name, "/")) { + path_name = path_name[0..path_name.len]; + } + if (strings.startsWith(path_name, "/")) { + path_name = path_name[1..]; + } + return path_name; + } + + pub fn unlink(this: *@This(), globalThis: *JSC.JSGlobalObject, extra_options: ?JSValue) bun.JSError!JSValue { + const Wrapper = struct { + promise: JSC.JSPromise.Strong, + + pub usingnamespace bun.New(@This()); + + pub fn resolve(result: AWS.S3DeleteResult, self: *@This()) void { + defer self.deinit(); + const globalObject = self.promise.globalObject().?; + switch (result) { + .success => { + self.promise.resolve(globalObject, .true); + }, + .not_found => { + const js_err = globalObject.createErrorInstance("File not found", .{}); + js_err.put(globalObject, ZigString.static("code"), ZigString.init("FileNotFound").toJS(globalObject)); + self.promise.reject(globalObject, js_err); + }, + .failure => |err| { + self.promise.rejectOnNextTick(globalObject, err.toJS(globalObject)); + }, + } + } + + fn deinit(self: *@This()) void { + self.promise.deinit(); + self.destroy(); + } + }; + const promise = JSC.JSPromise.Strong.init(globalThis); + const value = promise.value(); + const proxy_url = globalThis.bunVM().transpiler.env.getHttpProxy(true, null); + const proxy = if (proxy_url) |url| url.href else null; + var aws_options = try this.getCredentialsWithOptions(extra_options, globalThis); + defer aws_options.deinit(); + aws_options.credentials.s3Delete(this.path(), @ptrCast(&Wrapper.resolve), Wrapper.new(.{ + .promise = promise, + }), proxy); + + return value; + } + + pub fn init(pathlike: JSC.Node.PathLike, mime_type: ?http.MimeType, credentials: AWSCredentials) S3Store { + return .{ + .credentials = credentials.dupe(), + .pathlike = pathlike, + .mime_type = mime_type orelse http.MimeType.other, + }; + } + pub fn estimatedSize(this: *const @This()) usize { + return this.pathlike.estimatedSize() + if (this.credentials) |credentials| credentials.estimatedSize() else 0; + } + + pub fn deinit(this: *@This(), allocator: std.mem.Allocator) void { + if (this.pathlike == .string) { + allocator.free(@constCast(this.pathlike.slice())); + } else { + this.pathlike.deinit(); + } + this.pathlike = .{ + .string = bun.PathString.empty, + }; + if (this.credentials) |credentials| { + credentials.deref(); + this.credentials = null; + } + } + }; + pub const ByteStore = struct { ptr: [*]u8 = undefined, len: SizeType = 0, @@ -3430,15 +4126,531 @@ pub const Blob = struct { return JSValue.jsBoolean(bun.isRegularFile(store.data.file.mode) or bun.C.S.ISFIFO(store.data.file.mode)); } + pub fn isS3(this: *const Blob) bool { + if (this.store) |store| { + return store.data == .s3; + } + return false; + } + + const S3BlobDownloadTask = struct { + blob: Blob, + globalThis: *JSC.JSGlobalObject, + promise: JSC.JSPromise.Strong, + poll_ref: bun.Async.KeepAlive = .{}, + + handler: S3ReadHandler, + usingnamespace bun.New(S3BlobDownloadTask); + pub const S3ReadHandler = *const fn (this: *Blob, globalthis: *JSGlobalObject, raw_bytes: []u8) JSValue; + + pub fn callHandler(this: *S3BlobDownloadTask, raw_bytes: []u8) JSValue { + return this.handler(&this.blob, this.globalThis, raw_bytes); + } + pub fn onS3DownloadResolved(result: AWS.S3DownloadResult, this: *S3BlobDownloadTask) void { + defer this.deinit(); + switch (result) { + .success => |response| { + const bytes = response.body.list.items; + if (this.blob.size == Blob.max_size) { + this.blob.size = @truncate(bytes.len); + } + JSC.AnyPromise.wrap(.{ .normal = this.promise.get() }, this.globalThis, S3BlobDownloadTask.callHandler, .{ this, bytes }); + }, + .not_found => { + const js_err = this.globalThis.createErrorInstance("File not found", .{}); + js_err.put(this.globalThis, ZigString.static("code"), ZigString.init("FileNotFound").toJS(this.globalThis)); + this.promise.reject(this.globalThis, js_err); + }, + .failure => |err| { + this.promise.rejectOnNextTick(this.globalThis, err.toJS(this.globalThis)); + }, + } + } + + pub fn init(globalThis: *JSC.JSGlobalObject, blob: *Blob, handler: S3BlobDownloadTask.S3ReadHandler) JSValue { + blob.store.?.ref(); + + const this = S3BlobDownloadTask.new(.{ + .globalThis = globalThis, + .blob = blob.*, + .promise = JSC.JSPromise.Strong.init(globalThis), + .handler = handler, + }); + const promise = this.promise.value(); + const env = this.globalThis.bunVM().transpiler.env; + const credentials = this.blob.store.?.data.s3.getCredentials(); + const path = this.blob.store.?.data.s3.path(); + + this.poll_ref.ref(globalThis.bunVM()); + if (blob.offset > 0) { + const len: ?usize = if (blob.size != Blob.max_size) @intCast(blob.size) else null; + const offset: usize = @intCast(blob.offset); + credentials.s3DownloadSlice(path, offset, len, @ptrCast(&S3BlobDownloadTask.onS3DownloadResolved), this, if (env.getHttpProxy(true, null)) |proxy| proxy.href else null); + } else if (blob.size == Blob.max_size) { + credentials.s3Download(path, @ptrCast(&S3BlobDownloadTask.onS3DownloadResolved), this, if (env.getHttpProxy(true, null)) |proxy| proxy.href else null); + } else { + const len: usize = @intCast(blob.size); + const offset: usize = @intCast(blob.offset); + credentials.s3DownloadSlice(path, offset, len, @ptrCast(&S3BlobDownloadTask.onS3DownloadResolved), this, if (env.getHttpProxy(true, null)) |proxy| proxy.href else null); + } + return promise; + } + + pub fn deinit(this: *S3BlobDownloadTask) void { + this.blob.store.?.deref(); + this.poll_ref.unrefOnNextTick(this.globalThis.bunVM()); + this.promise.deinit(); + this.destroy(); + } + }; + + const S3BlobStatTask = struct { + promise: JSC.JSPromise.Strong, + usingnamespace bun.New(S3BlobStatTask); + + pub fn onS3ExistsResolved(result: AWS.S3StatResult, this: *S3BlobStatTask) void { + defer this.deinit(); + const globalThis = this.promise.globalObject().?; + switch (result) { + .not_found => { + this.promise.resolve(globalThis, .false); + }, + .success => |_| { + // calling .exists() should not prevent it to download a bigger file + // this would make it download a slice of the actual value, if the file changes before we download it + // if (this.blob.size == Blob.max_size) { + // this.blob.size = @truncate(stat.size); + // } + this.promise.resolve(globalThis, .true); + }, + .failure => |err| { + this.promise.rejectOnNextTick(globalThis, err.toJS(globalThis)); + }, + } + } + + pub fn onS3SizeResolved(result: AWS.S3StatResult, this: *S3BlobStatTask) void { + defer this.deinit(); + const globalThis = this.promise.globalObject().?; + + switch (result) { + .not_found => { + const js_err = globalThis.createErrorInstance("File not Found", .{}); + js_err.put(globalThis, ZigString.static("code"), ZigString.static("FileNotFound").toJS(globalThis)); + this.promise.rejectOnNextTick(globalThis, js_err); + }, + .success => |stat| { + this.promise.resolve(globalThis, JSValue.jsNumber(stat.size)); + }, + .failure => |err| { + this.promise.rejectOnNextTick(globalThis, err.toJS(globalThis)); + }, + } + } + + pub fn exists(globalThis: *JSC.JSGlobalObject, blob: *Blob) JSValue { + const this = S3BlobStatTask.new(.{ + .promise = JSC.JSPromise.Strong.init(globalThis), + }); + const promise = this.promise.value(); + const credentials = blob.store.?.data.s3.getCredentials(); + const path = blob.store.?.data.s3.path(); + const env = globalThis.bunVM().transpiler.env; + + credentials.s3Stat(path, @ptrCast(&S3BlobStatTask.onS3ExistsResolved), this, if (env.getHttpProxy(true, null)) |proxy| proxy.href else null); + return promise; + } + + pub fn size(globalThis: *JSC.JSGlobalObject, blob: *Blob) JSValue { + const this = S3BlobStatTask.new(.{ + .promise = JSC.JSPromise.Strong.init(globalThis), + }); + const promise = this.promise.value(); + const credentials = blob.store.?.data.s3.getCredentials(); + const path = blob.store.?.data.s3.path(); + const env = globalThis.bunVM().transpiler.env; + + credentials.s3Stat(path, @ptrCast(&S3BlobStatTask.onS3SizeResolved), this, if (env.getHttpProxy(true, null)) |proxy| proxy.href else null); + return promise; + } + + pub fn deinit(this: *S3BlobStatTask) void { + this.promise.deinit(); + this.destroy(); + } + }; + + pub fn doWrite(this: *Blob, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { + const arguments = callframe.arguments_old(3).slice(); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args.deinit(); + + const data = args.nextEat() orelse { + return globalThis.throwInvalidArguments("blob.write(pathOrFdOrBlob, blob) expects a Blob-y thing to write", .{}); + }; + if (data.isEmptyOrUndefinedOrNull()) { + return globalThis.throwInvalidArguments("blob.write(pathOrFdOrBlob, blob) expects a Blob-y thing to write", .{}); + } + var mkdirp_if_not_exists: ?bool = null; + const options = args.nextEat(); + if (options) |options_object| { + if (options_object.isObject()) { + if (try options_object.getTruthy(globalThis, "createPath")) |create_directory| { + if (!create_directory.isBoolean()) { + return globalThis.throwInvalidArgumentType("write", "options.createPath", "boolean"); + } + mkdirp_if_not_exists = create_directory.toBoolean(); + } + if (try options_object.getTruthy(globalThis, "type")) |content_type| { + //override the content type + if (!content_type.isString()) { + return globalThis.throwInvalidArgumentType("write", "options.type", "string"); + } + var content_type_str = content_type.toSlice(globalThis, bun.default_allocator); + defer content_type_str.deinit(); + const slice = content_type_str.slice(); + if (strings.isAllASCII(slice)) { + if (this.content_type_allocated) { + bun.default_allocator.free(this.content_type); + } + this.content_type_was_set = true; + + if (globalThis.bunVM().mimeType(slice)) |mime| { + this.content_type = mime.value; + } else { + const content_type_buf = bun.default_allocator.alloc(u8, slice.len) catch bun.outOfMemory(); + this.content_type = strings.copyLowercase(slice, content_type_buf); + this.content_type_allocated = true; + } + } + } + } else if (!options_object.isEmptyOrUndefinedOrNull()) { + return globalThis.throwInvalidArgumentType("write", "options", "object"); + } + } + var blob_internal: PathOrBlob = .{ .blob = this.* }; + return writeFileInternal(globalThis, &blob_internal, data, .{ .mkdirp_if_not_exists = mkdirp_if_not_exists, .extra_options = options }); + } + + pub fn doUnlink(this: *Blob, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { + const arguments = callframe.arguments_old(1).slice(); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args.deinit(); + const store = this.store orelse { + return JSC.JSPromise.resolvedPromiseValue(globalThis, globalThis.createInvalidArgs("Blob is detached", .{})); + }; + return switch (store.data) { + .s3 => |*s3| try s3.unlink(globalThis, args.nextEat()), + .file => |file| file.unlink(globalThis), + else => JSC.JSPromise.resolvedPromiseValue(globalThis, globalThis.createInvalidArgs("Blob is read-only", .{})), + }; + } + // This mostly means 'can it be read?' pub fn getExists( this: *Blob, globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame, ) bun.JSError!JSValue { + if (this.isS3()) { + return S3BlobStatTask.exists(globalThis, this); + } return JSC.JSPromise.resolvedPromiseValue(globalThis, this.getExistsSync()); } + pub fn getPresignUrlFrom(this: *Blob, globalThis: *JSC.JSGlobalObject, extra_options: ?JSValue) bun.JSError!JSValue { + if (this.isS3()) { + var method: bun.http.Method = .GET; + var expires: usize = 86400; // 1 day default + + var credentialsWithOptions: AWS.AWSCredentialsWithOptions = .{ + .credentials = this.store.?.data.s3.getCredentials().*, + }; + defer { + credentialsWithOptions.deinit(); + } + if (extra_options) |options| { + if (options.isObject()) { + if (try options.getTruthyComptime(globalThis, "method")) |method_| { + method = Method.fromJS(globalThis, method_) orelse { + return globalThis.throwInvalidArguments("method must be GET, PUT, DELETE or HEAD when using s3 protocol", .{}); + }; + } + if (try options.getOptional(globalThis, "expiresIn", i32)) |expires_| { + if (expires_ <= 0) return globalThis.throwInvalidArguments("expiresIn must be greather than 0", .{}); + expires = @intCast(expires_); + } + } + credentialsWithOptions = try this.store.?.data.s3.getCredentialsWithOptions(options, globalThis); + } + const path = this.store.?.data.s3.path(); + + const result = credentialsWithOptions.credentials.signRequest(.{ + .path = path, + .method = method, + }, .{ .expires = expires }) catch |sign_err| { + return AWS.throwSignError(sign_err, globalThis); + }; + defer result.deinit(); + var str = bun.String.fromUTF8(result.url); + return str.transferToJS(this.globalThis); + } + + return globalThis.throwError(error.NotSupported, "is only possible to presign s3:// files"); + } + + pub fn getPresignUrl(this: *Blob, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { + const args = callframe.arguments_old(1); + return getPresignUrlFrom(this, globalThis, if (args.len > 0) args.ptr[0] else null); + } + + pub const FileStreamWrapper = struct { + promise: JSC.JSPromise.Strong, + readable_stream_ref: JSC.WebCore.ReadableStream.Strong, + sink: *JSC.WebCore.FileSink, + + pub usingnamespace bun.New(@This()); + + pub fn deinit(this: *@This()) void { + this.promise.deinit(); + this.readable_stream_ref.deinit(); + this.sink.deref(); + this.destroy(); + } + }; + + pub const shim = JSC.Shimmer("Bun", "FileStreamWrapper", @This()); + pub fn onFileStreamResolveRequestStream(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { + var args = callframe.arguments_old(2); + var this = args.ptr[args.len - 1].asPromisePtr(FileStreamWrapper); + defer this.deinit(); + if (this.readable_stream_ref.get()) |stream| { + stream.done(globalThis); + } + this.readable_stream_ref.deinit(); + this.promise.resolve(globalThis, JSC.JSValue.jsNumber(0)); + return .undefined; + } + + pub fn onFileStreamRejectRequestStream(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { + const args = callframe.arguments_old(2); + var this = args.ptr[args.len - 1].asPromisePtr(FileStreamWrapper); + defer this.sink.deinit(); + const err = args.ptr[0]; + + this.promise.rejectOnNextTick(globalThis, err); + + if (this.readable_stream_ref.get()) |stream| { + stream.cancel(globalThis); + this.readable_stream_ref.deinit(); + } + return .undefined; + } + pub const Export = shim.exportFunctions(.{ + .onResolveRequestStream = onFileStreamResolveRequestStream, + .onRejectRequestStream = onFileStreamRejectRequestStream, + }); + comptime { + const jsonResolveRequestStream = JSC.toJSHostFunction(onFileStreamResolveRequestStream); + @export(jsonResolveRequestStream, .{ .name = Export[0].symbol_name }); + const jsonRejectRequestStream = JSC.toJSHostFunction(onFileStreamRejectRequestStream); + @export(jsonRejectRequestStream, .{ .name = Export[1].symbol_name }); + } + pub fn pipeReadableStreamToBlob(this: *Blob, globalThis: *JSC.JSGlobalObject, readable_stream: JSC.WebCore.ReadableStream, extra_options: ?JSValue) JSC.JSValue { + var store = this.store orelse { + return JSC.JSPromise.rejectedPromiseValue(globalThis, globalThis.createErrorInstance("Blob is detached", .{})); + }; + + if (this.isS3()) { + const s3 = &this.store.?.data.s3; + var aws_options = s3.getCredentialsWithOptions(extra_options, globalThis) catch |err| { + return JSC.JSPromise.rejectedPromiseValue(globalThis, globalThis.takeException(err)); + }; + defer aws_options.deinit(); + + const path = s3.path(); + const proxy = globalThis.bunVM().transpiler.env.getHttpProxy(true, null); + const proxy_url = if (proxy) |p| p.href else null; + + return (if (extra_options != null) aws_options.credentials.dupe() else s3.getCredentials()).s3UploadStream(path, readable_stream, globalThis, aws_options.options, this.contentTypeOrMimeType(), proxy_url, null, undefined); + } + + if (store.data != .file) { + return JSC.JSPromise.rejectedPromiseValue(globalThis, globalThis.createErrorInstance("Blob is read-only", .{})); + } + + const file_sink = brk_sink: { + if (Environment.isWindows) { + const pathlike = store.data.file.pathlike; + const fd: bun.FileDescriptor = if (pathlike == .fd) pathlike.fd else brk: { + var file_path: bun.PathBuffer = undefined; + const path = pathlike.path.sliceZ(&file_path); + switch (bun.sys.open( + path, + bun.O.WRONLY | bun.O.CREAT | bun.O.NONBLOCK, + write_permissions, + )) { + .result => |result| { + break :brk result; + }, + .err => |err| { + return JSC.JSPromise.rejectedPromiseValue(globalThis, err.withPath(path).toJSC(globalThis)); + }, + } + unreachable; + }; + + const is_stdout_or_stderr = brk: { + if (pathlike != .fd) { + break :brk false; + } + + if (globalThis.bunVM().rare_data) |rare| { + if (store == rare.stdout_store) { + break :brk true; + } + + if (store == rare.stderr_store) { + break :brk true; + } + } + + break :brk switch (bun.FDTag.get(fd)) { + .stdout, .stderr => true, + else => false, + }; + }; + var sink = JSC.WebCore.FileSink.init(fd, this.globalThis.bunVM().eventLoop()); + sink.writer.owns_fd = pathlike != .fd; + + if (is_stdout_or_stderr) { + switch (sink.writer.startSync(fd, false)) { + .err => |err| { + sink.deref(); + return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + }, + else => {}, + } + } else { + switch (sink.writer.start(fd, true)) { + .err => |err| { + sink.deref(); + return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + }, + else => {}, + } + } + + break :brk_sink sink; + } + + var sink = JSC.WebCore.FileSink.init(bun.invalid_fd, this.globalThis.bunVM().eventLoop()); + + const input_path: JSC.WebCore.PathOrFileDescriptor = brk: { + if (store.data.file.pathlike == .fd) { + break :brk .{ .fd = store.data.file.pathlike.fd }; + } else { + break :brk .{ + .path = ZigString.Slice.fromUTF8NeverFree( + store.data.file.pathlike.path.slice(), + ).clone( + bun.default_allocator, + ) catch bun.outOfMemory(), + }; + } + }; + defer input_path.deinit(); + + const stream_start: JSC.WebCore.StreamStart = .{ + .FileSink = .{ + .input_path = input_path, + }, + }; + + switch (sink.start(stream_start)) { + .err => |err| { + sink.deref(); + return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + }, + else => {}, + } + break :brk_sink sink; + }; + var signal = &file_sink.signal; + + signal.* = JSC.WebCore.FileSink.JSSink.SinkSignal.init(.zero); + + // explicitly set it to a dead pointer + // we use this memory address to disable signals being sent + signal.clear(); + bun.assert(signal.isDead()); + + const assignment_result: JSC.JSValue = JSC.WebCore.FileSink.JSSink.assignToStream( + globalThis, + readable_stream.value, + file_sink, + @as(**anyopaque, @ptrCast(&signal.ptr)), + ); + + assignment_result.ensureStillAlive(); + + // assert that it was updated + bun.assert(!signal.isDead()); + + if (assignment_result.toError()) |err| { + file_sink.deref(); + return JSC.JSPromise.rejectedPromiseValue(globalThis, err); + } + + if (!assignment_result.isEmptyOrUndefinedOrNull()) { + globalThis.bunVM().drainMicrotasks(); + + assignment_result.ensureStillAlive(); + // it returns a Promise when it goes through ReadableStreamDefaultReader + if (assignment_result.asAnyPromise()) |promise| { + switch (promise.status(globalThis.vm())) { + .pending => { + const wrapper = FileStreamWrapper.new(.{ + .promise = JSC.JSPromise.Strong.init(globalThis), + .readable_stream_ref = JSC.WebCore.ReadableStream.Strong.init(readable_stream, globalThis), + .sink = file_sink, + }); + const promise_value = wrapper.promise.value(); + + assignment_result.then( + globalThis, + wrapper, + onFileStreamResolveRequestStream, + onFileStreamRejectRequestStream, + ); + return promise_value; + }, + .fulfilled => { + file_sink.deref(); + readable_stream.done(globalThis); + return JSC.JSPromise.resolvedPromiseValue(globalThis, JSC.JSValue.jsNumber(0)); + }, + .rejected => { + file_sink.deref(); + + readable_stream.cancel(globalThis); + + return JSC.JSPromise.rejectedPromiseValue(globalThis, promise.result(globalThis.vm())); + }, + } + } else { + file_sink.deref(); + + readable_stream.cancel(globalThis); + + return JSC.JSPromise.rejectedPromiseValue(globalThis, assignment_result); + } + } + file_sink.deref(); + + return JSC.JSPromise.resolvedPromiseValue(globalThis, JSC.JSValue.jsNumber(0)); + } + pub fn getWriter( this: *Blob, globalThis: *JSC.JSGlobalObject, @@ -3454,7 +4666,43 @@ pub const Blob = struct { var store = this.store orelse { return globalThis.throwInvalidArguments("Blob is detached", .{}); }; + if (this.isS3()) { + const s3 = &this.store.?.data.s3; + const path = s3.path(); + const proxy = globalThis.bunVM().transpiler.env.getHttpProxy(true, null); + const proxy_url = if (proxy) |p| p.href else null; + if (arguments.len > 0) { + const options = arguments.ptr[0]; + if (options.isObject()) { + if (try options.getTruthy(globalThis, "type")) |content_type| { + //override the content type + if (!content_type.isString()) { + return globalThis.throwInvalidArgumentType("write", "options.type", "string"); + } + var content_type_str = content_type.toSlice(globalThis, bun.default_allocator); + defer content_type_str.deinit(); + const slice = content_type_str.slice(); + if (strings.isAllASCII(slice)) { + if (this.content_type_allocated) { + bun.default_allocator.free(this.content_type); + } + this.content_type_was_set = true; + if (globalThis.bunVM().mimeType(slice)) |mime| { + this.content_type = mime.value; + } else { + const content_type_buf = bun.default_allocator.alloc(u8, slice.len) catch bun.outOfMemory(); + this.content_type = strings.copyLowercase(slice, content_type_buf); + this.content_type_allocated = true; + } + } + } + const credentialsWithOptions = try s3.getCredentialsWithOptions(options, globalThis); + return try credentialsWithOptions.credentials.dupe().s3WritableStream(path, globalThis, credentialsWithOptions.options, this.contentTypeOrMimeType(), proxy_url); + } + } + return try s3.getCredentials().s3WritableStream(path, globalThis, .{}, this.contentTypeOrMimeType(), proxy_url); + } if (store.data != .file) { return globalThis.throwInvalidArguments("Blob is read-only", .{}); } @@ -3563,6 +4811,30 @@ pub const Blob = struct { return sink.toJS(globalThis); } + pub fn getSliceFrom(this: *Blob, globalThis: *JSC.JSGlobalObject, relativeStart: i64, relativeEnd: i64, content_type: []const u8, content_type_was_allocated: bool) JSValue { + const offset = this.offset +| @as(SizeType, @intCast(relativeStart)); + const len = @as(SizeType, @intCast(@max(relativeEnd -| relativeStart, 0))); + + // This copies over the is_all_ascii flag + // which is okay because this will only be a <= slice + var blob = this.dupe(); + blob.offset = offset; + blob.size = len; + + // infer the content type if it was not specified + if (content_type.len == 0 and this.content_type.len > 0 and !this.content_type_allocated) { + blob.content_type = this.content_type; + } else { + blob.content_type = content_type; + } + blob.content_type_allocated = content_type_was_allocated; + blob.content_type_was_set = this.content_type_was_set or content_type_was_allocated; + + var blob_ = Blob.new(blob); + blob_.allocator = bun.default_allocator; + return blob_.toJS(globalThis); + } + /// https://w3c.github.io/FileAPI/#slice-method-algo /// The slice() method returns a new Blob object with bytes ranging from the /// optional start parameter up to but not including the optional end @@ -3654,26 +4926,7 @@ pub const Blob = struct { } } - const offset = this.offset +| @as(SizeType, @intCast(relativeStart)); - const len = @as(SizeType, @intCast(@max(relativeEnd -| relativeStart, 0))); - - // This copies over the is_all_ascii flag - // which is okay because this will only be a <= slice - var blob = this.dupe(); - blob.offset = offset; - blob.size = len; - - // infer the content type if it was not specified - if (content_type.len == 0 and this.content_type.len > 0 and !this.content_type_allocated) - content_type = this.content_type; - - blob.content_type = content_type; - blob.content_type_allocated = content_type_was_allocated; - blob.content_type_was_set = this.content_type_was_set or content_type_was_allocated; - - var blob_ = Blob.new(blob); - blob_.allocator = allocator; - return blob_.toJS(globalThis); + return this.getSliceFrom(globalThis, relativeStart, relativeEnd, content_type, content_type_was_allocated); } pub fn getMimeType(this: *const Blob) ?bun.http.MimeType { @@ -3734,6 +4987,17 @@ pub const Blob = struct { return if (this.getNameString()) |name| name.toJS(globalThis) else .undefined; } + pub fn getBucket( + this: *Blob, + globalThis: *JSC.JSGlobalObject, + ) JSValue { + if (this.getBucketName()) |name| { + var str = bun.String.createUTF8(name); + return str.transferToJS(globalThis); + } + return .undefined; + } + pub fn setName( this: *Blob, jsThis: JSC.JSValue, @@ -3776,12 +5040,38 @@ pub const Blob = struct { } else if (store.data == .bytes) { if (store.data.bytes.stored_name.slice().len > 0) return store.data.bytes.stored_name.slice(); + } else if (store.data == .s3) { + return store.data.s3.path(); } } return null; } + pub fn getBucketName( + this: *const Blob, + ) ?[]const u8 { + const store = this.store orelse return null; + if (store.data != .s3) return null; + const credentials = store.data.s3.getCredentials(); + var full_path = store.data.s3.path(); + if (strings.startsWith(full_path, "/")) { + full_path = full_path[1..]; + } + var bucket: []const u8 = credentials.bucket; + + if (bucket.len == 0) { + if (strings.indexOf(full_path, "/")) |end| { + bucket = full_path[0..end]; + if (bucket.len > 0) { + return bucket; + } + } + return null; + } + return bucket; + } + // TODO: Move this to a separate `File` object or BunFile pub fn getLastModified( this: *Blob, @@ -3790,7 +5080,7 @@ pub const Blob = struct { if (this.store) |store| { if (store.data == .file) { // last_modified can be already set during read. - if (store.data.file.last_modified == JSC.init_timestamp) { + if (store.data.file.last_modified == JSC.init_timestamp and !this.isS3()) { resolveFileStat(store); } return JSValue.jsNumber(store.data.file.last_modified); @@ -3833,8 +5123,11 @@ pub const Blob = struct { } } - pub fn getSize(this: *Blob, _: *JSC.JSGlobalObject) JSValue { + pub fn getSize(this: *Blob, globalThis: *JSC.JSGlobalObject) JSValue { if (this.size == Blob.max_size) { + if (this.isS3()) { + return S3BlobStatTask.size(globalThis, this); + } this.resolveSize(); if (this.size == Blob.max_size and this.store != null) { return JSC.jsNumber(std.math.inf(f64)); @@ -4189,7 +5482,7 @@ pub const Blob = struct { } pub fn needsToReadFile(this: *const Blob) bool { - return this.store != null and this.store.?.data == .file; + return this.store != null and (this.store.?.data == .file); } pub fn toStringWithBytes(this: *Blob, global: *JSGlobalObject, raw_bytes: []const u8, comptime lifetime: Lifetime) bun.JSError!JSValue { @@ -4281,6 +5574,9 @@ pub const Blob = struct { if (this.needsToReadFile()) { return this.doReadFile(toStringWithBytes, global); } + if (this.isS3()) { + return this.doReadFromS3(toStringWithBytes, global); + } const view_: []u8 = @constCast(this.sharedView()); @@ -4295,6 +5591,9 @@ pub const Blob = struct { if (this.needsToReadFile()) { return this.doReadFile(toJSONWithBytes, global); } + if (this.isS3()) { + return this.doReadFromS3(toJSONWithBytes, global); + } const view_ = this.sharedView(); @@ -4457,6 +5756,10 @@ pub const Blob = struct { return this.doReadFile(WithBytesFn, global); } + if (this.isS3()) { + return this.doReadFromS3(WithBytesFn, global); + } + const view_ = this.sharedView(); if (view_.len == 0) return JSC.ArrayBuffer.create(global, "", TypedArrayView); @@ -4468,6 +5771,9 @@ pub const Blob = struct { if (this.needsToReadFile()) { return this.doReadFile(toFormDataWithBytes, global); } + if (this.isS3()) { + return this.doReadFromS3(toFormDataWithBytes, global); + } const view_ = this.sharedView(); @@ -5106,6 +6412,13 @@ pub const AnyBlob = union(enum) { }; } + pub fn isS3(self: *const @This()) bool { + return switch (self.*) { + .Blob => self.Blob.isS3(), + .WTFStringImpl, .InternalBlob => false, + }; + } + pub fn detach(self: *@This()) void { return switch (self.*) { .Blob => { diff --git a/src/bun.js/webcore/blob/WriteFile.zig b/src/bun.js/webcore/blob/WriteFile.zig index 13804680ae..9560fc4cd2 100644 --- a/src/bun.js/webcore/blob/WriteFile.zig +++ b/src/bun.js/webcore/blob/WriteFile.zig @@ -709,7 +709,7 @@ pub const WriteFileWaitFromLockedValueTask = struct { => { var blob = value.use(); // TODO: this should be one promise not two! - const new_promise = Blob.writeFileWithSourceDestination(globalThis, &blob, &file_blob, this.mkdirp_if_not_exists); + const new_promise = Blob.writeFileWithSourceDestination(globalThis, &blob, &file_blob, .{ .mkdirp_if_not_exists = this.mkdirp_if_not_exists }); if (new_promise.asAnyPromise()) |p| { switch (p.unwrap(globalThis.vm(), .mark_handled)) { // Fulfill the new promise using the pending promise diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig index 7b1534091d..abdfa55d87 100644 --- a/src/bun.js/webcore/body.zig +++ b/src/bun.js/webcore/body.zig @@ -1111,9 +1111,9 @@ pub const Body = struct { var body = Body{ .value = Value{ .Null = {} } }; body.value = try Value.fromJS(globalThis, value); - if (body.value == .Blob) + if (body.value == .Blob) { assert(body.value.Blob.allocator == null); // owned by Body - + } return body; } }; diff --git a/src/bun.js/webcore/response.classes.ts b/src/bun.js/webcore/response.classes.ts index 567c029cb4..ba7e022fa3 100644 --- a/src/bun.js/webcore/response.classes.ts +++ b/src/bun.js/webcore/response.classes.ts @@ -165,6 +165,16 @@ export default [ getter: "getLastModified", }, + // Non-standard, s3 + BunFile support + unlink: { fn: "doUnlink", length: 0 }, + write: { fn: "doWrite", length: 2 }, + // Non-standard, s3 support + bucket: { + cache: true, + getter: "getBucket", + }, + presign: { fn: "getPresignUrl", length: 1 }, + size: { getter: "getSize", }, diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 13955dbf52..38e737ea52 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -55,6 +55,7 @@ const Async = bun.Async; const BoringSSL = bun.BoringSSL; const X509 = @import("../api/bun/x509.zig"); const PosixToWinNormalizer = bun.path.PosixToWinNormalizer; +const s3 = @import("../../s3.zig"); pub const Response = struct { const ResponseMixin = BodyMixin(@This()); @@ -512,6 +513,37 @@ pub const Response = struct { pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!*Response { const arguments = callframe.argumentsAsArray(2); + if (!arguments[0].isUndefinedOrNull() and arguments[0].isObject()) { + if (arguments[0].as(Blob)) |blob| { + if (blob.isS3()) { + if (!arguments[1].isEmptyOrUndefinedOrNull()) { + return globalThis.throwInvalidArguments("new Response(s3File) do not support ResponseInit options", .{}); + } + var response: Response = .{ + .init = Response.Init{ + .status_code = 302, + }, + .body = Body{ + .value = .{ .Empty = {} }, + }, + .url = bun.String.empty, + }; + + const result = blob.store.?.data.s3.getCredentials().signRequest(.{ + .path = blob.store.?.data.s3.path(), + .method = .GET, + }, .{ .expires = 15 * 60 }) catch |sign_err| { + return s3.AWSCredentials.throwSignError(sign_err, globalThis); + }; + defer result.deinit(); + response.init.headers = response.getOrCreateHeaders(globalThis); + response.redirected = true; + var headers_ref = response.init.headers.?; + headers_ref.put(.Location, result.url, globalThis); + return bun.new(Response, response); + } + } + } var init: Init = (brk: { if (arguments[1].isUndefinedOrNull()) { break :brk Init{ @@ -697,7 +729,14 @@ pub const Response = struct { }; const null_fd = bun.invalid_fd; +fn setHeaders(headers: *?Headers, new_headers: []const picohttp.Header, allocator: std.mem.Allocator) void { + var old = headers.*; + headers.* = Headers.fromPicoHttpHeaders(new_headers, allocator) catch bun.outOfMemory(); + if (old) |*headers_| { + headers_.deinit(); + } +} pub const Fetch = struct { const headers_string = "headers"; const method_string = "method"; @@ -911,6 +950,13 @@ pub const Fetch = struct { }; } + pub fn isS3(this: *const HTTPRequestBody) bool { + return switch (this.*) { + .AnyBlob => |*blob| blob.isS3(), + else => false, + }; + } + pub fn hasContentTypeFromUser(this: *HTTPRequestBody) bool { return switch (this.*) { .AnyBlob => |blob| blob.hasContentTypeFromUser(), @@ -1092,7 +1138,7 @@ pub const Fetch = struct { const globalThis = this.global_this; var response_stream = FetchTaskletStream.new(.{ - .task = this, + .task = .{ .fetch = this }, .buffer = .{}, .globalThis = globalThis, }).toSink(); @@ -1889,10 +1935,10 @@ pub const Fetch = struct { var proxy: ?ZigURL = null; if (fetch_options.proxy) |proxy_opt| { if (!proxy_opt.isEmpty()) { //if is empty just ignore proxy - proxy = fetch_options.proxy orelse jsc_vm.transpiler.env.getHttpProxy(fetch_options.url); + proxy = fetch_options.proxy orelse jsc_vm.transpiler.env.getHttpProxyFor(fetch_options.url); } } else { - proxy = jsc_vm.transpiler.env.getHttpProxy(fetch_options.url); + proxy = jsc_vm.transpiler.env.getHttpProxyFor(fetch_options.url); } if (fetch_tasklet.check_server_identity.has() and fetch_tasklet.reject_unauthorized) { @@ -2182,7 +2228,7 @@ pub const Fetch = struct { } const url = ZigURL.parse(url_str.toOwnedSlice(bun.default_allocator) catch bun.outOfMemory()); - if (!url.isHTTP() and !url.isHTTPS()) { + if (!url.isHTTP() and !url.isHTTPS() and !url.isS3()) { bun.default_allocator.free(url.href); return globalObject.throwInvalidArguments("URL must be HTTP or HTTPS", .{}); } @@ -2273,6 +2319,7 @@ pub const Fetch = struct { var signal: ?*JSC.WebCore.AbortSignal = null; // Custom Hostname var hostname: ?[]u8 = null; + var range: ?[]u8 = null; var unix_socket_path: ZigString.Slice = ZigString.Slice.empty; var url_proxy_buffer: []const u8 = ""; @@ -2311,6 +2358,10 @@ pub const Fetch = struct { bun.default_allocator.free(hn); hostname = null; } + if (range) |range_| { + bun.default_allocator.free(range_); + range = null; + } if (ssl_config) |conf| { ssl_config = null; @@ -2928,6 +2979,15 @@ pub const Fetch = struct { } hostname = _hostname.toOwnedSliceZ(allocator) catch bun.outOfMemory(); } + if (url.isS3()) { + if (headers_.fastGet(JSC.FetchHeaders.HTTPHeaderName.Range)) |_range| { + if (range) |range_| { + range = null; + allocator.free(range_); + } + range = _range.toOwnedSliceZ(allocator) catch bun.outOfMemory(); + } + } break :extract_headers Headers.from(headers_, allocator, .{ .body = body.getAnyBlob() }) catch bun.outOfMemory(); } @@ -3039,6 +3099,7 @@ pub const Fetch = struct { break :blob Blob.findOrCreateFileFromPath( &pathlike, globalThis, + true, ); }; @@ -3056,8 +3117,8 @@ pub const Fetch = struct { } if (url.protocol.len > 0) { - if (!(url.isHTTP() or url.isHTTPS())) { - const err = JSC.toTypeError(.ERR_INVALID_ARG_VALUE, "protocol must be http: or https:", .{}, ctx); + if (!(url.isHTTP() or url.isHTTPS() or url.isS3())) { + const err = JSC.toTypeError(.ERR_INVALID_ARG_VALUE, "protocol must be http:, https: or s3:", .{}, ctx); is_error = true; return JSPromise.rejectedPromiseValue(globalThis, err); } @@ -3078,7 +3139,22 @@ pub const Fetch = struct { } var http_body = body; + if (body.isS3()) { + prepare_body: { + // is a S3 file we can use chunked here + if (JSC.WebCore.ReadableStream.fromJS(JSC.WebCore.ReadableStream.fromBlob(globalThis, &body.AnyBlob.Blob, s3.MultiPartUpload.DefaultPartSize), globalThis)) |stream| { + var old = body; + defer old.detach(); + body = .{ .ReadableStream = JSC.WebCore.ReadableStream.Strong.init(stream, globalThis) }; + break :prepare_body; + } + const rejected_value = JSPromise.rejectedPromiseValue(globalThis, globalThis.createErrorInstance("Failed to start s3 stream", .{})); + body.detach(); + + return rejected_value; + } + } if (body.needsToReadFile()) { prepare_body: { const opened_fd_res: JSC.Maybe(bun.FileDescriptor) = switch (body.store().?.data.file.pathlike) { @@ -3174,6 +3250,179 @@ pub const Fetch = struct { } } + if (url.isS3()) { + // get ENV config + var credentialsWithOptions: s3.AWSCredentials.AWSCredentialsWithOptions = .{ + .credentials = globalThis.bunVM().transpiler.env.getAWSCredentials(), + .options = .{}, + }; + defer { + credentialsWithOptions.deinit(); + } + + if (options_object) |options| { + if (try options.getTruthyComptime(globalThis, "s3")) |s3_options| { + if (s3_options.isObject()) { + s3_options.ensureStillAlive(); + credentialsWithOptions = try s3.AWSCredentials.getCredentialsWithOptions(credentialsWithOptions.credentials, s3_options, globalThis); + } + } + } + + if (body == .ReadableStream) { + // we cannot direct stream to s3 we need to use multi part upload + defer body.ReadableStream.deinit(); + const Wrapper = struct { + promise: JSC.JSPromise.Strong, + url: ZigURL, + url_proxy_buffer: []const u8, + pub usingnamespace bun.New(@This()); + + pub fn resolve(result: s3.AWSCredentials.S3UploadResult, self: *@This()) void { + if (self.promise.globalObject()) |global| { + switch (result) { + .success => { + const response = bun.new(Response, Response{ + .body = .{ .value = .Empty }, + .redirected = false, + .init = .{ .method = .PUT, .status_code = 200 }, + .url = bun.String.createAtomIfPossible(self.url.href), + }); + const response_js = Response.makeMaybePooled(@as(js.JSContextRef, global), response); + response_js.ensureStillAlive(); + self.promise.resolve(global, response_js); + }, + .failure => |err| { + const response = bun.new(Response, Response{ + .body = .{ + .value = .{ + .InternalBlob = .{ + .bytes = std.ArrayList(u8).fromOwnedSlice(bun.default_allocator, bun.default_allocator.dupe(u8, err.message) catch bun.outOfMemory()), + .was_string = true, + }, + }, + }, + .redirected = false, + .init = .{ + .method = .PUT, + .status_code = 500, + .status_text = bun.String.createAtomIfPossible(err.code), + }, + .url = bun.String.createAtomIfPossible(self.url.href), + }); + const response_js = Response.makeMaybePooled(@as(js.JSContextRef, global), response); + response_js.ensureStillAlive(); + self.promise.resolve(global, response_js); + }, + } + } + bun.default_allocator.free(self.url_proxy_buffer); + self.destroy(); + } + }; + if (method != .PUT and method != .POST) { + return JSC.JSPromise.rejectedPromiseValue(globalThis, globalThis.createErrorInstance("Only POST and PUT do support body when using S3", .{})); + } + const promise = JSC.JSPromise.Strong.init(globalThis); + + const s3_stream = Wrapper.new(.{ + .url = url, + .url_proxy_buffer = url_proxy_buffer, + .promise = promise, + }); + + const promise_value = promise.value(); + const proxy_url = if (proxy) |p| p.href else ""; + _ = credentialsWithOptions.credentials.dupe().s3UploadStream( + url.s3Path(), + body.ReadableStream.get().?, + globalThis, + credentialsWithOptions.options, + if (headers) |h| h.getContentType() else null, + proxy_url, + @ptrCast(&Wrapper.resolve), + s3_stream, + ); + url = .{}; + url_proxy_buffer = ""; + return promise_value; + } + if (method == .POST) { + method = .PUT; + } + + var result = credentialsWithOptions.credentials.signRequest(.{ + .path = url.s3Path(), + .method = method, + }, null) catch |sign_err| { + is_error = true; + return JSPromise.rejectedPromiseValue(globalThis, s3.AWSCredentials.getJSSignError(sign_err, globalThis)); + }; + defer result.deinit(); + if (proxy) |proxy_| { + // proxy and url are in the same buffer lets replace it + const old_buffer = url_proxy_buffer; + defer allocator.free(old_buffer); + var buffer = allocator.alloc(u8, result.url.len + proxy_.href.len) catch bun.outOfMemory(); + bun.copy(u8, buffer[0..result.url.len], result.url); + bun.copy(u8, buffer[proxy_.href.len..], proxy_.href); + url_proxy_buffer = buffer; + + url = ZigURL.parse(url_proxy_buffer[0..result.url.len]); + proxy = ZigURL.parse(url_proxy_buffer[result.url.len..]); + } else { + // replace headers and url of the request + allocator.free(url_proxy_buffer); + url_proxy_buffer = result.url; + url = ZigURL.parse(result.url); + result.url = ""; // fetch now owns this + } + + const content_type = if (headers) |h| h.getContentType() else null; + + if (range) |range_| { + const _headers = result.headers(); + var headersWithRange: [5]picohttp.Header = .{ + _headers[0], + _headers[1], + _headers[2], + _headers[3], + .{ .name = "range", .value = range_ }, + }; + + setHeaders(&headers, &headersWithRange, allocator); + } else if (content_type) |ct| { + if (ct.len > 0) { + const _headers = result.headers(); + if (_headers.len > 4) { + var headersWithContentType: [6]picohttp.Header = .{ + _headers[0], + _headers[1], + _headers[2], + _headers[3], + _headers[4], + .{ .name = "Content-Type", .value = ct }, + }; + setHeaders(&headers, &headersWithContentType, allocator); + } else { + var headersWithContentType: [5]picohttp.Header = .{ + _headers[0], + _headers[1], + _headers[2], + _headers[3], + .{ .name = "Content-Type", .value = ct }, + }; + + setHeaders(&headers, &headersWithContentType, allocator); + } + } else { + setHeaders(&headers, result.headers(), allocator); + } + } else { + setHeaders(&headers, result.headers(), allocator); + } + } + // Only create this after we have validated all the input. // or else we will leak it var promise = JSPromise.Strong.init(globalThis); @@ -3262,7 +3511,21 @@ pub const Headers = struct { this.entries.deinit(this.allocator); this.buf.clearAndFree(this.allocator); } + pub fn getContentType(this: *const Headers) ?[]const u8 { + if (this.entries.len == 0 or this.buf.items.len == 0) { + return null; + } + const header_entries = this.entries.slice(); + const header_names = header_entries.items(.name); + const header_values = header_entries.items(.value); + for (header_names, 0..header_names.len) |name, i| { + if (bun.strings.eqlCaseInsensitiveASCII(this.asStr(name), "content-type", true)) { + return this.asStr(header_values[i]); + } + } + return null; + } pub fn asStr(this: *const Headers, ptr: Api.StringPointer) []const u8 { return if (ptr.offset + ptr.length <= this.buf.items.len) this.buf.items[ptr.offset..][0..ptr.length] @@ -3274,6 +3537,45 @@ pub const Headers = struct { body: ?*const AnyBlob = null, }; + pub fn fromPicoHttpHeaders(headers: []const picohttp.Header, allocator: std.mem.Allocator) !Headers { + const header_count = headers.len; + var result = Headers{ + .entries = .{}, + .buf = .{}, + .allocator = allocator, + }; + + var buf_len: usize = 0; + for (headers) |header| { + buf_len += header.name.len + header.value.len; + } + result.entries.ensureTotalCapacity(allocator, header_count) catch bun.outOfMemory(); + result.entries.len = headers.len; + result.buf.ensureTotalCapacityPrecise(allocator, buf_len) catch bun.outOfMemory(); + result.buf.items.len = buf_len; + var offset: u32 = 0; + for (headers, 0..headers.len) |header, i| { + const name_offset = offset; + bun.copy(u8, result.buf.items[offset..][0..header.name.len], header.name); + offset += @truncate(header.name.len); + const value_offset = offset; + bun.copy(u8, result.buf.items[offset..][0..header.value.len], header.value); + offset += @truncate(header.value.len); + + result.entries.set(i, .{ + .name = .{ + .offset = name_offset, + .length = @truncate(header.name.len), + }, + .value = .{ + .offset = value_offset, + .length = @truncate(header.value.len), + }, + }); + } + return result; + } + pub fn from(fetch_headers_ref: ?*FetchHeaders, allocator: std.mem.Allocator, options: Options) !Headers { var header_count: u32 = 0; var buf_len: u32 = 0; diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index d4f61a5c14..8c7f348dfb 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -43,6 +43,7 @@ const Request = JSC.WebCore.Request; const assert = bun.assert; const Syscall = bun.sys; const uv = bun.windows.libuv; +const S3MultiPartUpload = @import("../../s3.zig").MultiPartUpload; const AnyBlob = JSC.WebCore.AnyBlob; pub const ReadableStream = struct { @@ -360,6 +361,9 @@ pub const ReadableStream = struct { .globalThis = globalThis, .context = .{ .event_loop = JSC.EventLoopHandle.init(globalThis.bunVM().eventLoop()), + .start_offset = blob.offset, + .max_size = if (blob.size != Blob.max_size) blob.size else null, + .lazy = .{ .blob = store, }, @@ -369,6 +373,14 @@ pub const ReadableStream = struct { return reader.toReadableStream(globalThis); }, + .s3 => |*s3| { + const credentials = s3.getCredentials(); + const path = s3.path(); + const proxy = globalThis.bunVM().transpiler.env.getHttpProxy(true, null); + const proxy_url = if (proxy) |p| p.href else null; + + return credentials.s3ReadableStream(path, blob.offset, if (blob.size != Blob.max_size) blob.size else null, proxy_url, globalThis); + }, } } @@ -2626,17 +2638,34 @@ pub fn HTTPServerWritable(comptime ssl: bool) type { pub const HTTPSResponseSink = HTTPServerWritable(true); pub const HTTPResponseSink = HTTPServerWritable(false); pub const FetchTaskletChunkedRequestSink = struct { - task: ?*JSC.WebCore.Fetch.FetchTasklet = null, + task: ?HTTPWritableStream = null, signal: Signal = .{}, globalThis: *JSGlobalObject = undefined, highWaterMark: Blob.SizeType = 2048, buffer: bun.io.StreamBuffer, ended: bool = false, done: bool = false, + encoded: bool = true, + + endPromise: JSC.JSPromise.Strong = .{}, + auto_flusher: AutoFlusher = AutoFlusher{}, pub usingnamespace bun.New(FetchTaskletChunkedRequestSink); + const HTTPWritableStream = union(enum) { + fetch: *JSC.WebCore.Fetch.FetchTasklet, + s3_upload: *S3MultiPartUpload, + }; + fn getHighWaterMark(this: *@This()) Blob.SizeType { + if (this.task) |task| { + return switch (task) { + .s3_upload => |s3| @truncate(s3.partSizeInBytes()), + else => this.highWaterMark, + }; + } + return this.highWaterMark; + } fn unregisterAutoFlusher(this: *@This()) void { if (this.auto_flusher.registered) AutoFlusher.unregisterDeferredMicrotaskWithTypeUnchecked(@This(), this, this.globalThis.bunVM()); @@ -2665,6 +2694,7 @@ pub const FetchTaskletChunkedRequestSink = struct { if (this.ended) { return .{ .result = {} }; } + switch (stream_start) { .chunk_size => |chunk_size| { if (chunk_size > 0) { @@ -2694,9 +2724,23 @@ pub const FetchTaskletChunkedRequestSink = struct { this.buffer = .{}; buffer.deinit(); + this.detachWritable(); + } + + fn detachWritable(this: *@This()) void { if (this.task) |task| { this.task = null; - task.deref(); + switch (task) { + inline .fetch, .s3_upload => |writable| { + writable.deref(); + }, + } + } + } + + fn sendRequestData(writable: HTTPWritableStream, data: []const u8, is_last: bool) void { + switch (writable) { + inline .fetch, .s3_upload => |task| task.sendRequestData(data, is_last), } } @@ -2705,19 +2749,22 @@ pub const FetchTaskletChunkedRequestSink = struct { if (this.task) |task| { if (is_last) this.done = true; + if (this.encoded) { + if (data.len == 0) { + sendRequestData(task, bun.http.end_of_chunked_http1_1_encoding_response_body, true); + return; + } - if (data.len == 0) { - task.sendRequestData(bun.http.end_of_chunked_http1_1_encoding_response_body, true); - return; - } - - // chunk encoding is really simple - if (is_last) { - const chunk = std.fmt.allocPrint(bun.default_allocator, "{x}\r\n{s}\r\n0\r\n\r\n", .{ data.len, data }) catch return error.OOM; - task.sendRequestData(chunk, true); + // chunk encoding is really simple + if (is_last) { + const chunk = std.fmt.allocPrint(bun.default_allocator, "{x}\r\n{s}\r\n0\r\n\r\n", .{ data.len, data }) catch return error.OOM; + sendRequestData(task, chunk, true); + } else { + const chunk = std.fmt.allocPrint(bun.default_allocator, "{x}\r\n{s}\r\n", .{ data.len, data }) catch return error.OOM; + sendRequestData(task, chunk, false); + } } else { - const chunk = std.fmt.allocPrint(bun.default_allocator, "{x}\r\n{s}\r\n", .{ data.len, data }) catch return error.OOM; - task.sendRequestData(chunk, false); + sendRequestData(task, data, is_last); } } } @@ -2769,14 +2816,14 @@ pub const FetchTaskletChunkedRequestSink = struct { const bytes = data.slice(); const len = @as(Blob.SizeType, @truncate(bytes.len)); - if (this.buffer.size() == 0 and len >= this.highWaterMark) { + if (this.buffer.size() == 0 and len >= this.getHighWaterMark()) { // fast path: // - large-ish chunk this.send(bytes, false) catch { return .{ .err = Syscall.Error.fromCode(.NOMEM, .write) }; }; return .{ .owned = len }; - } else if (this.buffer.size() + len >= this.highWaterMark) { + } else if (this.buffer.size() + len >= this.getHighWaterMark()) { _ = this.buffer.write(bytes) catch { return .{ .err = Syscall.Error.fromCode(.NOMEM, .write) }; }; @@ -2803,7 +2850,7 @@ pub const FetchTaskletChunkedRequestSink = struct { const bytes = data.slice(); const len = @as(Blob.SizeType, @truncate(bytes.len)); - if (this.buffer.size() == 0 and len >= this.highWaterMark) { + if (this.buffer.size() == 0 and len >= this.getHighWaterMark()) { // common case if (strings.isAllASCII(bytes)) { // fast path: @@ -2822,7 +2869,7 @@ pub const FetchTaskletChunkedRequestSink = struct { return .{ .err = Syscall.Error.fromCode(.NOMEM, .write) }; }; return .{ .owned = len }; - } else if (this.buffer.size() + len >= this.highWaterMark) { + } else if (this.buffer.size() + len >= this.getHighWaterMark()) { // kinda fast path: // - combined chunk is large enough to flush automatically this.buffer.writeLatin1(bytes) catch { @@ -2854,7 +2901,7 @@ pub const FetchTaskletChunkedRequestSink = struct { }; const readable = this.buffer.slice(); - if (readable.len >= this.highWaterMark) { + if (readable.len >= this.getHighWaterMark()) { _ = this.internalFlush() catch { return .{ .err = Syscall.Error.fromCode(.NOMEM, .write) }; }; @@ -2879,18 +2926,23 @@ pub const FetchTaskletChunkedRequestSink = struct { return .{ .result = {} }; } pub fn endFromJS(this: *@This(), _: *JSGlobalObject) JSC.Maybe(JSValue) { - if (this.ended) { + if (!this.ended) { + if (this.done) { + this.ended = true; + this.signal.close(null); + this.finalize(); + } else { + _ = this.end(null); + } + } + const promise = this.endPromise.valueOrEmpty(); + if (promise.isEmptyOrUndefinedOrNull()) { return .{ .result = JSC.JSValue.jsNumber(0) }; } - - if (this.done) { - this.ended = true; - this.signal.close(null); - this.finalize(); - return .{ .result = JSC.JSValue.jsNumber(0) }; - } - _ = this.end(null); - return .{ .result = JSC.JSValue.jsNumber(0) }; + return .{ .result = promise }; + } + pub fn toJS(this: *@This(), globalThis: *JSGlobalObject) JSValue { + return JSSink.createObject(globalThis, this, 0); } pub fn memoryCost(this: *const @This()) usize { @@ -3856,6 +3908,8 @@ pub const FileReader = struct { pending_view: []u8 = &.{}, fd: bun.FileDescriptor = bun.invalid_fd, start_offset: ?usize = null, + max_size: ?usize = null, + total_readed: usize = 0, started: bool = false, waiting_for_onReaderDone: bool = false, event_loop: JSC.EventLoopHandle, @@ -4011,7 +4065,7 @@ pub const FileReader = struct { var file_type: bun.io.FileType = .file; if (this.lazy == .blob) { switch (this.lazy.blob.data) { - .bytes => @panic("Invalid state in FileReader: expected file "), + .s3, .bytes => @panic("Invalid state in FileReader: expected file "), .file => |*file| { defer { this.lazy.blob.deref(); @@ -4134,15 +4188,32 @@ pub const FileReader = struct { } pub fn onReadChunk(this: *@This(), init_buf: []const u8, state: bun.io.ReadState) bool { - const buf = init_buf; + var buf = init_buf; log("onReadChunk() = {d} ({s})", .{ buf.len, @tagName(state) }); if (this.done) { this.reader.close(); return false; } + var close = false; + defer if (close) this.reader.close(); + var hasMore = state != .eof; - const hasMore = state != .eof; + if (buf.len > 0) { + if (this.max_size) |max_size| { + if (this.total_readed >= max_size) return false; + const len = @min(max_size - this.total_readed, buf.len); + if (buf.len > len) { + buf = buf[0..len]; + } + this.total_readed += len; + + if (buf.len == 0) { + close = true; + hasMore = false; + } + } + } if (this.read_inside_on_pull != .none) { switch (this.read_inside_on_pull) { @@ -4691,6 +4762,8 @@ pub const ByteStream = struct { size_hint: Blob.SizeType = 0, buffer_action: ?BufferAction = null, + const log = Output.scoped(.ByteStream, false); + const BufferAction = union(BufferedReadableStreamAction) { text: JSC.JSPromise.Strong, arrayBuffer: JSC.JSPromise.Strong, @@ -4795,6 +4868,9 @@ pub const ByteStream = struct { if (stream == .owned) allocator.free(stream.owned.slice()); if (stream == .owned_and_done) allocator.free(stream.owned_and_done.slice()); } + this.has_received_last_chunk = stream.isDone(); + + log("ByteStream.onData already done... do nothing", .{}); return; } @@ -4818,6 +4894,8 @@ pub const ByteStream = struct { this.buffer_action = null; } + log("ByteStream.onData err action.reject()", .{}); + action.reject(stream.err); return; } @@ -4827,7 +4905,16 @@ pub const ByteStream = struct { this.buffer_action = null; } + if (this.buffer.capacity == 0 and stream == .done) { + log("ByteStream.onData done and action.fulfill()", .{}); + + var blob = this.toAnyBlob().?; + action.fulfill(&blob); + return; + } if (this.buffer.capacity == 0 and stream == .owned_and_done) { + log("ByteStream.onData owned_and_done and action.fulfill()", .{}); + this.buffer = std.ArrayList(u8).fromOwnedSlice(bun.default_allocator, @constCast(chunk)); var blob = this.toAnyBlob().?; action.fulfill(&blob); @@ -4838,10 +4925,12 @@ pub const ByteStream = struct { allocator.free(stream.slice()); } } + log("ByteStream.onData appendSlice and action.fulfill()", .{}); this.buffer.appendSlice(chunk) catch bun.outOfMemory(); var blob = this.toAnyBlob().?; action.fulfill(&blob); + return; } else { this.buffer.appendSlice(chunk) catch bun.outOfMemory(); @@ -4895,13 +4984,18 @@ pub const ByteStream = struct { } const remaining = chunk[to_copy.len..]; - if (remaining.len > 0) + if (remaining.len > 0 and chunk.len > 0) this.append(stream, to_copy.len, chunk, allocator) catch @panic("Out of memory while copying request body"); + log("ByteStream.onData pending.run()", .{}); + this.pending.run(); + return; } + log("ByteStream.onData no action just append", .{}); + this.append(stream, 0, chunk, allocator) catch @panic("Out of memory while copying request body"); } @@ -4931,6 +5025,7 @@ pub const ByteStream = struct { .err => { this.pending.result = .{ .err = stream.err }; }, + .done => {}, else => unreachable, } return; @@ -4951,6 +5046,7 @@ pub const ByteStream = struct { this.pending.result = .{ .err = stream.err }; }, + .done => {}, // We don't support the rest of these yet else => unreachable, } diff --git a/src/cli/create_command.zig b/src/cli/create_command.zig index 9e20a74530..d611d8e259 100644 --- a/src/cli/create_command.zig +++ b/src/cli/create_command.zig @@ -1957,7 +1957,7 @@ pub const Example = struct { } } - const http_proxy: ?URL = env_loader.getHttpProxy(api_url); + const http_proxy: ?URL = env_loader.getHttpProxyFor(api_url); const mutable = try ctx.allocator.create(MutableString); mutable.* = try MutableString.init(ctx.allocator, 8192); @@ -2036,7 +2036,7 @@ pub const Example = struct { url = URL.parse(try std.fmt.bufPrint(&url_buf, "https://registry.npmjs.org/@bun-examples/{s}/latest", .{name})); - var http_proxy: ?URL = env_loader.getHttpProxy(url); + var http_proxy: ?URL = env_loader.getHttpProxyFor(url); // ensure very stable memory address var async_http: *HTTP.AsyncHTTP = ctx.allocator.create(HTTP.AsyncHTTP) catch unreachable; @@ -2119,7 +2119,7 @@ pub const Example = struct { // ensure very stable memory address const parsed_tarball_url = URL.parse(tarball_url); - http_proxy = env_loader.getHttpProxy(parsed_tarball_url); + http_proxy = env_loader.getHttpProxyFor(parsed_tarball_url); async_http.* = HTTP.AsyncHTTP.initSync( ctx.allocator, @@ -2157,7 +2157,7 @@ pub const Example = struct { pub fn fetchAll(ctx: Command.Context, env_loader: *DotEnv.Loader, progress_node: ?*Progress.Node) ![]Example { url = URL.parse(examples_url); - const http_proxy: ?URL = env_loader.getHttpProxy(url); + const http_proxy: ?URL = env_loader.getHttpProxyFor(url); var async_http: *HTTP.AsyncHTTP = ctx.allocator.create(HTTP.AsyncHTTP) catch unreachable; const mutable = try ctx.allocator.create(MutableString); diff --git a/src/cli/upgrade_command.zig b/src/cli/upgrade_command.zig index f86c6dd0fa..fb822fa4e9 100644 --- a/src/cli/upgrade_command.zig +++ b/src/cli/upgrade_command.zig @@ -231,7 +231,7 @@ pub const UpgradeCommand = struct { } } - const http_proxy: ?URL = env_loader.getHttpProxy(api_url); + const http_proxy: ?URL = env_loader.getHttpProxyFor(api_url); var metadata_body = try MutableString.init(allocator, 2048); @@ -501,7 +501,7 @@ pub const UpgradeCommand = struct { }; const zip_url = URL.parse(version.zip_url); - const http_proxy: ?URL = env_loader.getHttpProxy(zip_url); + const http_proxy: ?URL = env_loader.getHttpProxyFor(zip_url); { var refresher = Progress{}; diff --git a/src/compile_target.zig b/src/compile_target.zig index e6d9367fb6..5fee414738 100644 --- a/src/compile_target.zig +++ b/src/compile_target.zig @@ -153,7 +153,7 @@ pub fn downloadToPath(this: *const CompileTarget, env: *bun.DotEnv.Loader, alloc { var progress = refresher.start("Downloading", 0); defer progress.end(); - const http_proxy: ?bun.URL = env.getHttpProxy(url); + const http_proxy: ?bun.URL = env.getHttpProxyFor(url); async_http.* = HTTP.AsyncHTTP.initSync( allocator, diff --git a/src/env_loader.zig b/src/env_loader.zig index 77cc2aa7ec..8ea780553f 100644 --- a/src/env_loader.zig +++ b/src/env_loader.zig @@ -17,6 +17,7 @@ const Fs = @import("./fs.zig"); const URL = @import("./url.zig").URL; const Api = @import("./api/schema.zig").Api; const which = @import("./which.zig").which; +const s3 = @import("./s3.zig"); const DotEnvFileSuffix = enum { development, @@ -45,6 +46,8 @@ pub const Loader = struct { did_load_process: bool = false, reject_unauthorized: ?bool = null, + aws_credentials: ?s3.AWSCredentials = null, + pub fn iterator(this: *const Loader) Map.HashTable.Iterator { return this.map.iterator(); } @@ -112,6 +115,53 @@ pub const Loader = struct { } } + pub fn getAWSCredentials(this: *Loader) s3.AWSCredentials { + if (this.aws_credentials) |credentials| { + return credentials; + } + + var accessKeyId: []const u8 = ""; + var secretAccessKey: []const u8 = ""; + var region: []const u8 = ""; + var endpoint: []const u8 = ""; + var bucket: []const u8 = ""; + + if (this.get("S3_ACCESS_KEY_ID")) |access_key| { + accessKeyId = access_key; + } else if (this.get("AWS_ACCESS_KEY_ID")) |access_key| { + accessKeyId = access_key; + } + if (this.get("S3_SECRET_ACCESS_KEY")) |access_key| { + secretAccessKey = access_key; + } else if (this.get("AWS_SECRET_ACCESS_KEY")) |access_key| { + secretAccessKey = access_key; + } + + if (this.get("S3_REGION")) |region_| { + region = region_; + } else if (this.get("AWS_REGION")) |region_| { + region = region_; + } + if (this.get("S3_ENDPOINT")) |endpoint_| { + endpoint = bun.URL.parse(endpoint_).host; + } else if (this.get("AWS_ENDPOINT")) |endpoint_| { + endpoint = bun.URL.parse(endpoint_).host; + } + if (this.get("S3_BUCKET")) |bucket_| { + bucket = bucket_; + } else if (this.get("AWS_BUCKET")) |bucket_| { + bucket = bucket_; + } + this.aws_credentials = .{ + .accessKeyId = accessKeyId, + .secretAccessKey = secretAccessKey, + .region = region, + .endpoint = endpoint, + .bucket = bucket, + }; + + return this.aws_credentials.?; + } /// Checks whether `NODE_TLS_REJECT_UNAUTHORIZED` is set to `0` or `false`. /// /// **Prefer VirtualMachine.getTLSRejectUnauthorized()** for JavaScript, as individual workers could have different settings. @@ -134,11 +184,15 @@ pub const Loader = struct { return true; } - pub fn getHttpProxy(this: *Loader, url: URL) ?URL { + pub fn getHttpProxyFor(this: *Loader, url: URL) ?URL { + return this.getHttpProxy(url.isHTTP(), url.hostname); + } + + pub fn getHttpProxy(this: *Loader, is_http: bool, hostname: ?[]const u8) ?URL { // TODO: When Web Worker support is added, make sure to intern these strings var http_proxy: ?URL = null; - if (url.isHTTP()) { + if (is_http) { if (this.get("http_proxy") orelse this.get("HTTP_PROXY")) |proxy| { if (proxy.len > 0 and !strings.eqlComptime(proxy, "\"\"") and !strings.eqlComptime(proxy, "''")) { http_proxy = URL.parse(proxy); @@ -154,7 +208,7 @@ pub const Loader = struct { // NO_PROXY filter // See the syntax at https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/ - if (http_proxy != null) { + if (http_proxy != null and hostname != null) { if (this.get("no_proxy") orelse this.get("NO_PROXY")) |no_proxy_text| { if (no_proxy_text.len == 0 or strings.eqlComptime(no_proxy_text, "\"\"") or strings.eqlComptime(no_proxy_text, "''")) { return http_proxy; @@ -172,7 +226,7 @@ pub const Loader = struct { host = host[1..]; } //hostname ends with suffix - if (strings.endsWith(url.hostname, host)) { + if (strings.endsWith(hostname.?, host)) { return null; } next = no_proxy_list.next(); diff --git a/src/http.zig b/src/http.zig index 19a346691c..47339a4543 100644 --- a/src/http.zig +++ b/src/http.zig @@ -1216,11 +1216,13 @@ pub const HTTPThread = struct { } } if (client.http_proxy) |url| { - // https://github.com/oven-sh/bun/issues/11343 - if (url.protocol.len == 0 or strings.eqlComptime(url.protocol, "https") or strings.eqlComptime(url.protocol, "http")) { - return try this.context(is_ssl).connect(client, url.hostname, url.getPortAuto()); + if (url.href.len > 0) { + // https://github.com/oven-sh/bun/issues/11343 + if (url.protocol.len == 0 or strings.eqlComptime(url.protocol, "https") or strings.eqlComptime(url.protocol, "http")) { + return try this.context(is_ssl).connect(client, url.hostname, url.getPortAuto()); + } + return error.UnsupportedProxyProtocol; } - return error.UnsupportedProxyProtocol; } return try this.context(is_ssl).connect(client, client.url.hostname, client.url.getPortAuto()); } diff --git a/src/install/install.zig b/src/install/install.zig index 07bc1a8955..d64fc72cfb 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -3102,7 +3102,7 @@ pub const PackageManager = struct { } pub fn httpProxy(this: *PackageManager, url: URL) ?URL { - return this.env.getHttpProxy(url); + return this.env.getHttpProxyFor(url); } pub fn tlsRejectUnauthorized(this: *PackageManager) bool { diff --git a/src/s3.zig b/src/s3.zig new file mode 100644 index 0000000000..aa12dadd49 --- /dev/null +++ b/src/s3.zig @@ -0,0 +1,2182 @@ +const bun = @import("root").bun; +const picohttp = bun.picohttp; +const std = @import("std"); +const DotEnv = @import("./env_loader.zig"); +pub const RareData = @import("./bun.js/rare_data.zig"); + +const JSC = bun.JSC; +const strings = bun.strings; + +pub const AWSCredentials = struct { + accessKeyId: []const u8, + secretAccessKey: []const u8, + region: []const u8, + endpoint: []const u8, + bucket: []const u8, + + ref_count: u32 = 1, + pub usingnamespace bun.NewRefCounted(@This(), @This().deinit); + + pub fn estimatedSize(this: *const @This()) usize { + return @sizeOf(AWSCredentials) + this.accessKeyId.len + this.region.len + this.secretAccessKey.len + this.endpoint.len + this.bucket.len; + } + + pub const AWSCredentialsWithOptions = struct { + credentials: AWSCredentials, + options: MultiPartUpload.MultiPartUploadOptions = .{}, + + _accessKeyIdSlice: ?JSC.ZigString.Slice = null, + _secretAccessKeySlice: ?JSC.ZigString.Slice = null, + _regionSlice: ?JSC.ZigString.Slice = null, + _endpointSlice: ?JSC.ZigString.Slice = null, + _bucketSlice: ?JSC.ZigString.Slice = null, + + pub fn deinit(this: *@This()) void { + if (this._accessKeyIdSlice) |slice| slice.deinit(); + if (this._secretAccessKeySlice) |slice| slice.deinit(); + if (this._regionSlice) |slice| slice.deinit(); + if (this._endpointSlice) |slice| slice.deinit(); + if (this._bucketSlice) |slice| slice.deinit(); + } + }; + pub fn getCredentialsWithOptions(this: AWSCredentials, options: ?JSC.JSValue, globalObject: *JSC.JSGlobalObject) bun.JSError!AWSCredentialsWithOptions { + // get ENV config + var new_credentials = AWSCredentialsWithOptions{ + .credentials = this, + .options = .{}, + }; + errdefer { + new_credentials.deinit(); + } + + if (options) |opts| { + if (opts.isObject()) { + if (try opts.getTruthyComptime(globalObject, "accessKeyId")) |js_value| { + if (!js_value.isEmptyOrUndefinedOrNull()) { + if (js_value.isString()) { + const str = bun.String.fromJS(js_value, globalObject); + defer str.deref(); + if (str.tag != .Empty and str.tag != .Dead) { + new_credentials._accessKeyIdSlice = str.toUTF8(bun.default_allocator); + new_credentials.credentials.accessKeyId = new_credentials._accessKeyIdSlice.?.slice(); + } + } else { + return globalObject.throwInvalidArgumentTypeValue("accessKeyId", "string", js_value); + } + } + } + if (try opts.getTruthyComptime(globalObject, "secretAccessKey")) |js_value| { + if (!js_value.isEmptyOrUndefinedOrNull()) { + if (js_value.isString()) { + const str = bun.String.fromJS(js_value, globalObject); + defer str.deref(); + if (str.tag != .Empty and str.tag != .Dead) { + new_credentials._secretAccessKeySlice = str.toUTF8(bun.default_allocator); + new_credentials.credentials.secretAccessKey = new_credentials._secretAccessKeySlice.?.slice(); + } + } else { + return globalObject.throwInvalidArgumentTypeValue("secretAccessKey", "string", js_value); + } + } + } + if (try opts.getTruthyComptime(globalObject, "region")) |js_value| { + if (!js_value.isEmptyOrUndefinedOrNull()) { + if (js_value.isString()) { + const str = bun.String.fromJS(js_value, globalObject); + defer str.deref(); + if (str.tag != .Empty and str.tag != .Dead) { + new_credentials._regionSlice = str.toUTF8(bun.default_allocator); + new_credentials.credentials.region = new_credentials._regionSlice.?.slice(); + } + } else { + return globalObject.throwInvalidArgumentTypeValue("region", "string", js_value); + } + } + } + if (try opts.getTruthyComptime(globalObject, "endpoint")) |js_value| { + if (!js_value.isEmptyOrUndefinedOrNull()) { + if (js_value.isString()) { + const str = bun.String.fromJS(js_value, globalObject); + defer str.deref(); + if (str.tag != .Empty and str.tag != .Dead) { + new_credentials._endpointSlice = str.toUTF8(bun.default_allocator); + const normalized_endpoint = bun.URL.parse(new_credentials._endpointSlice.?.slice()).host; + if (normalized_endpoint.len > 0) { + new_credentials.credentials.endpoint = normalized_endpoint; + } + } + } else { + return globalObject.throwInvalidArgumentTypeValue("endpoint", "string", js_value); + } + } + } + if (try opts.getTruthyComptime(globalObject, "bucket")) |js_value| { + if (!js_value.isEmptyOrUndefinedOrNull()) { + if (js_value.isString()) { + const str = bun.String.fromJS(js_value, globalObject); + defer str.deref(); + if (str.tag != .Empty and str.tag != .Dead) { + new_credentials._bucketSlice = str.toUTF8(bun.default_allocator); + new_credentials.credentials.bucket = new_credentials._bucketSlice.?.slice(); + } + } else { + return globalObject.throwInvalidArgumentTypeValue("bucket", "string", js_value); + } + } + } + + if (try opts.getOptional(globalObject, "pageSize", i32)) |pageSize| { + if (pageSize < MultiPartUpload.MIN_SINGLE_UPLOAD_SIZE_IN_MiB and pageSize > MultiPartUpload.MAX_SINGLE_UPLOAD_SIZE_IN_MiB) { + return globalObject.throwRangeError(pageSize, .{ + .min = @intCast(MultiPartUpload.MIN_SINGLE_UPLOAD_SIZE_IN_MiB), + .max = @intCast(MultiPartUpload.MAX_SINGLE_UPLOAD_SIZE_IN_MiB), + .field_name = "pageSize", + }); + } else { + new_credentials.options.partSize = @intCast(pageSize); + } + } + + if (try opts.getOptional(globalObject, "queueSize", i32)) |queueSize| { + if (queueSize < 1) { + return globalObject.throwRangeError(queueSize, .{ + .min = 1, + .field_name = "queueSize", + }); + } else { + new_credentials.options.queueSize = @intCast(@max(queueSize, std.math.maxInt(u8))); + } + } + } + } + return new_credentials; + } + pub fn dupe(this: *const @This()) *AWSCredentials { + return AWSCredentials.new(.{ + .accessKeyId = if (this.accessKeyId.len > 0) + bun.default_allocator.dupe(u8, this.accessKeyId) catch bun.outOfMemory() + else + "", + + .secretAccessKey = if (this.secretAccessKey.len > 0) + bun.default_allocator.dupe(u8, this.secretAccessKey) catch bun.outOfMemory() + else + "", + + .region = if (this.region.len > 0) + bun.default_allocator.dupe(u8, this.region) catch bun.outOfMemory() + else + "", + + .endpoint = if (this.endpoint.len > 0) + bun.default_allocator.dupe(u8, this.endpoint) catch bun.outOfMemory() + else + "", + + .bucket = if (this.bucket.len > 0) + bun.default_allocator.dupe(u8, this.bucket) catch bun.outOfMemory() + else + "", + }); + } + pub fn deinit(this: *@This()) void { + if (this.accessKeyId.len > 0) { + bun.default_allocator.free(this.accessKeyId); + } + if (this.secretAccessKey.len > 0) { + bun.default_allocator.free(this.secretAccessKey); + } + if (this.region.len > 0) { + bun.default_allocator.free(this.region); + } + if (this.endpoint.len > 0) { + bun.default_allocator.free(this.endpoint); + } + if (this.bucket.len > 0) { + bun.default_allocator.free(this.bucket); + } + this.destroy(); + } + + const log = bun.Output.scoped(.AWS, false); + + const DateResult = struct { + // numeric representation of year, month and day (excluding time components) + numeric_day: u64, + date: []const u8, + }; + + fn getAMZDate(allocator: std.mem.Allocator) DateResult { + // We can also use Date.now() but would be slower and would add JSC dependency + // var buffer: [28]u8 = undefined; + // the code bellow is the same as new Date(Date.now()).toISOString() + // JSC.JSValue.getDateNowISOString(globalObject, &buffer); + + // Create UTC timestamp + const secs: u64 = @intCast(@divFloor(std.time.milliTimestamp(), 1000)); + const utc_seconds = std.time.epoch.EpochSeconds{ .secs = secs }; + const utc_day = utc_seconds.getEpochDay(); + const year_and_day = utc_day.calculateYearDay(); + const month_and_day = year_and_day.calculateMonthDay(); + // Get UTC date components + const year = year_and_day.year; + const day = @as(u32, month_and_day.day_index) + 1; // this starts in 0 + const month = month_and_day.month.numeric(); // starts in 1 + + // Get UTC time components + const time = utc_seconds.getDaySeconds(); + const hours = time.getHoursIntoDay(); + const minutes = time.getMinutesIntoHour(); + const seconds = time.getSecondsIntoMinute(); + + // Format the date + return .{ + .numeric_day = secs - time.secs, + .date = std.fmt.allocPrint(allocator, "{d:0>4}{d:0>2}{d:0>2}T{d:0>2}{d:0>2}{d:0>2}Z", .{ + year, + month, + day, + hours, + minutes, + seconds, + }) catch bun.outOfMemory(), + }; + } + + const DIGESTED_HMAC_256_LEN = 32; + pub const SignResult = struct { + amz_date: []const u8, + host: []const u8, + authorization: []const u8, + url: []const u8, + + content_disposition: []const u8, + _headers: [5]picohttp.Header, + _headers_len: u8 = 4, + + pub fn headers(this: *const @This()) []const picohttp.Header { + return this._headers[0..this._headers_len]; + } + + pub fn deinit(this: *const @This()) void { + if (this.amz_date.len > 0) { + bun.default_allocator.free(this.amz_date); + } + + if (this.content_disposition.len > 0) { + bun.default_allocator.free(this.content_disposition); + } + + if (this.host.len > 0) { + bun.default_allocator.free(this.host); + } + + if (this.authorization.len > 0) { + bun.default_allocator.free(this.authorization); + } + + if (this.url.len > 0) { + bun.default_allocator.free(this.url); + } + } + }; + + pub const SignQueryOptions = struct { + expires: usize = 86400, + }; + + pub const SignOptions = struct { + path: []const u8, + method: bun.http.Method, + content_hash: ?[]const u8 = null, + search_params: ?[]const u8 = null, + content_disposition: ?[]const u8 = null, + }; + fn guessRegion(endpoint: []const u8) []const u8 { + if (endpoint.len > 0) { + if (strings.endsWith(endpoint, ".r2.cloudflarestorage.com")) return "auto"; + if (strings.indexOf(endpoint, ".amazonaws.com")) |end| { + if (strings.indexOf(endpoint, "s3.")) |start| { + return endpoint[start + 3 .. end]; + } + } + } + return "us-east-1"; + } + fn toHexChar(value: u8) !u8 { + return switch (value) { + 0...9 => value + '0', + 10...15 => (value - 10) + 'A', + else => error.InvalidHexChar, + }; + } + fn encodeURIComponent(input: []const u8, buffer: []u8) ![]const u8 { + var written: usize = 0; + + for (input) |c| { + switch (c) { + // RFC 3986 Unreserved Characters (do not encode) + 'A'...'Z', 'a'...'z', '0'...'9', '-', '_', '.', '~' => { + if (written >= buffer.len) return error.BufferTooSmall; + buffer[written] = c; + written += 1; + }, + // All other characters need to be percent-encoded + else => { + if (written + 3 > buffer.len) return error.BufferTooSmall; + buffer[written] = '%'; + // Convert byte to hex + const high_nibble: u8 = (c >> 4) & 0xF; + const low_nibble: u8 = c & 0xF; + buffer[written + 1] = try toHexChar(high_nibble); + buffer[written + 2] = try toHexChar(low_nibble); + written += 3; + }, + } + } + + return buffer[0..written]; + } + + const ErrorCodeAndMessage = struct { + code: []const u8, + message: []const u8, + }; + fn getSignErrorMessage(comptime err: anyerror) [:0]const u8 { + return switch (err) { + error.MissingCredentials => return "missing s3 credentials", + error.InvalidMethod => return "method must be GET, PUT, DELETE or HEAD when using s3 protocol", + error.InvalidPath => return "invalid s3 bucket, key combination", + error.InvalidEndpoint => return "invalid s3 endpoint", + else => return "failed to retrieve s3 content check your credentials", + }; + } + pub fn getJSSignError(err: anyerror, globalThis: *JSC.JSGlobalObject) JSC.JSValue { + return switch (err) { + error.MissingCredentials => return globalThis.ERR_AWS_MISSING_CREDENTIALS(getSignErrorMessage(error.MissingCredentials), .{}).toJS(), + error.InvalidMethod => return globalThis.ERR_AWS_INVALID_METHOD(getSignErrorMessage(error.InvalidMethod), .{}).toJS(), + error.InvalidPath => return globalThis.ERR_AWS_INVALID_PATH(getSignErrorMessage(error.InvalidPath), .{}).toJS(), + error.InvalidEndpoint => return globalThis.ERR_AWS_INVALID_ENDPOINT(getSignErrorMessage(error.InvalidEndpoint), .{}).toJS(), + else => return globalThis.ERR_AWS_INVALID_SIGNATURE(getSignErrorMessage(error.SignError), .{}).toJS(), + }; + } + pub fn throwSignError(err: anyerror, globalThis: *JSC.JSGlobalObject) bun.JSError { + return switch (err) { + error.MissingCredentials => globalThis.ERR_AWS_MISSING_CREDENTIALS(getSignErrorMessage(error.MissingCredentials), .{}).throw(), + error.InvalidMethod => globalThis.ERR_AWS_INVALID_METHOD(getSignErrorMessage(error.InvalidMethod), .{}).throw(), + error.InvalidPath => globalThis.ERR_AWS_INVALID_PATH(getSignErrorMessage(error.InvalidPath), .{}).throw(), + error.InvalidEndpoint => globalThis.ERR_AWS_INVALID_ENDPOINT(getSignErrorMessage(error.InvalidEndpoint), .{}).throw(), + else => globalThis.ERR_AWS_INVALID_SIGNATURE(getSignErrorMessage(error.SignError), .{}).throw(), + }; + } + pub fn getSignErrorCodeAndMessage(err: anyerror) ErrorCodeAndMessage { + return switch (err) { + error.MissingCredentials => .{ .code = "MissingCredentials", .message = getSignErrorMessage(error.MissingCredentials) }, + error.InvalidMethod => .{ .code = "InvalidMethod", .message = getSignErrorMessage(error.InvalidMethod) }, + error.InvalidPath => .{ .code = "InvalidPath", .message = getSignErrorMessage(error.InvalidPath) }, + error.InvalidEndpoint => .{ .code = "InvalidEndpoint", .message = getSignErrorMessage(error.InvalidEndpoint) }, + else => .{ .code = "SignError", .message = getSignErrorMessage(error.SignError) }, + }; + } + pub fn signRequest(this: *const @This(), signOptions: SignOptions, signQueryOption: ?SignQueryOptions) !SignResult { + const method = signOptions.method; + const request_path = signOptions.path; + const content_hash = signOptions.content_hash; + const search_params = signOptions.search_params; + + var content_disposition = signOptions.content_disposition; + if (content_disposition != null and content_disposition.?.len == 0) { + content_disposition = null; + } + + if (this.accessKeyId.len == 0 or this.secretAccessKey.len == 0) return error.MissingCredentials; + const signQuery = signQueryOption != null; + const expires = if (signQueryOption) |options| options.expires else 0; + const method_name = switch (method) { + .GET => "GET", + .POST => "POST", + .PUT => "PUT", + .DELETE => "DELETE", + .HEAD => "HEAD", + else => return error.InvalidMethod, + }; + + const region = if (this.region.len > 0) this.region else guessRegion(this.endpoint); + var full_path = request_path; + if (strings.startsWith(full_path, "/")) { + full_path = full_path[1..]; + } + var path: []const u8 = full_path; + var bucket: []const u8 = this.bucket; + + if (bucket.len == 0) { + //TODO: r2 supports bucket in the endpoint + + // guess bucket using path + if (strings.indexOf(full_path, "/")) |end| { + bucket = full_path[0..end]; + path = full_path[end + 1 ..]; + } else { + return error.InvalidPath; + } + } + if (strings.endsWith(path, "/")) { + path = path[0..path.len]; + } + if (strings.startsWith(path, "/")) { + path = path[1..]; + } + + // if we allow path.len == 0 it will list the bucket for now we disallow + if (path.len == 0) return error.InvalidPath; + + var path_buffer: [1024 + 63 + 2]u8 = undefined; // 1024 max key size and 63 max bucket name + + const normalizedPath = std.fmt.bufPrint(&path_buffer, "/{s}/{s}", .{ bucket, path }) catch return error.InvalidPath; + + const date_result = getAMZDate(bun.default_allocator); + const amz_date = date_result.date; + errdefer bun.default_allocator.free(amz_date); + + const amz_day = amz_date[0..8]; + const signed_headers = if (signQuery) "host" else brk: { + if (content_disposition != null) { + break :brk "content-disposition;host;x-amz-content-sha256;x-amz-date"; + } else { + break :brk "host;x-amz-content-sha256;x-amz-date"; + } + }; + // detect service name and host from region or endpoint + var encoded_host_buffer: [512]u8 = undefined; + var encoded_host: []const u8 = ""; + const host = brk_host: { + if (this.endpoint.len > 0) { + encoded_host = encodeURIComponent(this.endpoint, &encoded_host_buffer) catch return error.InvalidEndpoint; + break :brk_host try bun.default_allocator.dupe(u8, this.endpoint); + } else { + break :brk_host try std.fmt.allocPrint(bun.default_allocator, "s3.{s}.amazonaws.com", .{region}); + } + }; + const service_name = "s3"; + + errdefer bun.default_allocator.free(host); + + const aws_content_hash = if (content_hash) |hash| hash else ("UNSIGNED-PAYLOAD"); + var tmp_buffer: [2048]u8 = undefined; + + const authorization = brk: { + // we hash the hash so we need 2 buffers + var hmac_sig_service: [bun.BoringSSL.EVP_MAX_MD_SIZE]u8 = undefined; + var hmac_sig_service2: [bun.BoringSSL.EVP_MAX_MD_SIZE]u8 = undefined; + + const sigDateRegionServiceReq = brk_sign: { + const key = try std.fmt.bufPrint(&tmp_buffer, "{s}{s}{s}", .{ region, service_name, this.secretAccessKey }); + var cache = (JSC.VirtualMachine.getMainThreadVM() orelse JSC.VirtualMachine.get()).rareData().awsCache(); + if (cache.get(date_result.numeric_day, key)) |cached| { + break :brk_sign cached; + } + // not cached yet lets generate a new one + const sigDate = bun.hmac.generate(try std.fmt.bufPrint(&tmp_buffer, "AWS4{s}", .{this.secretAccessKey}), amz_day, .sha256, &hmac_sig_service) orelse return error.FailedToGenerateSignature; + const sigDateRegion = bun.hmac.generate(sigDate, region, .sha256, &hmac_sig_service2) orelse return error.FailedToGenerateSignature; + const sigDateRegionService = bun.hmac.generate(sigDateRegion, service_name, .sha256, &hmac_sig_service) orelse return error.FailedToGenerateSignature; + const result = bun.hmac.generate(sigDateRegionService, "aws4_request", .sha256, &hmac_sig_service2) orelse return error.FailedToGenerateSignature; + + cache.set(date_result.numeric_day, key, hmac_sig_service2[0..DIGESTED_HMAC_256_LEN].*); + break :brk_sign result; + }; + if (signQuery) { + const canonical = try std.fmt.bufPrint(&tmp_buffer, "{s}\n{s}\nX-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential={s}%2F{s}%2F{s}%2F{s}%2Faws4_request&X-Amz-Date={s}&X-Amz-Expires={}&X-Amz-SignedHeaders=host\nhost:{s}\n\n{s}\n{s}", .{ method_name, normalizedPath, this.accessKeyId, amz_day, region, service_name, amz_date, expires, if (encoded_host.len > 0) encoded_host else host, signed_headers, aws_content_hash }); + var sha_digest = std.mem.zeroes(bun.sha.SHA256.Digest); + bun.sha.SHA256.hash(canonical, &sha_digest, JSC.VirtualMachine.get().rareData().boringEngine()); + + const signValue = try std.fmt.bufPrint(&tmp_buffer, "AWS4-HMAC-SHA256\n{s}\n{s}/{s}/{s}/aws4_request\n{s}", .{ amz_date, amz_day, region, service_name, bun.fmt.bytesToHex(sha_digest[0..bun.sha.SHA256.digest], .lower) }); + + const signature = bun.hmac.generate(sigDateRegionServiceReq, signValue, .sha256, &hmac_sig_service) orelse return error.FailedToGenerateSignature; + break :brk try std.fmt.allocPrint( + bun.default_allocator, + "https://{s}{s}?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential={s}%2F{s}%2F{s}%2F{s}%2Faws4_request&X-Amz-Date={s}&X-Amz-Expires={}&X-Amz-SignedHeaders=host&X-Amz-Signature={s}", + .{ host, normalizedPath, this.accessKeyId, amz_day, region, service_name, amz_date, expires, bun.fmt.bytesToHex(signature[0..DIGESTED_HMAC_256_LEN], .lower) }, + ); + } else { + var encoded_content_disposition_buffer: [255]u8 = undefined; + const encoded_content_disposition: []const u8 = if (content_disposition) |cd| encodeURIComponent(cd, &encoded_content_disposition_buffer) catch return error.ContentTypeIsTooLong else ""; + const canonical = brk_canonical: { + if (content_disposition != null) { + break :brk_canonical try std.fmt.bufPrint(&tmp_buffer, "{s}\n{s}\n{s}\ncontent-disposition:{s}\nhost:{s}\nx-amz-content-sha256:{s}\nx-amz-date:{s}\n\n{s}\n{s}", .{ method_name, normalizedPath, if (search_params) |p| p[1..] else "", encoded_content_disposition, if (encoded_host.len > 0) encoded_host else host, aws_content_hash, amz_date, signed_headers, aws_content_hash }); + } else { + break :brk_canonical try std.fmt.bufPrint(&tmp_buffer, "{s}\n{s}\n{s}\nhost:{s}\nx-amz-content-sha256:{s}\nx-amz-date:{s}\n\n{s}\n{s}", .{ method_name, normalizedPath, if (search_params) |p| p[1..] else "", if (encoded_host.len > 0) encoded_host else host, aws_content_hash, amz_date, signed_headers, aws_content_hash }); + } + }; + var sha_digest = std.mem.zeroes(bun.sha.SHA256.Digest); + bun.sha.SHA256.hash(canonical, &sha_digest, JSC.VirtualMachine.get().rareData().boringEngine()); + + const signValue = try std.fmt.bufPrint(&tmp_buffer, "AWS4-HMAC-SHA256\n{s}\n{s}/{s}/{s}/aws4_request\n{s}", .{ amz_date, amz_day, region, service_name, bun.fmt.bytesToHex(sha_digest[0..bun.sha.SHA256.digest], .lower) }); + + const signature = bun.hmac.generate(sigDateRegionServiceReq, signValue, .sha256, &hmac_sig_service) orelse return error.FailedToGenerateSignature; + + break :brk try std.fmt.allocPrint( + bun.default_allocator, + "AWS4-HMAC-SHA256 Credential={s}/{s}/{s}/{s}/aws4_request, SignedHeaders={s}, Signature={s}", + .{ this.accessKeyId, amz_day, region, service_name, signed_headers, bun.fmt.bytesToHex(signature[0..DIGESTED_HMAC_256_LEN], .lower) }, + ); + } + }; + errdefer bun.default_allocator.free(authorization); + + if (signQuery) { + defer bun.default_allocator.free(host); + defer bun.default_allocator.free(amz_date); + + return SignResult{ + .amz_date = "", + .host = "", + .authorization = "", + .url = authorization, + .content_disposition = "", + ._headers = .{ + .{ .name = "", .value = "" }, + .{ .name = "", .value = "" }, + .{ .name = "", .value = "" }, + .{ .name = "", .value = "" }, + .{ .name = "", .value = "" }, + }, + ._headers_len = 0, + }; + } + + if (content_disposition) |cd| { + const content_disposition_value = bun.default_allocator.dupe(u8, cd) catch bun.outOfMemory(); + return SignResult{ + .amz_date = amz_date, + .host = host, + .authorization = authorization, + .url = try std.fmt.allocPrint(bun.default_allocator, "https://{s}{s}{s}", .{ host, normalizedPath, if (search_params) |s| s else "" }), + .content_disposition = content_disposition_value, + ._headers = .{ + .{ .name = "x-amz-content-sha256", .value = aws_content_hash }, + .{ .name = "x-amz-date", .value = amz_date }, + .{ .name = "Authorization", .value = authorization[0..] }, + .{ .name = "Host", .value = host }, + .{ .name = "Content-Disposition", .value = content_disposition_value }, + }, + ._headers_len = 5, + }; + } + return SignResult{ + .amz_date = amz_date, + .host = host, + .authorization = authorization, + .url = try std.fmt.allocPrint(bun.default_allocator, "https://{s}{s}{s}", .{ host, normalizedPath, if (search_params) |s| s else "" }), + .content_disposition = "", + ._headers = .{ + .{ .name = "x-amz-content-sha256", .value = aws_content_hash }, + .{ .name = "x-amz-date", .value = amz_date }, + .{ .name = "Authorization", .value = authorization[0..] }, + .{ .name = "Host", .value = host }, + .{ .name = "", .value = "" }, + }, + ._headers_len = 4, + }; + } + pub const S3Error = struct { + code: []const u8, + message: []const u8, + + pub fn toJS(err: *const @This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + const js_err = globalObject.createErrorInstance("{s}", .{err.message}); + js_err.put(globalObject, JSC.ZigString.static("code"), JSC.ZigString.init(err.code).toJS(globalObject)); + return js_err; + } + }; + pub const S3StatResult = union(enum) { + success: struct { + size: usize = 0, + /// etag is not owned and need to be copied if used after this callback + etag: []const u8 = "", + }, + not_found: void, + + /// failure error is not owned and need to be copied if used after this callback + failure: S3Error, + }; + pub const S3DownloadResult = union(enum) { + success: struct { + /// etag is not owned and need to be copied if used after this callback + etag: []const u8 = "", + /// body is owned and dont need to be copied, but dont forget to free it + body: bun.MutableString, + }, + not_found: void, + /// failure error is not owned and need to be copied if used after this callback + failure: S3Error, + }; + pub const S3UploadResult = union(enum) { + success: void, + /// failure error is not owned and need to be copied if used after this callback + failure: S3Error, + }; + pub const S3DeleteResult = union(enum) { + success: void, + not_found: void, + + /// failure error is not owned and need to be copied if used after this callback + failure: S3Error, + }; + // commit result also fails if status 200 but with body containing an Error + pub const S3CommitResult = union(enum) { + success: void, + /// failure error is not owned and need to be copied if used after this callback + failure: S3Error, + }; + // commit result also fails if status 200 but with body containing an Error + pub const S3PartResult = union(enum) { + etag: []const u8, + /// failure error is not owned and need to be copied if used after this callback + failure: S3Error, + }; + pub const S3HttpSimpleTask = struct { + http: bun.http.AsyncHTTP, + vm: *JSC.VirtualMachine, + sign_result: SignResult, + headers: JSC.WebCore.Headers, + callback_context: *anyopaque, + callback: Callback, + response_buffer: bun.MutableString = .{ + .allocator = bun.default_allocator, + .list = .{ + .items = &.{}, + .capacity = 0, + }, + }, + result: bun.http.HTTPClientResult = .{}, + concurrent_task: JSC.ConcurrentTask = .{}, + range: ?[]const u8, + poll_ref: bun.Async.KeepAlive = bun.Async.KeepAlive.init(), + + usingnamespace bun.New(@This()); + pub const Callback = union(enum) { + stat: *const fn (S3StatResult, *anyopaque) void, + download: *const fn (S3DownloadResult, *anyopaque) void, + upload: *const fn (S3UploadResult, *anyopaque) void, + delete: *const fn (S3DeleteResult, *anyopaque) void, + commit: *const fn (S3CommitResult, *anyopaque) void, + part: *const fn (S3PartResult, *anyopaque) void, + + pub fn fail(this: @This(), code: []const u8, message: []const u8, context: *anyopaque) void { + switch (this) { + inline .upload, + .download, + .stat, + .delete, + .commit, + .part, + => |callback| callback(.{ + .failure = .{ + .code = code, + .message = message, + }, + }, context), + } + } + }; + pub fn deinit(this: *@This()) void { + if (this.result.certificate_info) |*certificate| { + certificate.deinit(bun.default_allocator); + } + this.poll_ref.unref(this.vm); + this.response_buffer.deinit(); + this.headers.deinit(); + this.sign_result.deinit(); + this.http.clearData(); + if (this.range) |range| { + bun.default_allocator.free(range); + } + if (this.result.metadata) |*metadata| { + metadata.deinit(bun.default_allocator); + } + this.destroy(); + } + + fn fail(this: *@This()) void { + var code: []const u8 = "UnknownError"; + var message: []const u8 = "an unexpected error has occurred"; + if (this.result.fail) |err| { + code = @errorName(err); + } else if (this.result.body) |body| { + const bytes = body.list.items; + if (bytes.len > 0) { + message = bytes[0..]; + if (strings.indexOf(bytes, "")) |start| { + if (strings.indexOf(bytes, "")) |end| { + code = bytes[start + "".len .. end]; + } + } + if (strings.indexOf(bytes, "")) |start| { + if (strings.indexOf(bytes, "")) |end| { + message = bytes[start + "".len .. end]; + } + } + } + } + this.callback.fail(code, message, this.callback_context); + } + + fn failIfContainsError(this: *@This(), status: u32) bool { + var code: []const u8 = "UnknownError"; + var message: []const u8 = "an unexpected error has occurred"; + + if (this.result.fail) |err| { + code = @errorName(err); + } else if (this.result.body) |body| { + const bytes = body.list.items; + var has_error = false; + if (bytes.len > 0) { + message = bytes[0..]; + if (strings.indexOf(bytes, "") != null) { + has_error = true; + if (strings.indexOf(bytes, "")) |start| { + if (strings.indexOf(bytes, "")) |end| { + code = bytes[start + "".len .. end]; + } + } + if (strings.indexOf(bytes, "")) |start| { + if (strings.indexOf(bytes, "")) |end| { + message = bytes[start + "".len .. end]; + } + } + } + } + if (!has_error and status == 200 or status == 206) { + return false; + } + } else if (status == 200 or status == 206) { + return false; + } + this.callback.fail(code, message, this.callback_context); + return true; + } + + pub fn onResponse(this: *@This()) void { + defer this.deinit(); + if (!this.result.isSuccess()) { + this.fail(); + return; + } + bun.assert(this.result.metadata != null); + const response = this.result.metadata.?.response; + switch (this.callback) { + .stat => |callback| { + switch (response.status_code) { + 404 => { + callback(.{ .not_found = {} }, this.callback_context); + }, + 200 => { + callback(.{ + .success = .{ + .etag = response.headers.get("etag") orelse "", + .size = if (response.headers.get("content-length")) |content_len| (std.fmt.parseInt(usize, content_len, 10) catch 0) else 0, + }, + }, this.callback_context); + }, + else => { + this.fail(); + }, + } + }, + .delete => |callback| { + switch (response.status_code) { + 404 => { + callback(.{ .not_found = {} }, this.callback_context); + }, + 200, 204 => { + callback(.{ .success = {} }, this.callback_context); + }, + else => { + this.fail(); + }, + } + }, + .upload => |callback| { + switch (response.status_code) { + 200 => { + callback(.{ .success = {} }, this.callback_context); + }, + else => { + this.fail(); + }, + } + }, + .download => |callback| { + switch (response.status_code) { + 404 => { + callback(.{ .not_found = {} }, this.callback_context); + }, + 200, 204, 206 => { + const body = this.response_buffer; + this.response_buffer = .{ + .allocator = bun.default_allocator, + .list = .{ + .items = &.{}, + .capacity = 0, + }, + }; + callback(.{ + .success = .{ + .etag = response.headers.get("etag") orelse "", + .body = body, + }, + }, this.callback_context); + }, + else => { + //error + this.fail(); + }, + } + }, + .commit => |callback| { + // commit multipart upload can fail with status 200 + if (!this.failIfContainsError(response.status_code)) { + callback(.{ .success = {} }, this.callback_context); + } + }, + .part => |callback| { + if (!this.failIfContainsError(response.status_code)) { + if (response.headers.get("etag")) |etag| { + callback(.{ .etag = etag }, this.callback_context); + } else { + this.fail(); + } + } + }, + } + } + + pub fn http_callback(this: *@This(), async_http: *bun.http.AsyncHTTP, result: bun.http.HTTPClientResult) void { + const is_done = !result.has_more; + this.result = result; + this.http = async_http.*; + this.response_buffer = async_http.response_buffer.*; + if (is_done) { + this.vm.eventLoop().enqueueTaskConcurrent(this.concurrent_task.from(this, .manual_deinit)); + } + } + }; + + pub const S3HttpDownloadStreamingTask = struct { + http: bun.http.AsyncHTTP, + vm: *JSC.VirtualMachine, + sign_result: SignResult, + headers: JSC.WebCore.Headers, + callback_context: *anyopaque, + // this transfers ownership from the chunk + callback: *const fn (chunk: bun.MutableString, has_more: bool, err: ?S3Error, *anyopaque) void, + has_schedule_callback: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), + signal_store: bun.http.Signals.Store = .{}, + signals: bun.http.Signals = .{}, + poll_ref: bun.Async.KeepAlive = bun.Async.KeepAlive.init(), + + response_buffer: bun.MutableString = .{ + .allocator = bun.default_allocator, + .list = .{ + .items = &.{}, + .capacity = 0, + }, + }, + reported_response_lock: bun.Lock = .{}, + reported_response_buffer: bun.MutableString = .{ + .allocator = bun.default_allocator, + .list = .{ + .items = &.{}, + .capacity = 0, + }, + }, + state: State.AtomicType = State.AtomicType.init(0), + + concurrent_task: JSC.ConcurrentTask = .{}, + range: ?[]const u8, + proxy_url: []const u8, + + usingnamespace bun.New(@This()); + pub const State = packed struct(u64) { + pub const AtomicType = std.atomic.Value(u64); + status_code: u32 = 0, + request_error: u16 = 0, + has_more: bool = false, + _reserved: u15 = 0, + }; + + pub fn getState(this: @This()) State { + const state: State = @bitCast(this.state.load(.acquire)); + return state; + } + + pub fn setState(this: *@This(), state: State) void { + this.state.store(@bitCast(state), .monotonic); + } + + pub fn deinit(this: *@This()) void { + this.poll_ref.unref(this.vm); + this.response_buffer.deinit(); + this.reported_response_buffer.deinit(); + this.headers.deinit(); + this.sign_result.deinit(); + this.http.clearData(); + if (this.range) |range| { + bun.default_allocator.free(range); + } + if (this.proxy_url.len > 0) { + bun.default_allocator.free(this.proxy_url); + } + + this.destroy(); + } + + fn reportProgress(this: *@This()) bool { + var has_more = true; + var err: ?S3Error = null; + var failed = false; + this.reported_response_lock.lock(); + defer this.reported_response_lock.unlock(); + const chunk = brk: { + const state = this.getState(); + has_more = state.has_more; + switch (state.status_code) { + 200, 204, 206 => { + failed = state.request_error != 0; + }, + else => { + failed = true; + }, + } + if (failed) { + if (!has_more) { + var has_body_code = false; + var has_body_message = false; + + var code: []const u8 = "UnknownError"; + var message: []const u8 = "an unexpected error has occurred"; + if (state.request_error != 0) { + const req_err = @errorFromInt(state.request_error); + code = @errorName(req_err); + has_body_code = true; + } else { + const bytes = this.reported_response_buffer.list.items; + if (bytes.len > 0) { + message = bytes[0..]; + + if (strings.indexOf(bytes, "")) |start| { + if (strings.indexOf(bytes, "")) |end| { + code = bytes[start + "".len .. end]; + has_body_code = true; + } + } + if (strings.indexOf(bytes, "")) |start| { + if (strings.indexOf(bytes, "")) |end| { + message = bytes[start + "".len .. end]; + has_body_message = true; + } + } + } + } + if (state.status_code == 404) { + if (!has_body_code) { + code = "FileNotFound"; + } + if (!has_body_message) { + message = "File not found"; + } + } + err = .{ + .code = code, + .message = message, + }; + } + break :brk bun.MutableString{ .allocator = bun.default_allocator, .list = .{} }; + } else { + const buffer = this.reported_response_buffer; + break :brk buffer; + } + }; + log("reportProgres failed: {} has_more: {} len: {d}", .{ failed, has_more, chunk.list.items.len }); + if (failed) { + if (!has_more) { + this.callback(chunk, false, err, this.callback_context); + } + } else { + // dont report empty chunks if we have more data to read + if (!has_more or chunk.list.items.len > 0) { + this.callback(chunk, has_more, null, this.callback_context); + this.reported_response_buffer.reset(); + } + } + + return has_more; + } + + pub fn onResponse(this: *@This()) void { + this.has_schedule_callback.store(false, .monotonic); + const has_more = this.reportProgress(); + if (!has_more) this.deinit(); + } + + pub fn http_callback(this: *@This(), async_http: *bun.http.AsyncHTTP, result: bun.http.HTTPClientResult) void { + const is_done = !result.has_more; + var state = this.getState(); + + var wait_until_done = false; + { + state.has_more = !is_done; + + state.request_error = if (result.fail) |err| @intFromError(err) else 0; + if (state.status_code == 0) { + if (result.certificate_info) |*certificate| { + certificate.deinit(bun.default_allocator); + } + if (result.metadata) |m| { + var metadata = m; + state.status_code = metadata.response.status_code; + metadata.deinit(bun.default_allocator); + } + } + switch (state.status_code) { + 200, 204, 206 => wait_until_done = state.request_error != 0, + else => wait_until_done = true, + } + this.setState(state); + this.http = async_http.*; + } + // if we got a error or fail wait until we are done buffering the response body to report + const should_enqueue = !wait_until_done or is_done; + log("state err: {} status_code: {} has_more: {} should_enqueue: {}", .{ state.request_error, state.status_code, state.has_more, should_enqueue }); + if (should_enqueue) { + if (result.body) |body| { + this.reported_response_lock.lock(); + defer this.reported_response_lock.unlock(); + this.response_buffer = body.*; + if (body.list.items.len > 0) { + _ = this.reported_response_buffer.write(body.list.items) catch bun.outOfMemory(); + } + this.response_buffer.reset(); + if (this.reported_response_buffer.list.items.len == 0 and !is_done) { + return; + } + } else if (!is_done) { + return; + } + if (this.has_schedule_callback.cmpxchgStrong(false, true, .acquire, .monotonic)) |has_schedule_callback| { + if (has_schedule_callback) { + return; + } + } + this.vm.eventLoop().enqueueTaskConcurrent(this.concurrent_task.from(this, .manual_deinit)); + } + } + }; + + pub const S3SimpleRequestOptions = struct { + // signing options + path: []const u8, + method: bun.http.Method, + search_params: ?[]const u8 = null, + content_type: ?[]const u8 = null, + content_disposition: ?[]const u8 = null, + + // http request options + body: []const u8, + proxy_url: ?[]const u8 = null, + range: ?[]const u8 = null, + }; + + pub fn executeSimpleS3Request( + this: *const @This(), + options: S3SimpleRequestOptions, + callback: S3HttpSimpleTask.Callback, + callback_context: *anyopaque, + ) void { + var result = this.signRequest(.{ + .path = options.path, + .method = options.method, + .search_params = options.search_params, + .content_disposition = options.content_disposition, + }, null) catch |sign_err| { + if (options.range) |range_| bun.default_allocator.free(range_); + const error_code_and_message = getSignErrorCodeAndMessage(sign_err); + callback.fail(error_code_and_message.code, error_code_and_message.message, callback_context); + return; + }; + + const headers = brk: { + if (options.range) |range_| { + const _headers = result.headers(); + var headersWithRange: [5]picohttp.Header = .{ + _headers[0], + _headers[1], + _headers[2], + _headers[3], + .{ .name = "range", .value = range_ }, + }; + break :brk JSC.WebCore.Headers.fromPicoHttpHeaders(&headersWithRange, bun.default_allocator) catch bun.outOfMemory(); + } else { + if (options.content_type) |content_type| { + if (content_type.len > 0) { + const _headers = result.headers(); + if (_headers.len > 4) { + var headersWithContentType: [6]picohttp.Header = .{ + _headers[0], + _headers[1], + _headers[2], + _headers[3], + _headers[4], + .{ .name = "Content-Type", .value = content_type }, + }; + break :brk JSC.WebCore.Headers.fromPicoHttpHeaders(&headersWithContentType, bun.default_allocator) catch bun.outOfMemory(); + } + + var headersWithContentType: [5]picohttp.Header = .{ + _headers[0], + _headers[1], + _headers[2], + _headers[3], + .{ .name = "Content-Type", .value = content_type }, + }; + break :brk JSC.WebCore.Headers.fromPicoHttpHeaders(&headersWithContentType, bun.default_allocator) catch bun.outOfMemory(); + } + } + + break :brk JSC.WebCore.Headers.fromPicoHttpHeaders(result.headers(), bun.default_allocator) catch bun.outOfMemory(); + } + }; + const task = S3HttpSimpleTask.new(.{ + .http = undefined, + .sign_result = result, + .callback_context = callback_context, + .callback = callback, + .range = options.range, + .headers = headers, + .vm = JSC.VirtualMachine.get(), + }); + task.poll_ref.ref(task.vm); + + const url = bun.URL.parse(result.url); + const proxy = options.proxy_url orelse ""; + task.http = bun.http.AsyncHTTP.init( + bun.default_allocator, + options.method, + url, + task.headers.entries, + task.headers.buf.items, + &task.response_buffer, + options.body, + bun.http.HTTPClientResult.Callback.New( + *S3HttpSimpleTask, + S3HttpSimpleTask.http_callback, + ).init(task), + .follow, + .{ + .http_proxy = if (proxy.len > 0) bun.URL.parse(proxy) else null, + .verbose = .none, + .reject_unauthorized = task.vm.getTLSRejectUnauthorized(), + }, + ); + // queue http request + bun.http.HTTPThread.init(&.{}); + var batch = bun.ThreadPool.Batch{}; + task.http.schedule(bun.default_allocator, &batch); + bun.http.http_thread.schedule(batch); + } + + pub fn s3Stat(this: *const @This(), path: []const u8, callback: *const fn (S3StatResult, *anyopaque) void, callback_context: *anyopaque, proxy_url: ?[]const u8) void { + this.executeSimpleS3Request(.{ + .path = path, + .method = .HEAD, + .proxy_url = proxy_url, + .body = "", + }, .{ .stat = callback }, callback_context); + } + + pub fn s3Download(this: *const @This(), path: []const u8, callback: *const fn (S3DownloadResult, *anyopaque) void, callback_context: *anyopaque, proxy_url: ?[]const u8) void { + this.executeSimpleS3Request(.{ + .path = path, + .method = .GET, + .proxy_url = proxy_url, + .body = "", + }, .{ .download = callback }, callback_context); + } + + pub fn s3DownloadSlice(this: *const @This(), path: []const u8, offset: usize, size: ?usize, callback: *const fn (S3DownloadResult, *anyopaque) void, callback_context: *anyopaque, proxy_url: ?[]const u8) void { + const range = brk: { + if (size) |size_| { + if (offset == 0) break :brk null; + + var end = (offset + size_); + if (size_ > 0) { + end -= 1; + } + break :brk std.fmt.allocPrint(bun.default_allocator, "bytes={}-{}", .{ offset, end }) catch bun.outOfMemory(); + } + if (offset == 0) break :brk null; + break :brk std.fmt.allocPrint(bun.default_allocator, "bytes={}-", .{offset}) catch bun.outOfMemory(); + }; + + this.executeSimpleS3Request(.{ + .path = path, + .method = .GET, + .proxy_url = proxy_url, + .body = "", + .range = range, + }, .{ .download = callback }, callback_context); + } + + pub fn s3StreamDownload(this: *@This(), path: []const u8, offset: usize, size: ?usize, proxy_url: ?[]const u8, callback: *const fn (chunk: bun.MutableString, has_more: bool, err: ?S3Error, *anyopaque) void, callback_context: *anyopaque) void { + const range = brk: { + if (size) |size_| { + if (offset == 0) break :brk null; + + var end = (offset + size_); + if (size_ > 0) { + end -= 1; + } + break :brk std.fmt.allocPrint(bun.default_allocator, "bytes={}-{}", .{ offset, end }) catch bun.outOfMemory(); + } + if (offset == 0) break :brk null; + break :brk std.fmt.allocPrint(bun.default_allocator, "bytes={}-", .{offset}) catch bun.outOfMemory(); + }; + + var result = this.signRequest(.{ + .path = path, + .method = .GET, + }, null) catch |sign_err| { + if (range) |range_| bun.default_allocator.free(range_); + const error_code_and_message = getSignErrorCodeAndMessage(sign_err); + callback(.{ .allocator = bun.default_allocator, .list = .{} }, false, .{ .code = error_code_and_message.code, .message = error_code_and_message.message }, callback_context); + return; + }; + + const headers = brk: { + if (range) |range_| { + const _headers = result.headers(); + var headersWithRange: [5]picohttp.Header = .{ + _headers[0], + _headers[1], + _headers[2], + _headers[3], + .{ .name = "range", .value = range_ }, + }; + break :brk JSC.WebCore.Headers.fromPicoHttpHeaders(&headersWithRange, bun.default_allocator) catch bun.outOfMemory(); + } else { + break :brk JSC.WebCore.Headers.fromPicoHttpHeaders(result.headers(), bun.default_allocator) catch bun.outOfMemory(); + } + }; + const proxy = proxy_url orelse ""; + const owned_proxy = if (proxy.len > 0) bun.default_allocator.dupe(u8, proxy) catch bun.outOfMemory() else ""; + const task = S3HttpDownloadStreamingTask.new(.{ + .http = undefined, + .sign_result = result, + .proxy_url = owned_proxy, + .callback_context = callback_context, + .callback = callback, + .range = range, + .headers = headers, + .vm = JSC.VirtualMachine.get(), + }); + task.poll_ref.ref(task.vm); + + const url = bun.URL.parse(result.url); + + task.signals = task.signal_store.to(); + + task.http = bun.http.AsyncHTTP.init( + bun.default_allocator, + .GET, + url, + task.headers.entries, + task.headers.buf.items, + &task.response_buffer, + "", + bun.http.HTTPClientResult.Callback.New( + *S3HttpDownloadStreamingTask, + S3HttpDownloadStreamingTask.http_callback, + ).init(task), + .follow, + .{ + .http_proxy = if (owned_proxy.len > 0) bun.URL.parse(owned_proxy) else null, + .verbose = .none, + .signals = task.signals, + .reject_unauthorized = task.vm.getTLSRejectUnauthorized(), + }, + ); + // enable streaming + task.http.enableBodyStreaming(); + // queue http request + bun.http.HTTPThread.init(&.{}); + var batch = bun.ThreadPool.Batch{}; + task.http.schedule(bun.default_allocator, &batch); + bun.http.http_thread.schedule(batch); + } + + pub fn s3ReadableStream(this: *@This(), path: []const u8, offset: usize, size: ?usize, proxy_url: ?[]const u8, globalThis: *JSC.JSGlobalObject) JSC.JSValue { + var reader = JSC.WebCore.ByteStream.Source.new(.{ + .context = undefined, + .globalThis = globalThis, + }); + + reader.context.setup(); + const readable_value = reader.toReadableStream(globalThis); + + this.s3StreamDownload(path, offset, size, proxy_url, @ptrCast(&S3DownloadStreamWrapper.callback), S3DownloadStreamWrapper.new(.{ + .readable_stream_ref = JSC.WebCore.ReadableStream.Strong.init(.{ + .ptr = .{ .Bytes = &reader.context }, + .value = readable_value, + }, globalThis), + })); + return readable_value; + } + + const S3DownloadStreamWrapper = struct { + readable_stream_ref: JSC.WebCore.ReadableStream.Strong, + pub usingnamespace bun.New(@This()); + + pub fn callback(chunk: bun.MutableString, has_more: bool, request_err: ?S3Error, this: *@This()) void { + defer if (!has_more) this.deinit(); + + if (this.readable_stream_ref.get()) |readable| { + if (readable.ptr == .Bytes) { + const globalThis = this.readable_stream_ref.globalThis().?; + + if (request_err) |err| { + log("S3DownloadStreamWrapper.callback .temporary", .{}); + + readable.ptr.Bytes.onData( + .{ + .err = .{ .JSValue = err.toJS(globalThis) }, + }, + bun.default_allocator, + ); + return; + } + if (has_more) { + log("S3DownloadStreamWrapper.callback .temporary", .{}); + + readable.ptr.Bytes.onData( + .{ + .temporary = bun.ByteList.initConst(chunk.list.items), + }, + bun.default_allocator, + ); + return; + } + log("S3DownloadStreamWrapper.callback .temporary_and_done", .{}); + + readable.ptr.Bytes.onData( + .{ + .temporary_and_done = bun.ByteList.initConst(chunk.list.items), + }, + bun.default_allocator, + ); + return; + } + } + log("S3DownloadStreamWrapper.callback invalid readable stream", .{}); + } + + pub fn deinit(this: *@This()) void { + this.readable_stream_ref.deinit(); + this.destroy(); + } + }; + + pub fn s3Delete(this: *const @This(), path: []const u8, callback: *const fn (S3DeleteResult, *anyopaque) void, callback_context: *anyopaque, proxy_url: ?[]const u8) void { + this.executeSimpleS3Request(.{ + .path = path, + .method = .DELETE, + .proxy_url = proxy_url, + .body = "", + }, .{ .delete = callback }, callback_context); + } + + pub fn s3Upload(this: *const @This(), path: []const u8, content: []const u8, content_type: ?[]const u8, proxy_url: ?[]const u8, callback: *const fn (S3UploadResult, *anyopaque) void, callback_context: *anyopaque) void { + this.executeSimpleS3Request(.{ + .path = path, + .method = .PUT, + .proxy_url = proxy_url, + .body = content, + .content_type = content_type, + }, .{ .upload = callback }, callback_context); + } + + const S3UploadStreamWrapper = struct { + readable_stream_ref: JSC.WebCore.ReadableStream.Strong, + sink: *JSC.WebCore.FetchTaskletChunkedRequestSink, + callback: ?*const fn (S3UploadResult, *anyopaque) void, + callback_context: *anyopaque, + ref_count: u32 = 1, + pub usingnamespace bun.NewRefCounted(@This(), @This().deinit); + pub fn resolve(result: S3UploadResult, self: *@This()) void { + const sink = self.sink; + defer self.deref(); + + if (sink.endPromise.globalObject()) |globalObject| { + switch (result) { + .success => sink.endPromise.resolve(globalObject, JSC.jsNumber(0)), + .failure => |err| { + if (!sink.done) { + sink.abort(); + return; + } + sink.endPromise.rejectOnNextTick(globalObject, err.toJS(globalObject)); + }, + } + } + if (self.callback) |callback| { + callback(result, self.callback_context); + } + } + + pub fn deinit(self: *@This()) void { + self.readable_stream_ref.deinit(); + self.sink.finalize(); + self.sink.destroy(); + self.destroy(); + } + }; + pub fn onUploadStreamResolveRequestStream(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { + var args = callframe.arguments_old(2); + var this = args.ptr[args.len - 1].asPromisePtr(S3UploadStreamWrapper); + defer this.deref(); + if (this.sink.endPromise.hasValue()) { + this.sink.endPromise.resolve(globalThis, JSC.jsNumber(0)); + } + if (this.readable_stream_ref.get()) |stream| { + stream.done(globalThis); + } + this.readable_stream_ref.deinit(); + + return .undefined; + } + + pub fn onUploadStreamRejectRequestStream(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { + const args = callframe.arguments_old(2); + var this = args.ptr[args.len - 1].asPromisePtr(S3UploadStreamWrapper); + defer this.deref(); + const err = args.ptr[0]; + if (this.sink.endPromise.hasValue()) { + this.sink.endPromise.rejectOnNextTick(globalThis, err); + } + + if (this.readable_stream_ref.get()) |stream| { + stream.cancel(globalThis); + this.readable_stream_ref.deinit(); + } + if (this.sink.task) |task| { + if (task == .s3_upload) { + task.s3_upload.fail(.{ + .code = "UnknownError", + .message = "ReadableStream ended with an error", + }); + } + } + return .undefined; + } + pub const shim = JSC.Shimmer("Bun", "S3UploadStream", @This()); + + pub const Export = shim.exportFunctions(.{ + .onResolveRequestStream = onUploadStreamResolveRequestStream, + .onRejectRequestStream = onUploadStreamRejectRequestStream, + }); + comptime { + const jsonResolveRequestStream = JSC.toJSHostFunction(onUploadStreamResolveRequestStream); + @export(jsonResolveRequestStream, .{ .name = Export[0].symbol_name }); + const jsonRejectRequestStream = JSC.toJSHostFunction(onUploadStreamRejectRequestStream); + @export(jsonRejectRequestStream, .{ .name = Export[1].symbol_name }); + } + + /// consumes the readable stream and upload to s3 + pub fn s3UploadStream(this: *@This(), path: []const u8, readable_stream: JSC.WebCore.ReadableStream, globalThis: *JSC.JSGlobalObject, options: MultiPartUpload.MultiPartUploadOptions, content_type: ?[]const u8, proxy: ?[]const u8, callback: ?*const fn (S3UploadResult, *anyopaque) void, callback_context: *anyopaque) JSC.JSValue { + this.ref(); // ref the credentials + const proxy_url = (proxy orelse ""); + + const task = MultiPartUpload.new(.{ + .credentials = this, + .path = bun.default_allocator.dupe(u8, path) catch bun.outOfMemory(), + .proxy = if (proxy_url.len > 0) bun.default_allocator.dupe(u8, proxy_url) catch bun.outOfMemory() else "", + .content_type = if (content_type) |ct| bun.default_allocator.dupe(u8, ct) catch bun.outOfMemory() else null, + .callback = @ptrCast(&S3UploadStreamWrapper.resolve), + .callback_context = undefined, + .globalThis = globalThis, + .options = options, + .vm = JSC.VirtualMachine.get(), + }); + + task.poll_ref.ref(task.vm); + + task.ref(); // + 1 for the stream + + var response_stream = JSC.WebCore.FetchTaskletChunkedRequestSink.new(.{ + .task = .{ .s3_upload = task }, + .buffer = .{}, + .globalThis = globalThis, + .encoded = false, + .endPromise = JSC.JSPromise.Strong.init(globalThis), + }).toSink(); + const endPromise = response_stream.sink.endPromise.value(); + const ctx = S3UploadStreamWrapper.new(.{ + .readable_stream_ref = JSC.WebCore.ReadableStream.Strong.init(readable_stream, globalThis), + .sink = &response_stream.sink, + .callback = callback, + .callback_context = callback_context, + }); + task.callback_context = @ptrCast(ctx); + var signal = &response_stream.sink.signal; + + signal.* = JSC.WebCore.FetchTaskletChunkedRequestSink.JSSink.SinkSignal.init(.zero); + + // explicitly set it to a dead pointer + // we use this memory address to disable signals being sent + signal.clear(); + bun.assert(signal.isDead()); + + // We are already corked! + const assignment_result: JSC.JSValue = JSC.WebCore.FetchTaskletChunkedRequestSink.JSSink.assignToStream( + globalThis, + readable_stream.value, + response_stream, + @as(**anyopaque, @ptrCast(&signal.ptr)), + ); + + assignment_result.ensureStillAlive(); + + // assert that it was updated + bun.assert(!signal.isDead()); + + if (assignment_result.toError()) |err| { + readable_stream.cancel(globalThis); + if (response_stream.sink.endPromise.hasValue()) { + response_stream.sink.endPromise.rejectOnNextTick(globalThis, err); + } + task.fail(.{ + .code = "UnknownError", + .message = "ReadableStream ended with an error", + }); + return endPromise; + } + + if (!assignment_result.isEmptyOrUndefinedOrNull()) { + task.vm.drainMicrotasks(); + + assignment_result.ensureStillAlive(); + // it returns a Promise when it goes through ReadableStreamDefaultReader + if (assignment_result.asAnyPromise()) |promise| { + switch (promise.status(globalThis.vm())) { + .pending => { + ctx.ref(); + assignment_result.then( + globalThis, + task.callback_context, + onUploadStreamResolveRequestStream, + onUploadStreamRejectRequestStream, + ); + }, + .fulfilled => { + readable_stream.done(globalThis); + if (response_stream.sink.endPromise.hasValue()) { + response_stream.sink.endPromise.resolve(globalThis, JSC.jsNumber(0)); + } + }, + .rejected => { + readable_stream.cancel(globalThis); + if (response_stream.sink.endPromise.hasValue()) { + response_stream.sink.endPromise.rejectOnNextTick(globalThis, promise.result(globalThis.vm())); + } + task.fail(.{ + .code = "UnknownError", + .message = "ReadableStream ended with an error", + }); + }, + } + } else { + readable_stream.cancel(globalThis); + if (response_stream.sink.endPromise.hasValue()) { + response_stream.sink.endPromise.rejectOnNextTick(globalThis, assignment_result); + } + task.fail(.{ + .code = "UnknownError", + .message = "ReadableStream ended with an error", + }); + } + } + return endPromise; + } + /// returns a writable stream that writes to the s3 path + pub fn s3WritableStream(this: *@This(), path: []const u8, globalThis: *JSC.JSGlobalObject, options: MultiPartUpload.MultiPartUploadOptions, content_type: ?[]const u8, proxy: ?[]const u8) bun.JSError!JSC.JSValue { + const Wrapper = struct { + pub fn callback(result: S3UploadResult, sink: *JSC.WebCore.FetchTaskletChunkedRequestSink) void { + if (sink.endPromise.globalObject()) |globalObject| { + const event_loop = globalObject.bunVM().eventLoop(); + event_loop.enter(); + defer event_loop.exit(); + switch (result) { + .success => { + sink.endPromise.resolve(globalObject, JSC.jsNumber(0)); + }, + .failure => |err| { + if (!sink.done) { + sink.abort(); + return; + } + + sink.endPromise.rejectOnNextTick(globalObject, err.toJS(globalObject)); + }, + } + } + sink.finalize(); + } + }; + const proxy_url = (proxy orelse ""); + this.ref(); // ref the credentials + const task = MultiPartUpload.new(.{ + .credentials = this, + .path = bun.default_allocator.dupe(u8, path) catch bun.outOfMemory(), + .proxy = if (proxy_url.len > 0) bun.default_allocator.dupe(u8, proxy_url) catch bun.outOfMemory() else "", + .content_type = if (content_type) |ct| bun.default_allocator.dupe(u8, ct) catch bun.outOfMemory() else null, + + .callback = @ptrCast(&Wrapper.callback), + .callback_context = undefined, + .globalThis = globalThis, + .options = options, + .vm = JSC.VirtualMachine.get(), + }); + + task.poll_ref.ref(task.vm); + + task.ref(); // + 1 for the stream + var response_stream = JSC.WebCore.FetchTaskletChunkedRequestSink.new(.{ + .task = .{ .s3_upload = task }, + .buffer = .{}, + .globalThis = globalThis, + .encoded = false, + .endPromise = JSC.JSPromise.Strong.init(globalThis), + }).toSink(); + + task.callback_context = @ptrCast(response_stream); + var signal = &response_stream.sink.signal; + + signal.* = JSC.WebCore.FetchTaskletChunkedRequestSink.JSSink.SinkSignal.init(.zero); + + // explicitly set it to a dead pointer + // we use this memory address to disable signals being sent + signal.clear(); + bun.assert(signal.isDead()); + return response_stream.sink.toJS(globalThis); + } +}; + +pub const MultiPartUpload = struct { + pub const OneMiB: usize = 1048576; + pub const MAX_SINGLE_UPLOAD_SIZE_IN_MiB: usize = 5120; // we limit to 5 GiB + pub const MAX_SINGLE_UPLOAD_SIZE: usize = MAX_SINGLE_UPLOAD_SIZE_IN_MiB * OneMiB; // we limit to 5 GiB + pub const MIN_SINGLE_UPLOAD_SIZE_IN_MiB: usize = 5; + pub const DefaultPartSize = OneMiB * MIN_SINGLE_UPLOAD_SIZE_IN_MiB; + const MAX_QUEUE_SIZE = 64; // dont make sense more than this because we use fetch anything greater will be 64 + const AWS = AWSCredentials; + queue: std.ArrayListUnmanaged(UploadPart) = .{}, + available: bun.bit_set.IntegerBitSet(MAX_QUEUE_SIZE) = bun.bit_set.IntegerBitSet(MAX_QUEUE_SIZE).initFull(), + + currentPartNumber: u16 = 1, + ref_count: u16 = 1, + ended: bool = false, + + options: MultiPartUploadOptions = .{}, + credentials: *AWSCredentials, + poll_ref: bun.Async.KeepAlive = bun.Async.KeepAlive.init(), + vm: *JSC.VirtualMachine, + globalThis: *JSC.JSGlobalObject, + + buffered: std.ArrayListUnmanaged(u8) = .{}, + offset: usize = 0, + + path: []const u8, + proxy: []const u8, + content_type: ?[]const u8 = null, + upload_id: []const u8 = "", + uploadid_buffer: bun.MutableString = .{ .allocator = bun.default_allocator, .list = .{} }, + + multipart_etags: std.ArrayListUnmanaged(UploadPart.UploadPartResult) = .{}, + multipart_upload_list: bun.ByteList = .{}, + + state: enum { + not_started, + multipart_started, + multipart_completed, + singlefile_started, + finished, + } = .not_started, + + callback: *const fn (AWS.S3UploadResult, *anyopaque) void, + callback_context: *anyopaque, + + pub usingnamespace bun.NewRefCounted(@This(), @This().deinit); + + const log = bun.Output.scoped(.S3MultiPartUpload, true); + pub const MultiPartUploadOptions = struct { + /// more than 255 dont make sense http thread cannot handle more than that + queueSize: u8 = 5, + /// in s3 client sdk they set it in bytes but the min is still 5 MiB + /// var params = {Bucket: 'bucket', Key: 'key', Body: stream}; + /// var options = {partSize: 10 * 1024 * 1024, queueSize: 1}; + /// s3.upload(params, options, function(err, data) { + /// console.log(err, data); + /// }); + /// See. https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property + /// The value is in MiB min is 5 and max 5120 (but we limit to 4 GiB aka 4096) + partSize: u16 = 5, + /// default is 3 max 255 + retry: u8 = 3, + }; + + pub const UploadPart = struct { + data: []const u8, + state: enum { + pending, + started, + completed, + canceled, + }, + owns_data: bool, + partNumber: u16, // max is 10,000 + retry: u8, // auto retry, decrement until 0 and fail after this + index: u8, + ctx: *MultiPartUpload, + + pub const UploadPartResult = struct { + number: u16, + etag: []const u8, + }; + fn sortEtags(_: *MultiPartUpload, a: UploadPart.UploadPartResult, b: UploadPart.UploadPartResult) bool { + return a.number < b.number; + } + + pub fn onPartResponse(result: AWS.S3PartResult, this: *@This()) void { + if (this.state == .canceled) { + log("onPartResponse {} canceled", .{this.partNumber}); + if (this.owns_data) bun.default_allocator.free(this.data); + this.ctx.deref(); + return; + } + + this.state = .completed; + + switch (result) { + .failure => |err| { + if (this.retry > 0) { + log("onPartResponse {} retry", .{this.partNumber}); + this.retry -= 1; + // retry failed + this.perform(); + return; + } else { + log("onPartResponse {} failed", .{this.partNumber}); + if (this.owns_data) bun.default_allocator.free(this.data); + defer this.ctx.deref(); + return this.ctx.fail(err); + } + }, + .etag => |etag| { + log("onPartResponse {} success", .{this.partNumber}); + + if (this.owns_data) bun.default_allocator.free(this.data); + // we will need to order this + this.ctx.multipart_etags.append(bun.default_allocator, .{ + .number = this.partNumber, + .etag = bun.default_allocator.dupe(u8, etag) catch bun.outOfMemory(), + }) catch bun.outOfMemory(); + + defer this.ctx.deref(); + // mark as available + this.ctx.available.set(this.index); + // drain more + this.ctx.drainEnqueuedParts(); + }, + } + } + + fn perform(this: *@This()) void { + var params_buffer: [2048]u8 = undefined; + const search_params = std.fmt.bufPrint(¶ms_buffer, "?partNumber={}&uploadId={s}&x-id=UploadPart", .{ + this.partNumber, + this.ctx.upload_id, + }) catch unreachable; + this.ctx.credentials.executeSimpleS3Request(.{ + .path = this.ctx.path, + .method = .PUT, + .proxy_url = this.ctx.proxyUrl(), + .body = this.data, + .search_params = search_params, + }, .{ .part = @ptrCast(&onPartResponse) }, this); + } + pub fn start(this: *@This()) void { + if (this.state != .pending or this.ctx.state != .multipart_completed) return; + this.ctx.ref(); + this.state = .started; + this.perform(); + } + pub fn cancel(this: *@This()) void { + const state = this.state; + this.state = .canceled; + + switch (state) { + .pending => { + if (this.owns_data) bun.default_allocator.free(this.data); + }, + // if is not pending we will free later or is already freed + else => {}, + } + } + }; + + fn deinit(this: *@This()) void { + log("deinit", .{}); + if (this.queue.capacity > 0) + this.queue.deinit(bun.default_allocator); + this.poll_ref.unref(this.vm); + bun.default_allocator.free(this.path); + if (this.proxy.len > 0) { + bun.default_allocator.free(this.proxy); + } + if (this.content_type) |ct| { + if (ct.len > 0) { + bun.default_allocator.free(ct); + } + } + this.credentials.deref(); + this.uploadid_buffer.deinit(); + for (this.multipart_etags.items) |tag| { + bun.default_allocator.free(tag.etag); + } + if (this.multipart_etags.capacity > 0) + this.multipart_etags.deinit(bun.default_allocator); + if (this.multipart_upload_list.cap > 0) + this.multipart_upload_list.deinitWithAllocator(bun.default_allocator); + this.destroy(); + } + + pub fn singleSendUploadResponse(result: AWS.S3UploadResult, this: *@This()) void { + switch (result) { + .failure => |err| { + if (this.options.retry > 0) { + log("singleSendUploadResponse {} retry", .{this.options.retry}); + this.options.retry -= 1; + // retry failed + this.credentials.executeSimpleS3Request(.{ + .path = this.path, + .method = .PUT, + .proxy_url = this.proxyUrl(), + .body = this.buffered.items, + .content_type = this.content_type, + }, .{ .upload = @ptrCast(&singleSendUploadResponse) }, this); + + return; + } else { + log("singleSendUploadResponse failed", .{}); + return this.fail(err); + } + }, + .success => { + log("singleSendUploadResponse success", .{}); + this.done(); + }, + } + } + + fn getCreatePart(this: *@This(), chunk: []const u8, owns_data: bool) ?*UploadPart { + const index = this.available.findFirstSet() orelse { + // this means that the queue is full and we cannot flush it + return null; + }; + + if (index >= this.options.queueSize) { + // ops too much concurrency wait more + return null; + } + this.available.unset(index); + defer this.currentPartNumber += 1; + + if (this.queue.items.len <= index) { + this.queue.append(bun.default_allocator, .{ + .data = chunk, + .partNumber = this.currentPartNumber, + .owns_data = owns_data, + .ctx = this, + .index = @truncate(index), + .retry = this.options.retry, + .state = .pending, + }) catch bun.outOfMemory(); + return &this.queue.items[index]; + } + this.queue.items[index] = .{ + .data = chunk, + .partNumber = this.currentPartNumber, + .owns_data = owns_data, + .ctx = this, + .index = @truncate(index), + .retry = this.options.retry, + .state = .pending, + }; + return &this.queue.items[index]; + } + + fn drainEnqueuedParts(this: *@This()) void { + // check pending to start or transformed buffered ones into tasks + if (this.state == .multipart_completed) { + for (this.queue.items) |*part| { + if (part.state == .pending) { + // lets start the part request + part.start(); + } + } + } + const partSize = this.partSizeInBytes(); + if (this.ended or this.buffered.items.len >= partSize) { + this.processMultiPart(partSize); + } + + if (this.ended and this.available.mask == std.bit_set.IntegerBitSet(MAX_QUEUE_SIZE).initFull().mask) { + // we are done + this.done(); + } + } + pub fn fail(this: *@This(), _err: AWS.S3Error) void { + log("fail {s}:{s}", .{ _err.code, _err.message }); + for (this.queue.items) |*task| { + task.cancel(); + } + if (this.state != .finished) { + this.callback(.{ .failure = _err }, this.callback_context); + this.state = .finished; + if (this.state == .multipart_completed) { + // will deref after rollback + this.rollbackMultiPartRequest(); + } else { + this.deref(); + } + } + } + + fn done(this: *@This()) void { + if (this.state == .multipart_completed) { + this.state = .finished; + + std.sort.block(UploadPart.UploadPartResult, this.multipart_etags.items, this, UploadPart.sortEtags); + this.multipart_upload_list.append(bun.default_allocator, "") catch bun.outOfMemory(); + for (this.multipart_etags.items) |tag| { + this.multipart_upload_list.appendFmt(bun.default_allocator, "{}{s}", .{ tag.number, tag.etag }) catch bun.outOfMemory(); + + bun.default_allocator.free(tag.etag); + } + this.multipart_etags.deinit(bun.default_allocator); + this.multipart_etags = .{}; + this.multipart_upload_list.append(bun.default_allocator, "") catch bun.outOfMemory(); + // will deref and ends after commit + this.commitMultiPartRequest(); + } else { + this.callback(.{ .success = {} }, this.callback_context); + this.state = .finished; + this.deref(); + } + } + pub fn startMultiPartRequestResult(result: AWS.S3DownloadResult, this: *@This()) void { + switch (result) { + .failure => |err| { + log("startMultiPartRequestResult {s} failed {s}: {s}", .{ this.path, err.message, err.message }); + this.fail(err); + }, + .success => |response| { + const slice = response.body.list.items; + this.uploadid_buffer = result.success.body; + + if (strings.indexOf(slice, "")) |start| { + if (strings.indexOf(slice, "")) |end| { + this.upload_id = slice[start + 10 .. end]; + } + } + if (this.upload_id.len == 0) { + // Unknown type of response error from AWS + log("startMultiPartRequestResult {s} failed invalid id", .{this.path}); + this.fail(.{ + .code = "UnknownError", + .message = "Failed to initiate multipart upload", + }); + return; + } + log("startMultiPartRequestResult {s} success id: {s}", .{ this.path, this.upload_id }); + this.state = .multipart_completed; + this.drainEnqueuedParts(); + }, + // this is "unreachable" but we cover in case AWS returns 404 + .not_found => this.fail(.{ + .code = "UnknownError", + .message = "Failed to initiate multipart upload", + }), + } + } + + pub fn onCommitMultiPartRequest(result: AWS.S3CommitResult, this: *@This()) void { + log("onCommitMultiPartRequest {s}", .{this.upload_id}); + switch (result) { + .failure => |err| { + if (this.options.retry > 0) { + this.options.retry -= 1; + // retry commit + this.commitMultiPartRequest(); + return; + } + this.callback(.{ .failure = err }, this.callback_context); + this.deref(); + }, + .success => { + this.callback(.{ .success = {} }, this.callback_context); + this.state = .finished; + this.deref(); + }, + } + } + + pub fn onRollbackMultiPartRequest(result: AWS.S3UploadResult, this: *@This()) void { + log("onRollbackMultiPartRequest {s}", .{this.upload_id}); + switch (result) { + .failure => { + if (this.options.retry > 0) { + this.options.retry -= 1; + // retry rollback + this.rollbackMultiPartRequest(); + return; + } + this.deref(); + }, + .success => { + this.deref(); + }, + } + } + + fn commitMultiPartRequest(this: *@This()) void { + log("commitMultiPartRequest {s}", .{this.upload_id}); + var params_buffer: [2048]u8 = undefined; + const searchParams = std.fmt.bufPrint(¶ms_buffer, "?uploadId={s}", .{ + this.upload_id, + }) catch unreachable; + + this.credentials.executeSimpleS3Request(.{ + .path = this.path, + .method = .POST, + .proxy_url = this.proxyUrl(), + .body = this.multipart_upload_list.slice(), + .search_params = searchParams, + }, .{ .commit = @ptrCast(&onCommitMultiPartRequest) }, this); + } + fn rollbackMultiPartRequest(this: *@This()) void { + log("rollbackMultiPartRequest {s}", .{this.upload_id}); + var params_buffer: [2048]u8 = undefined; + const search_params = std.fmt.bufPrint(¶ms_buffer, "?uploadId={s}", .{ + this.upload_id, + }) catch unreachable; + + this.credentials.executeSimpleS3Request(.{ + .path = this.path, + .method = .DELETE, + .proxy_url = this.proxyUrl(), + .body = "", + .search_params = search_params, + }, .{ .upload = @ptrCast(&onRollbackMultiPartRequest) }, this); + } + fn enqueuePart(this: *@This(), chunk: []const u8, owns_data: bool) bool { + const part = this.getCreatePart(chunk, owns_data) orelse return false; + + if (this.state == .not_started) { + // will auto start later + this.state = .multipart_started; + this.credentials.executeSimpleS3Request(.{ + .path = this.path, + .method = .POST, + .proxy_url = this.proxyUrl(), + .body = "", + .search_params = "?uploads=", + .content_type = this.content_type, + }, .{ .download = @ptrCast(&startMultiPartRequestResult) }, this); + } else if (this.state == .multipart_completed) { + part.start(); + } + return true; + } + + fn processMultiPart(this: *@This(), part_size: usize) void { + // need to split in multiple parts because of the size + var buffer = this.buffered.items[this.offset..]; + var queue_full = false; + defer if (!this.ended and queue_full == false) { + this.buffered = .{}; + this.offset = 0; + }; + + while (buffer.len > 0) { + const len = @min(part_size, buffer.len); + const slice = buffer[0..len]; + buffer = buffer[len..]; + // its one big buffer lets free after we are done with everything, part dont own the data + if (this.enqueuePart(slice, this.ended)) { + this.offset += len; + } else { + queue_full = true; + break; + } + } + } + + pub fn proxyUrl(this: *@This()) ?[]const u8 { + return this.proxy; + } + fn processBuffered(this: *@This(), part_size: usize) void { + if (this.ended and this.buffered.items.len < this.partSizeInBytes() and this.state == .not_started) { + log("processBuffered {s} singlefile_started", .{this.path}); + this.state = .singlefile_started; + // we can do only 1 request + this.credentials.executeSimpleS3Request(.{ + .path = this.path, + .method = .PUT, + .proxy_url = this.proxyUrl(), + .body = this.buffered.items, + .content_type = this.content_type, + }, .{ .upload = @ptrCast(&singleSendUploadResponse) }, this); + } else { + // we need to split + this.processMultiPart(part_size); + } + } + + pub fn partSizeInBytes(this: *@This()) usize { + return this.options.partSize * OneMiB; + } + + pub fn sendRequestData(this: *@This(), chunk: []const u8, is_last: bool) void { + if (this.ended) return; + + if (is_last) { + this.ended = true; + if (chunk.len > 0) { + this.buffered.appendSlice(bun.default_allocator, chunk) catch bun.outOfMemory(); + } + this.processBuffered(this.partSizeInBytes()); + } else { + // still have more data and receive empty, nothing todo here + if (chunk.len == 0) return; + this.buffered.appendSlice(bun.default_allocator, chunk) catch bun.outOfMemory(); + const partSize = this.partSizeInBytes(); + if (this.buffered.items.len >= partSize) { + // send the part we have enough data + this.processBuffered(partSize); + return; + } + + // wait for more + } + } +}; diff --git a/src/url.zig b/src/url.zig index 5dafcac0c7..f96325ade9 100644 --- a/src/url.zig +++ b/src/url.zig @@ -93,6 +93,10 @@ pub const URL = struct { return strings.eqlComptime(this.protocol, "https"); } + pub inline fn isS3(this: *const URL) bool { + return strings.eqlComptime(this.protocol, "s3"); + } + pub inline fn isHTTP(this: *const URL) bool { return strings.eqlComptime(this.protocol, "http"); } @@ -105,6 +109,12 @@ pub const URL = struct { return "localhost"; } + pub fn s3Path(this: *const URL) string { + // we need to remove protocol if exists and ignore searchParams, should be host + pathname + const href = if (this.protocol.len > 0 and this.href.len > this.protocol.len + 2) this.href[this.protocol.len + 2 ..] else this.href; + return href[0 .. href.len - (this.search.len + this.hash.len)]; + } + pub fn displayHost(this: *const URL) bun.fmt.HostFormatter { return bun.fmt.HostFormatter{ .host = if (this.host.len > 0) this.host else this.displayHostname(), diff --git a/test/js/bun/s3/bun-write-leak-fixture.js b/test/js/bun/s3/bun-write-leak-fixture.js new file mode 100644 index 0000000000..0a7dabee81 --- /dev/null +++ b/test/js/bun/s3/bun-write-leak-fixture.js @@ -0,0 +1,31 @@ +// Avoid using String.prototype.repeat in this file because it's very slow in +// debug builds of JavaScriptCore +let MAX_ALLOWED_MEMORY_USAGE = 0; +let MAX_ALLOWED_MEMORY_USAGE_INCREMENT = 15; +const { randomUUID } = require("crypto"); + +const payload = new Buffer(1024 * 1024 * 1, "A".charCodeAt(0)).toString("utf-8"); +async function writeLargeFile() { + const dest = `s3://${randomUUID()}`; + await Bun.write(dest, payload); + await Bun.file(dest).unlink(); +} +async function run() { + { + // base line + await Promise.all(new Array(10).fill(writeLargeFile())); + await Bun.sleep(10); + Bun.gc(true); + } + MAX_ALLOWED_MEMORY_USAGE = ((process.memoryUsage.rss() / 1024 / 1024) | 0) + MAX_ALLOWED_MEMORY_USAGE_INCREMENT; + + { + await Promise.all(new Array(100).fill(writeLargeFile())); + Bun.gc(true); + } + const rss = (process.memoryUsage.rss() / 1024 / 1024) | 0; + if (rss > MAX_ALLOWED_MEMORY_USAGE) { + throw new Error("Memory usage is too high"); + } +} +await run(); diff --git a/test/js/bun/s3/s3-stream-leak-fixture.js b/test/js/bun/s3/s3-stream-leak-fixture.js new file mode 100644 index 0000000000..f2ad73edd7 --- /dev/null +++ b/test/js/bun/s3/s3-stream-leak-fixture.js @@ -0,0 +1,40 @@ +// Avoid using String.prototype.repeat in this file because it's very slow in +// debug builds of JavaScriptCore +let MAX_ALLOWED_MEMORY_USAGE = 0; +let MAX_ALLOWED_MEMORY_USAGE_INCREMENT = 15; +const { randomUUID } = require("crypto"); + +const s3Dest = randomUUID() + "-s3-stream-leak-fixture"; + +const s3file = Bun.s3(s3Dest); +async function readLargeFile() { + const stream = Bun.s3(s3Dest).stream(); + const reader = stream.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done) break; + } +} +async function run(inputType) { + await s3file.write(inputType); + Bun.gc(true); + + { + // base line + await Promise.all(new Array(10).fill(readLargeFile())); + await Bun.sleep(10); + Bun.gc(true); + } + MAX_ALLOWED_MEMORY_USAGE = ((process.memoryUsage.rss() / 1024 / 1024) | 0) + MAX_ALLOWED_MEMORY_USAGE_INCREMENT; + { + await Promise.all(new Array(100).fill(readLargeFile())); + Bun.gc(true); + } + const rss = (process.memoryUsage.rss() / 1024 / 1024) | 0; + if (rss > MAX_ALLOWED_MEMORY_USAGE) { + await s3file.unlink(); + throw new Error("Memory usage is too high"); + } +} +await run(new Buffer(1024 * 1024 * 1, "A".charCodeAt(0)).toString("utf-8")); +await s3file.unlink(); diff --git a/test/js/bun/s3/s3-text-leak-fixture.js b/test/js/bun/s3/s3-text-leak-fixture.js new file mode 100644 index 0000000000..e564a9edb5 --- /dev/null +++ b/test/js/bun/s3/s3-text-leak-fixture.js @@ -0,0 +1,35 @@ +// Avoid using String.prototype.repeat in this file because it's very slow in +// debug builds of JavaScriptCore +let MAX_ALLOWED_MEMORY_USAGE = 0; +let MAX_ALLOWED_MEMORY_USAGE_INCREMENT = 15; +const { randomUUID } = require("crypto"); + +const s3Dest = randomUUID() + "-s3-stream-leak-fixture"; + +const s3file = Bun.s3(s3Dest); +async function readLargeFile() { + await Bun.s3(s3Dest).text(); +} +async function run(inputType) { + await s3file.write(inputType); + Bun.gc(true); + + { + // base line + await Promise.all(new Array(10).fill(readLargeFile())); + await Bun.sleep(10); + Bun.gc(true); + } + MAX_ALLOWED_MEMORY_USAGE = ((process.memoryUsage.rss() / 1024 / 1024) | 0) + MAX_ALLOWED_MEMORY_USAGE_INCREMENT; + { + await Promise.all(new Array(100).fill(readLargeFile())); + Bun.gc(true); + } + const rss = (process.memoryUsage.rss() / 1024 / 1024) | 0; + if (rss > MAX_ALLOWED_MEMORY_USAGE) { + await s3file.unlink(); + throw new Error("Memory usage is too high"); + } +} +await run(new Buffer(1024 * 1024 * 1, "A".charCodeAt(0)).toString("utf-8")); +await s3file.unlink(); diff --git a/test/js/bun/s3/s3-write-leak-fixture.js b/test/js/bun/s3/s3-write-leak-fixture.js new file mode 100644 index 0000000000..019b8121a0 --- /dev/null +++ b/test/js/bun/s3/s3-write-leak-fixture.js @@ -0,0 +1,31 @@ +// Avoid using String.prototype.repeat in this file because it's very slow in +// debug builds of JavaScriptCore +let MAX_ALLOWED_MEMORY_USAGE = 0; +let MAX_ALLOWED_MEMORY_USAGE_INCREMENT = 15; +const dest = process.argv.at(-1); +const { randomUUID } = require("crypto"); +const payload = new Buffer(1024 * 1024 + 1, "A".charCodeAt(0)).toString("utf-8"); +async function writeLargeFile() { + const s3file = Bun.s3(randomUUID()); + await s3file.write(payload); + await s3file.unlink(); +} +async function run() { + { + // base line + await Promise.all(new Array(10).fill(writeLargeFile())); + await Bun.sleep(10); + Bun.gc(true); + } + MAX_ALLOWED_MEMORY_USAGE = ((process.memoryUsage.rss() / 1024 / 1024) | 0) + MAX_ALLOWED_MEMORY_USAGE_INCREMENT; + + { + await Promise.all(new Array(100).fill(writeLargeFile())); + Bun.gc(true); + } + const rss = (process.memoryUsage.rss() / 1024 / 1024) | 0; + if (rss > MAX_ALLOWED_MEMORY_USAGE) { + throw new Error("Memory usage is too high"); + } +} +await run(); diff --git a/test/js/bun/s3/s3-writer-leak-fixture.js b/test/js/bun/s3/s3-writer-leak-fixture.js new file mode 100644 index 0000000000..80a42b3795 --- /dev/null +++ b/test/js/bun/s3/s3-writer-leak-fixture.js @@ -0,0 +1,39 @@ +// Avoid using String.prototype.repeat in this file because it's very slow in +// debug builds of JavaScriptCore +let MAX_ALLOWED_MEMORY_USAGE = 0; +let MAX_ALLOWED_MEMORY_USAGE_INCREMENT = 15; +const dest = process.argv.at(-1); +const { randomUUID } = require("crypto"); +const payload = new Buffer(1024 * 256, "A".charCodeAt(0)).toString("utf-8"); +async function writeLargeFile() { + const s3file = Bun.s3(randomUUID()); + const writer = s3file.writer(); + writer.write(payload); + await Bun.sleep(10); + writer.write(payload); + await Bun.sleep(10); + writer.write(payload); + await Bun.sleep(10); + writer.write(payload); + await writer.end(); + await s3file.unlink(); +} +async function run() { + { + // base line + await Promise.all(new Array(10).fill(writeLargeFile())); + await Bun.sleep(10); + Bun.gc(true); + } + MAX_ALLOWED_MEMORY_USAGE = ((process.memoryUsage.rss() / 1024 / 1024) | 0) + MAX_ALLOWED_MEMORY_USAGE_INCREMENT; + + { + await Promise.all(new Array(100).fill(writeLargeFile())); + Bun.gc(true); + } + const rss = (process.memoryUsage.rss() / 1024 / 1024) | 0; + if (rss > MAX_ALLOWED_MEMORY_USAGE) { + throw new Error("Memory usage is too high"); + } +} +await run(); diff --git a/test/js/bun/s3/s3.leak.test.ts b/test/js/bun/s3/s3.leak.test.ts new file mode 100644 index 0000000000..9b25c622cb --- /dev/null +++ b/test/js/bun/s3/s3.leak.test.ts @@ -0,0 +1,172 @@ +import { describe, expect, it } from "bun:test"; +import { bunExe, bunEnv, getSecret, tempDirWithFiles } from "harness"; +import type { S3FileOptions } from "bun"; +import path from "path"; +const s3Options: S3FileOptions = { + accessKeyId: getSecret("S3_R2_ACCESS_KEY"), + secretAccessKey: getSecret("S3_R2_SECRET_KEY"), + endpoint: getSecret("S3_R2_ENDPOINT"), +}; + +const S3Bucket = getSecret("S3_R2_BUCKET"); + +describe.skipIf(!s3Options.accessKeyId)("s3", () => { + describe("leak tests", () => { + it( + "s3().stream() should not leak", + async () => { + const dir = tempDirWithFiles("s3-stream-leak-fixture", { + "s3-stream-leak-fixture.js": await Bun.file(path.join(import.meta.dir, "s3-stream-leak-fixture.js")).text(), + "out.bin": "here", + }); + + const dest = path.join(dir, "out.bin"); + + const { exitCode, stderr } = Bun.spawnSync( + [bunExe(), "--smol", path.join(dir, "s3-stream-leak-fixture.js"), dest], + { + env: { + ...bunEnv, + BUN_JSC_gcMaxHeapSize: "503316", + AWS_ACCESS_KEY_ID: s3Options.accessKeyId, + AWS_SECRET_ACCESS_KEY: s3Options.secretAccessKey, + AWS_ENDPOINT: s3Options.endpoint, + AWS_BUCKET: S3Bucket, + }, + stderr: "pipe", + stdout: "inherit", + stdin: "ignore", + }, + ); + expect(exitCode).toBe(0); + expect(stderr.toString()).toBe(""); + }, + 30 * 1000, + ); + it( + "s3().text() should not leak", + async () => { + const dir = tempDirWithFiles("s3-text-leak-fixture", { + "s3-text-leak-fixture.js": await Bun.file(path.join(import.meta.dir, "s3-text-leak-fixture.js")).text(), + "out.bin": "here", + }); + + const dest = path.join(dir, "out.bin"); + + const { exitCode, stderr } = Bun.spawnSync( + [bunExe(), "--smol", path.join(dir, "s3-text-leak-fixture.js"), dest], + { + env: { + ...bunEnv, + BUN_JSC_gcMaxHeapSize: "503316", + AWS_ACCESS_KEY_ID: s3Options.accessKeyId, + AWS_SECRET_ACCESS_KEY: s3Options.secretAccessKey, + AWS_ENDPOINT: s3Options.endpoint, + AWS_BUCKET: S3Bucket, + }, + stderr: "pipe", + stdout: "inherit", + stdin: "ignore", + }, + ); + expect(exitCode).toBe(0); + expect(stderr.toString()).toBe(""); + }, + 30 * 1000, + ); + it( + "s3().writer().write() should not leak", + async () => { + const dir = tempDirWithFiles("s3-writer-leak-fixture", { + "s3-writer-leak-fixture.js": await Bun.file(path.join(import.meta.dir, "s3-writer-leak-fixture.js")).text(), + "out.bin": "here", + }); + + const dest = path.join(dir, "out.bin"); + + const { exitCode, stderr } = Bun.spawnSync( + [bunExe(), "--smol", path.join(dir, "s3-writer-leak-fixture.js"), dest], + { + env: { + ...bunEnv, + BUN_JSC_gcMaxHeapSize: "503316", + AWS_ACCESS_KEY_ID: s3Options.accessKeyId, + AWS_SECRET_ACCESS_KEY: s3Options.secretAccessKey, + AWS_ENDPOINT: s3Options.endpoint, + AWS_BUCKET: S3Bucket, + }, + stderr: "pipe", + stdout: "inherit", + stdin: "ignore", + }, + ); + expect(exitCode).toBe(0); + expect(stderr.toString()).toBe(""); + }, + 30 * 1000, + ); + it( + "s3().write() should not leak", + async () => { + const dir = tempDirWithFiles("s3-write-leak-fixture", { + "s3-write-leak-fixture.js": await Bun.file(path.join(import.meta.dir, "s3-write-leak-fixture.js")).text(), + "out.bin": "here", + }); + + const dest = path.join(dir, "out.bin"); + + const { exitCode, stderr } = Bun.spawnSync( + [bunExe(), "--smol", path.join(dir, "s3-write-leak-fixture.js"), dest], + { + env: { + ...bunEnv, + BUN_JSC_gcMaxHeapSize: "503316", + AWS_ACCESS_KEY_ID: s3Options.accessKeyId, + AWS_SECRET_ACCESS_KEY: s3Options.secretAccessKey, + AWS_ENDPOINT: s3Options.endpoint, + AWS_BUCKET: S3Bucket, + }, + stderr: "pipe", + stdout: "inherit", + stdin: "ignore", + }, + ); + expect(exitCode).toBe(0); + expect(stderr.toString()).toBe(""); + }, + 30 * 1000, + ); + + it( + "Bun.write should not leak", + async () => { + const dir = tempDirWithFiles("bun-write-leak-fixture", { + "bun-write-leak-fixture.js": await Bun.file(path.join(import.meta.dir, "bun-write-leak-fixture.js")).text(), + "out.bin": "here", + }); + + const dest = path.join(dir, "out.bin"); + + const { exitCode, stderr } = Bun.spawnSync( + [bunExe(), "--smol", path.join(dir, "bun-write-leak-fixture.js"), dest], + { + env: { + ...bunEnv, + BUN_JSC_gcMaxHeapSize: "503316", + AWS_ACCESS_KEY_ID: s3Options.accessKeyId, + AWS_SECRET_ACCESS_KEY: s3Options.secretAccessKey, + AWS_ENDPOINT: s3Options.endpoint, + AWS_BUCKET: S3Bucket, + }, + stderr: "pipe", + stdout: "inherit", + stdin: "ignore", + }, + ); + expect(exitCode).toBe(0); + expect(stderr.toString()).toBe(""); + }, + 30 * 1000, + ); + }); +}); diff --git a/test/js/bun/s3/s3.test.ts b/test/js/bun/s3/s3.test.ts new file mode 100644 index 0000000000..7ac336fc6c --- /dev/null +++ b/test/js/bun/s3/s3.test.ts @@ -0,0 +1,617 @@ +import { describe, expect, it, beforeAll, afterAll } from "bun:test"; +import { bunExe, bunEnv, getSecret, tempDirWithFiles } from "harness"; +import { randomUUID } from "crypto"; +import { S3, s3, file } from "bun"; +import type { S3File, S3FileOptions } from "bun"; +import path from "path"; +const s3Options: S3FileOptions = { + accessKeyId: getSecret("S3_R2_ACCESS_KEY"), + secretAccessKey: getSecret("S3_R2_SECRET_KEY"), + endpoint: getSecret("S3_R2_ENDPOINT"), +}; + +const S3Bucket = getSecret("S3_R2_BUCKET"); + +function makePayLoadFrom(text: string, size: number): string { + while (Buffer.byteLength(text) < size) { + text += text; + } + return text.slice(0, size); +} + +// 10 MiB big enough to Multipart upload in more than one part +const bigPayload = makePayLoadFrom("Bun is the best runtime ever", 10 * 1024 * 1024); +const bigishPayload = makePayLoadFrom("Bun is the best runtime ever", 1 * 1024 * 1024); + +describe.skipIf(!s3Options.accessKeyId)("s3", () => { + for (let bucketInName of [true, false]) { + describe("fetch", () => { + describe(bucketInName ? "bucket in path" : "bucket in options", () => { + var tmp_filename: string; + const options = bucketInName ? s3Options : { ...s3Options, bucket: S3Bucket }; + beforeAll(async () => { + tmp_filename = bucketInName ? `s3://${S3Bucket}/${randomUUID()}` : `s3://${randomUUID()}`; + const result = await fetch(tmp_filename, { + method: "PUT", + body: "Hello Bun!", + s3: options, + }); + expect(result.status).toBe(200); + }); + + afterAll(async () => { + const result = await fetch(tmp_filename, { + method: "DELETE", + s3: options, + }); + expect(result.status).toBe(204); + }); + + it("should download file via fetch GET", async () => { + const result = await fetch(tmp_filename, { s3: options }); + expect(result.status).toBe(200); + expect(await result.text()).toBe("Hello Bun!"); + }); + + it("should download range", async () => { + const result = await fetch(tmp_filename, { + headers: { "range": "bytes=6-10" }, + s3: options, + }); + expect(result.status).toBe(206); + expect(await result.text()).toBe("Bun!"); + }); + + it("should check if a key exists or content-length", async () => { + const result = await fetch(tmp_filename, { + method: "HEAD", + s3: options, + }); + expect(result.status).toBe(200); // 404 if do not exists + expect(result.headers.get("content-length")).toBe("10"); // content-length + }); + + it("should check if a key does not exist", async () => { + const result = await fetch(tmp_filename + "-does-not-exist", { s3: options }); + expect(result.status).toBe(404); + }); + + it("should be able to set content-type", async () => { + { + const result = await fetch(tmp_filename, { + method: "PUT", + body: "Hello Bun!", + headers: { + "Content-Type": "application/json", + }, + s3: options, + }); + expect(result.status).toBe(200); + const response = await fetch(tmp_filename, { s3: options }); + expect(response.headers.get("content-type")).toStartWith("application/json"); + } + { + const result = await fetch(tmp_filename, { + method: "PUT", + body: "Hello Bun!", + headers: { + "Content-Type": "text/plain", + }, + s3: options, + }); + expect(result.status).toBe(200); + const response = await fetch(tmp_filename, { s3: options }); + expect(response.headers.get("content-type")).toStartWith("text/plain"); + } + }); + + it("should be able to upload large files", async () => { + // 10 MiB big enough to Multipart upload in more than one part + const buffer = Buffer.alloc(1 * 1024 * 1024, "a"); + { + await fetch(tmp_filename, { + method: "PUT", + body: async function* () { + for (let i = 0; i < 10; i++) { + await Bun.sleep(10); + yield buffer; + } + }, + s3: options, + }).then(res => res.text()); + + const result = await fetch(tmp_filename, { method: "HEAD", s3: options }); + expect(result.status).toBe(200); + expect(result.headers.get("content-length")).toBe((buffer.byteLength * 10).toString()); + } + }, 10_000); + }); + }); + + describe("Bun.S3", () => { + describe(bucketInName ? "bucket in path" : "bucket in options", () => { + const tmp_filename = bucketInName ? `${S3Bucket}/${randomUUID()}` : `${randomUUID()}`; + const options = bucketInName ? s3Options : { ...s3Options, bucket: S3Bucket }; + beforeAll(async () => { + const file = new S3(tmp_filename, options); + await file.write("Hello Bun!"); + }); + + afterAll(async () => { + const file = new S3(tmp_filename, options); + await file.unlink(); + }); + + it("should download file via Bun.s3().text()", async () => { + const file = new S3(tmp_filename, options); + const text = await file.text(); + expect(text).toBe("Hello Bun!"); + }); + + it("should download range", async () => { + const file = new S3(tmp_filename, options); + const text = await file.slice(6, 10).text(); + expect(text).toBe("Bun!"); + }); + + it("should check if a key exists or content-length", async () => { + const file = new S3(tmp_filename, options); + const exists = await file.exists(); + expect(exists).toBe(true); + const contentLength = await file.size; + expect(contentLength).toBe(10); + }); + + it("should check if a key does not exist", async () => { + const file = new S3(tmp_filename + "-does-not-exist", options); + const exists = await file.exists(); + expect(exists).toBe(false); + }); + + it("should be able to set content-type", async () => { + { + const s3file = new S3(tmp_filename, { ...options, type: "text/css" }); + await s3file.write("Hello Bun!"); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("text/css"); + } + { + const s3file = new S3(tmp_filename, options); + await s3file.write("Hello Bun!", { type: "text/plain" }); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("text/plain"); + } + + { + const s3file = new S3(tmp_filename, options); + const writer = s3file.writer({ type: "application/json" }); + writer.write("Hello Bun!"); + await writer.end(); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("application/json"); + } + + { + await S3.upload(tmp_filename, "Hello Bun!", { ...options, type: "application/xml" }); + const response = await fetch(s3(tmp_filename, options).presign()); + expect(response.headers.get("content-type")).toStartWith("application/xml"); + } + }); + + it("should be able to upload large files using S3.upload + readable Request", async () => { + { + await S3.upload( + tmp_filename, + new Request("https://example.com", { + method: "PUT", + body: async function* () { + for (let i = 0; i < 10; i++) { + if (i % 5 === 0) { + await Bun.sleep(10); + } + yield bigishPayload; + } + }, + }), + options, + ); + expect(await S3.size(tmp_filename, options)).toBe(Buffer.byteLength(bigishPayload) * 10); + } + }, 10_000); + + it("should be able to upload large files in one go using S3.upload", async () => { + { + await S3.upload(tmp_filename, bigPayload, options); + expect(await S3.size(tmp_filename, options)).toBe(Buffer.byteLength(bigPayload)); + expect(await new S3(tmp_filename, options).text()).toBe(bigPayload); + } + }, 10_000); + + it("should be able to upload large files in one go using S3File.write", async () => { + { + const s3File = new S3(tmp_filename, options); + await s3File.write(bigPayload); + expect(await s3File.size).toBe(Buffer.byteLength(bigPayload)); + expect(await s3File.text()).toBe(bigPayload); + } + }, 10_000); + }); + }); + + describe("Bun.file", () => { + describe(bucketInName ? "bucket in path" : "bucket in options", () => { + const tmp_filename = bucketInName ? `s3://${S3Bucket}/${randomUUID()}` : `s3://${randomUUID()}`; + const options = bucketInName ? s3Options : { ...s3Options, bucket: S3Bucket }; + beforeAll(async () => { + const s3file = file(tmp_filename, options); + await s3file.write("Hello Bun!"); + }); + + afterAll(async () => { + const s3file = file(tmp_filename, options); + await s3file.unlink(); + }); + + it("should download file via Bun.file().text()", async () => { + const s3file = file(tmp_filename, options); + const text = await s3file.text(); + expect(text).toBe("Hello Bun!"); + }); + + it("should download range", async () => { + const s3file = file(tmp_filename, options); + const text = await s3file.slice(6, 10).text(); + expect(text).toBe("Bun!"); + }); + + it("should check if a key exists or content-length", async () => { + const s3file = file(tmp_filename, options); + const exists = await s3file.exists(); + expect(exists).toBe(true); + const contentLength = await s3file.size; + expect(contentLength).toBe(10); + }); + + it("should check if a key does not exist", async () => { + const s3file = file(tmp_filename + "-does-not-exist", options); + const exists = await s3file.exists(); + expect(exists).toBe(false); + }); + + it("should be able to set content-type", async () => { + { + const s3file = file(tmp_filename, { ...options, type: "text/css" }); + await s3file.write("Hello Bun!"); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("text/css"); + } + { + const s3file = file(tmp_filename, options); + await s3file.write("Hello Bun!", { type: "text/plain" }); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("text/plain"); + } + + { + const s3file = file(tmp_filename, options); + const writer = s3file.writer({ type: "application/json" }); + writer.write("Hello Bun!"); + await writer.end(); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("application/json"); + } + }); + + it("should be able to upload large files in one go using Bun.write", async () => { + { + await Bun.write(file(tmp_filename, options), bigPayload); + expect(await S3.size(tmp_filename, options)).toBe(Buffer.byteLength(bigPayload)); + expect(await file(tmp_filename, options).text()).toEqual(bigPayload); + } + }, 15_000); + + it("should be able to upload large files in one go using S3File.write", async () => { + { + const s3File = file(tmp_filename, options); + await s3File.write(bigPayload); + expect(await s3File.size).toBe(Buffer.byteLength(bigPayload)); + expect(await s3File.text()).toBe(bigPayload); + } + }, 10_000); + }); + }); + + describe("Bun.s3", () => { + describe(bucketInName ? "bucket in path" : "bucket in options", () => { + const tmp_filename = bucketInName ? `${S3Bucket}/${randomUUID()}` : `${randomUUID()}`; + const options = bucketInName ? s3Options : { ...s3Options, bucket: S3Bucket }; + beforeAll(async () => { + const s3file = s3(tmp_filename, options); + await s3file.write("Hello Bun!"); + }); + + afterAll(async () => { + const s3file = s3(tmp_filename, options); + await s3file.unlink(); + }); + + it("should download file via Bun.s3().text()", async () => { + const s3file = s3(tmp_filename, options); + const text = await s3file.text(); + expect(text).toBe("Hello Bun!"); + }); + + it("should download range", async () => { + const s3file = s3(tmp_filename, options); + const text = await s3file.slice(6, 10).text(); + expect(text).toBe("Bun!"); + }); + + it("should check if a key exists or content-length", async () => { + const s3file = s3(tmp_filename, options); + const exists = await s3file.exists(); + expect(exists).toBe(true); + const contentLength = await s3file.size; + expect(contentLength).toBe(10); + }); + + it("should check if a key does not exist", async () => { + const s3file = s3(tmp_filename + "-does-not-exist", options); + const exists = await s3file.exists(); + expect(exists).toBe(false); + }); + + it("presign url", async () => { + const s3file = s3(tmp_filename, options); + const response = await fetch(s3file.presign()); + expect(response.status).toBe(200); + expect(await response.text()).toBe("Hello Bun!"); + }); + + it("should be able to set content-type", async () => { + { + const s3file = s3(tmp_filename, { ...options, type: "text/css" }); + await s3file.write("Hello Bun!"); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("text/css"); + } + { + const s3file = s3(tmp_filename, options); + await s3file.write("Hello Bun!", { type: "text/plain" }); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("text/plain"); + } + + { + const s3file = s3(tmp_filename, options); + const writer = s3file.writer({ type: "application/json" }); + writer.write("Hello Bun!"); + await writer.end(); + const response = await fetch(s3file.presign()); + expect(response.headers.get("content-type")).toStartWith("application/json"); + } + }); + + it("should be able to upload large files in one go using S3.upload", async () => { + { + await S3.upload(s3(tmp_filename, options), bigPayload); + expect(await S3.size(tmp_filename, options)).toBe(Buffer.byteLength(bigPayload)); + } + }, 10_000); + + it("should be able to upload large files in one go using Bun.write", async () => { + { + await Bun.write(s3(tmp_filename, options), bigPayload); + expect(await S3.size(tmp_filename, options)).toBe(Buffer.byteLength(bigPayload)); + expect(await s3(tmp_filename, options).text()).toBe(bigPayload); + } + }, 10_000); + + it("should be able to upload large files in one go using S3File.write", async () => { + { + const s3File = s3(tmp_filename, options); + await s3File.write(bigPayload); + expect(await s3File.size).toBe(Buffer.byteLength(bigPayload)); + expect(await s3File.text()).toBe(bigPayload); + } + }, 10_000); + + describe("readable stream", () => { + afterAll(async () => { + await Promise.all([ + s3(tmp_filename + "-readable-stream", options).unlink(), + s3(tmp_filename + "-readable-stream-big", options).unlink(), + ]); + }); + it("should work with small files", async () => { + const s3file = s3(tmp_filename + "-readable-stream", options); + await s3file.write("Hello Bun!"); + const stream = s3file.stream(); + const reader = stream.getReader(); + let bytes = 0; + let chunks: Array = []; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + bytes += value?.length ?? 0; + + if (value) chunks.push(value as Buffer); + } + expect(bytes).toBe(10); + expect(Buffer.concat(chunks)).toEqual(Buffer.from("Hello Bun!")); + }); + it("should work with large files ", async () => { + const s3file = s3(tmp_filename + "-readable-stream-big", options); + await s3file.write(bigishPayload); + const stream = s3file.stream(); + const reader = stream.getReader(); + let bytes = 0; + let chunks: Array = []; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + bytes += value?.length ?? 0; + if (value) chunks.push(value as Buffer); + } + expect(bytes).toBe(Buffer.byteLength(bigishPayload)); + expect(Buffer.concat(chunks).toString()).toBe(bigishPayload); + }, 30_000); + }); + }); + }); + } + + describe("credentials", () => { + it("should error with invalid access key id", async () => { + [s3, (...args) => new S3(...args), file].forEach(fn => { + const s3file = fn("s3://bucket/credentials-test", { + ...s3Options, + accessKeyId: "invalid", + }); + expect(s3file.write("Hello Bun!")).rejects.toThrow(); + }); + }); + it("should error with invalid secret key id", async () => { + [s3, (...args) => new S3(...args), file].forEach(fn => { + const s3file = fn("s3://bucket/credentials-test", { + ...s3Options, + secretAccessKey: "invalid", + }); + expect(s3file.write("Hello Bun!")).rejects.toThrow(); + }); + }); + + it("should error with invalid endpoint", async () => { + [s3, (...args) => new S3(...args), file].forEach(fn => { + const s3file = fn("s3://bucket/credentials-test", { + ...s3Options, + endpoint: "🙂.🥯", + }); + expect(s3file.write("Hello Bun!")).rejects.toThrow(); + }); + }); + + it("should error with invalid endpoint", async () => { + [s3, (...args) => new S3(...args), file].forEach(fn => { + const s3file = fn("s3://bucket/credentials-test", { + ...s3Options, + endpoint: "..asd.@%&&&%%", + }); + expect(s3file.write("Hello Bun!")).rejects.toThrow(); + }); + }); + + it("should error with invalid bucket", async () => { + [s3, (...args) => new S3(...args), file].forEach(fn => { + const s3file = fn("s3://credentials-test", { + ...s3Options, + bucket: "invalid", + }); + expect(s3file.write("Hello Bun!")).rejects.toThrow(); + }); + }); + }); + + describe("S3 static methods", () => { + describe("presign", () => { + it("should work", async () => { + const s3file = s3("s3://bucket/credentials-test", s3Options); + const url = s3file.presign(); + expect(url).toBeDefined(); + expect(url.includes("X-Amz-Expires=86400")).toBe(true); + expect(url.includes("X-Amz-Date")).toBe(true); + expect(url.includes("X-Amz-Signature")).toBe(true); + expect(url.includes("X-Amz-Credential")).toBe(true); + expect(url.includes("X-Amz-Algorithm")).toBe(true); + expect(url.includes("X-Amz-SignedHeaders")).toBe(true); + }); + it("should work with expires", async () => { + const s3file = s3("s3://bucket/credentials-test", s3Options); + const url = s3file.presign({ + expiresIn: 10, + }); + expect(url).toBeDefined(); + expect(url.includes("X-Amz-Expires=10")).toBe(true); + expect(url.includes("X-Amz-Date")).toBe(true); + expect(url.includes("X-Amz-Signature")).toBe(true); + expect(url.includes("X-Amz-Credential")).toBe(true); + expect(url.includes("X-Amz-Algorithm")).toBe(true); + expect(url.includes("X-Amz-SignedHeaders")).toBe(true); + }); + + it("S3.presign should work", async () => { + const url = S3.presign("s3://bucket/credentials-test", { + ...s3Options, + expiresIn: 10, + }); + expect(url).toBeDefined(); + expect(url.includes("X-Amz-Expires=10")).toBe(true); + expect(url.includes("X-Amz-Date")).toBe(true); + expect(url.includes("X-Amz-Signature")).toBe(true); + expect(url.includes("X-Amz-Credential")).toBe(true); + expect(url.includes("X-Amz-Algorithm")).toBe(true); + expect(url.includes("X-Amz-SignedHeaders")).toBe(true); + }); + + it("S3.presign endpoint should work", async () => { + const url = S3.presign("s3://bucket/credentials-test", { + ...s3Options, + expiresIn: 10, + endpoint: "https://s3.bun.sh", + }); + expect(url).toBeDefined(); + expect(url.includes("https://s3.bun.sh")).toBe(true); + expect(url.includes("X-Amz-Expires=10")).toBe(true); + expect(url.includes("X-Amz-Date")).toBe(true); + expect(url.includes("X-Amz-Signature")).toBe(true); + expect(url.includes("X-Amz-Credential")).toBe(true); + expect(url.includes("X-Amz-Algorithm")).toBe(true); + expect(url.includes("X-Amz-SignedHeaders")).toBe(true); + }); + + it("S3.presign endpoint should work", async () => { + const url = S3.presign("s3://folder/credentials-test", { + ...s3Options, + expiresIn: 10, + bucket: "my-bucket", + }); + expect(url).toBeDefined(); + expect(url.includes("my-bucket")).toBe(true); + expect(url.includes("X-Amz-Expires=10")).toBe(true); + expect(url.includes("X-Amz-Date")).toBe(true); + expect(url.includes("X-Amz-Signature")).toBe(true); + expect(url.includes("X-Amz-Credential")).toBe(true); + expect(url.includes("X-Amz-Algorithm")).toBe(true); + expect(url.includes("X-Amz-SignedHeaders")).toBe(true); + }); + }); + + it("exists, upload, size, unlink should work", async () => { + const filename = randomUUID(); + const fullPath = `s3://${S3Bucket}/${filename}`; + expect(await S3.exists(fullPath, s3Options)).toBe(false); + + await S3.upload(fullPath, "bun", s3Options); + expect(await S3.exists(fullPath, s3Options)).toBe(true); + expect(await S3.size(fullPath, s3Options)).toBe(3); + await S3.unlink(fullPath, s3Options); + expect(await S3.exists(fullPath, s3Options)).toBe(false); + }); + + it("should be able to upload a slice", async () => { + const filename = randomUUID(); + const fullPath = `s3://${S3Bucket}/${filename}`; + const s3file = s3(fullPath, s3Options); + await s3file.write("Hello Bun!"); + const slice = s3file.slice(6, 10); + expect(await slice.text()).toBe("Bun!"); + expect(await s3file.text()).toBe("Hello Bun!"); + + await S3.upload(fullPath, slice, s3Options); + const text = await s3file.text(); + expect(text).toBe("Bun!"); + await s3file.unlink(); + }); + }); +}); From 18ac7f9509b16c3b1f8e98cebd18a6474c97bed7 Mon Sep 17 00:00:00 2001 From: Devanand Sharma <59835311+Devanand-Sharma@users.noreply.github.com> Date: Sun, 29 Dec 2024 01:57:25 -0500 Subject: [PATCH 106/125] Add remove() and isRemoved in HTMLRewriterTypes.Doctype interface (#16031) --- packages/bun-types/html-rewriter.d.ts | 2 ++ src/bun.js/api/html_rewriter.classes.ts | 7 ++++++ src/bun.js/api/html_rewriter.zig | 20 ++++++++++++++++ src/deps/lol-html.zig | 10 ++++++++ .../js/web/html/html-rewriter-doctype.test.ts | 24 +++++++++++++++++++ 5 files changed, 63 insertions(+) create mode 100644 test/js/web/html/html-rewriter-doctype.test.ts diff --git a/packages/bun-types/html-rewriter.d.ts b/packages/bun-types/html-rewriter.d.ts index 44c9951e4d..4db17decb6 100644 --- a/packages/bun-types/html-rewriter.d.ts +++ b/packages/bun-types/html-rewriter.d.ts @@ -26,6 +26,8 @@ declare namespace HTMLRewriterTypes { readonly name: string | null; readonly publicId: string | null; readonly systemId: string | null; + readonly removed: boolean; + remove(): Doctype; } interface DocumentEnd { diff --git a/src/bun.js/api/html_rewriter.classes.ts b/src/bun.js/api/html_rewriter.classes.ts index a00c20b7e1..2e8808402b 100644 --- a/src/bun.js/api/html_rewriter.classes.ts +++ b/src/bun.js/api/html_rewriter.classes.ts @@ -81,6 +81,13 @@ export default [ getter: "publicId", cache: true, }, + remove: { + fn: "remove", + length: 0, + }, + removed: { + getter: "removed", + }, }, }), define({ diff --git a/src/bun.js/api/html_rewriter.zig b/src/bun.js/api/html_rewriter.zig index bab7ac3e5a..65ec201080 100644 --- a/src/bun.js/api/html_rewriter.zig +++ b/src/bun.js/api/html_rewriter.zig @@ -1157,6 +1157,26 @@ pub const DocType = struct { return JSValue.jsNull(); return ZigString.init(str).toJS(globalObject); } + + pub fn remove( + this: *DocType, + _: *JSGlobalObject, + callFrame: *JSC.CallFrame, + ) bun.JSError!JSValue { + if (this.doctype == null) + return JSValue.jsUndefined(); + this.doctype.?.remove(); + return callFrame.this(); + } + + pub fn removed( + this: *DocType, + _: *JSGlobalObject, + ) JSValue { + if (this.doctype == null) + return JSValue.jsUndefined(); + return JSValue.jsBoolean(this.doctype.?.isRemoved()); + } }; pub const DocEnd = struct { diff --git a/src/deps/lol-html.zig b/src/deps/lol-html.zig index bafd833c90..303588edc0 100644 --- a/src/deps/lol-html.zig +++ b/src/deps/lol-html.zig @@ -796,6 +796,8 @@ pub const DocType = opaque { extern fn lol_html_doctype_system_id_get(doctype: *const DocType) HTMLString; extern fn lol_html_doctype_user_data_set(doctype: *const DocType, user_data: ?*anyopaque) void; extern fn lol_html_doctype_user_data_get(doctype: *const DocType) ?*anyopaque; + extern fn lol_html_doctype_remove(doctype: *DocType) void; + extern fn lol_html_doctype_is_removed(doctype: *const DocType) bool; pub const Callback = *const fn (*DocType, ?*anyopaque) callconv(.C) Directive; @@ -811,6 +813,14 @@ pub const DocType = opaque { auto_disable(); return this.lol_html_doctype_system_id_get(); } + pub fn remove(this: *DocType) void { + auto_disable(); + return this.lol_html_doctype_remove(); + } + pub fn isRemoved(this: *const DocType) bool { + auto_disable(); + return this.lol_html_doctype_is_removed(); + } }; pub const Encoding = enum { diff --git a/test/js/web/html/html-rewriter-doctype.test.ts b/test/js/web/html/html-rewriter-doctype.test.ts new file mode 100644 index 0000000000..632a6fccb3 --- /dev/null +++ b/test/js/web/html/html-rewriter-doctype.test.ts @@ -0,0 +1,24 @@ +import { expect, test, describe } from "bun:test"; + +describe("HTMLRewriter DOCTYPE handler", () => { + test("remove and removed property work on DOCTYPE", () => { + const html = "Hello"; + let sawDoctype = false; + let wasRemoved = false; + + const rewriter = new HTMLRewriter().onDocument({ + doctype(doctype) { + sawDoctype = true; + doctype.remove(); + wasRemoved = doctype.removed; + }, + }); + + const result = rewriter.transform(html); + + expect(sawDoctype).toBe(true); + expect(wasRemoved).toBe(true); + expect(result).not.toContain(""); + }); +}); From f0073bfa8134801a0def6ba59e20f23d855505d1 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Mon, 30 Dec 2024 15:38:39 -0500 Subject: [PATCH 107/125] fix(install): free correct pointer in `bun patch --commit` (#16064) --- src/install/bun.lock.zig | 3 --- src/install/lockfile.zig | 32 ++++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/install/bun.lock.zig b/src/install/bun.lock.zig index fef28d2b91..6a212b46f4 100644 --- a/src/install/bun.lock.zig +++ b/src/install/bun.lock.zig @@ -1015,9 +1015,6 @@ pub fn parseIntoBinaryLockfile( log: *logger.Log, manager: ?*PackageManager, ) ParseError!void { - var temp_buf: std.ArrayListUnmanaged(u8) = .{}; - defer temp_buf.deinit(allocator); - lockfile.initEmpty(allocator); const lockfile_version_expr = root.get("lockfileVersion") orelse { diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 57c8ddd676..095c4c5e84 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -707,11 +707,19 @@ pub const Tree = struct { dependencies: Lockfile.DependencyIDList, }; + pub const CleanResult = struct { + trees: std.ArrayListUnmanaged(Tree), + dep_ids: std.ArrayListUnmanaged(DependencyID), + }; + /// Flatten the multi-dimensional ArrayList of package IDs into a single easily serializable array - pub fn clean(this: *@This()) OOM!DependencyIDList { + pub fn clean(this: *@This()) OOM!CleanResult { var total: u32 = 0; - const trees = this.list.items(.tree); - const dependencies = this.list.items(.dependencies); + + const list_ptr = this.list.bytes; + const slice = this.list.toOwnedSlice(); + var trees = slice.items(.tree); + const dependencies = slice.items(.dependencies); for (trees) |*tree| { total += tree.dependencies.len; @@ -733,7 +741,17 @@ pub const Tree = struct { this.queue.deinit(); this.sort_buf.deinit(this.allocator); - return dependency_ids; + // take over the `builder.list` pointer for only trees + if (@intFromPtr(trees.ptr) != @intFromPtr(list_ptr)) { + var new: [*]Tree = @ptrCast(list_ptr); + bun.copy(Tree, new[0..trees.len], trees); + trees = new[0..trees.len]; + } + + return .{ + .trees = std.ArrayListUnmanaged(Tree).fromOwnedSlice(trees), + .dep_ids = dependency_ids, + }; } }; } @@ -1458,6 +1476,7 @@ const Cloner = struct { } }; +/// Sets `buffers.trees` and `buffers.hoisted_dependencies` pub fn hoist( lockfile: *Lockfile, log: *logger.Log, @@ -1484,8 +1503,9 @@ pub fn hoist( try builder.list.items(.tree)[item.tree_id].processSubtree(item.dependency_id, method, &builder, if (method == .filter) manager.options.log_level else {}); } - lockfile.buffers.trees = std.ArrayListUnmanaged(Tree).fromOwnedSlice(builder.list.items(.tree)); - lockfile.buffers.hoisted_dependencies = try builder.clean(); + const cleaned = try builder.clean(); + lockfile.buffers.trees = cleaned.trees; + lockfile.buffers.hoisted_dependencies = cleaned.dep_ids; } const PendingResolution = struct { From 76bfceae81afd87f70163c04daada1849d0b123c Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 30 Dec 2024 13:25:01 -0800 Subject: [PATCH 108/125] Support jsonb, `idle_timeout`, `connection_timeout`, `max_lifetime` timeouts in bun:sql. Add `onopen` and `onclose` callbacks. Fix missing `"code"` property appearing in errors. Add error codes for postgres. (#16045) --- src/bun.js/api/Timer.zig | 11 + src/bun.js/api/postgres.classes.ts | 26 +- src/bun.js/bindings/ErrorCode.cpp | 3 + src/bun.js/bindings/ErrorCode.ts | 32 +- src/bun.js/bindings/JSPropertyIterator.cpp | 30 + src/bun.js/bindings/JSPropertyIterator.zig | 26 +- src/bun.js/bindings/bindings.zig | 4 +- src/bun.js/javascript.zig | 3 +- src/js/bun/sql.ts | 171 ++++- src/sql/postgres.zig | 689 +++++++++++++++------ src/sql/postgres/postgres_protocol.zig | 295 ++++++--- src/sql/postgres/postgres_types.zig | 34 +- src/string.zig | 6 + src/string_builder.zig | 6 + test/js/sql/sql.test.ts | 163 ++++- 15 files changed, 1152 insertions(+), 347 deletions(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 6f9dcb62e3..ab532acabb 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -731,6 +731,8 @@ pub const EventLoopTimer = struct { StatWatcherScheduler, UpgradedDuplex, WindowsNamedPipe, + PostgresSQLConnectionTimeout, + PostgresSQLConnectionMaxLifetime, pub fn Type(comptime T: Tag) type { return switch (T) { @@ -740,6 +742,8 @@ pub const EventLoopTimer = struct { .StatWatcherScheduler => StatWatcherScheduler, .UpgradedDuplex => uws.UpgradedDuplex, .WindowsNamedPipe => uws.WindowsNamedPipe, + .PostgresSQLConnectionTimeout => JSC.Postgres.PostgresSQLConnection, + .PostgresSQLConnectionMaxLifetime => JSC.Postgres.PostgresSQLConnection, }; } } else enum { @@ -748,6 +752,8 @@ pub const EventLoopTimer = struct { TestRunner, StatWatcherScheduler, UpgradedDuplex, + PostgresSQLConnectionTimeout, + PostgresSQLConnectionMaxLifetime, pub fn Type(comptime T: Tag) type { return switch (T) { @@ -756,6 +762,8 @@ pub const EventLoopTimer = struct { .TestRunner => JSC.Jest.TestRunner, .StatWatcherScheduler => StatWatcherScheduler, .UpgradedDuplex => uws.UpgradedDuplex, + .PostgresSQLConnectionTimeout => JSC.Postgres.PostgresSQLConnection, + .PostgresSQLConnectionMaxLifetime => JSC.Postgres.PostgresSQLConnection, }; } }; @@ -808,11 +816,14 @@ pub const EventLoopTimer = struct { pub fn fire(this: *EventLoopTimer, now: *const timespec, vm: *VirtualMachine) Arm { switch (this.tag) { + .PostgresSQLConnectionTimeout => return @as(*JSC.Postgres.PostgresSQLConnection, @alignCast(@fieldParentPtr("timer", this))).onConnectionTimeout(), + .PostgresSQLConnectionMaxLifetime => return @as(*JSC.Postgres.PostgresSQLConnection, @alignCast(@fieldParentPtr("max_lifetime_timer", this))).onMaxLifetimeTimeout(), inline else => |t| { var container: *t.Type() = @alignCast(@fieldParentPtr("event_loop_timer", this)); if (comptime t.Type() == TimerObject) { return container.fire(now, vm); } + if (comptime t.Type() == StatWatcherScheduler) { return container.timerCallback(); } diff --git a/src/bun.js/api/postgres.classes.ts b/src/bun.js/api/postgres.classes.ts index 04097296fc..40664ecb2b 100644 --- a/src/bun.js/api/postgres.classes.ts +++ b/src/bun.js/api/postgres.classes.ts @@ -5,8 +5,8 @@ export default [ name: "PostgresSQLConnection", construct: true, finalize: true, - hasPendingActivity: true, configurable: false, + hasPendingActivity: true, klass: { // escapeString: { // fn: "escapeString", @@ -20,9 +20,6 @@ export default [ close: { fn: "doClose", }, - flush: { - fn: "doFlush", - }, connected: { getter: "getConnected", }, @@ -32,17 +29,30 @@ export default [ unref: { fn: "doUnref", }, - query: { - fn: "createQuery", + + queries: { + getter: "getQueries", + this: true, + }, + onconnect: { + getter: "getOnConnect", + setter: "setOnConnect", + this: true, + }, + onclose: { + getter: "getOnClose", + setter: "setOnClose", + this: true, }, }, + values: ["onconnect", "onclose", "queries"], }), define({ name: "PostgresSQLQuery", construct: true, finalize: true, configurable: false, - hasPendingActivity: true, + JSType: "0b11101110", klass: {}, proto: { @@ -59,7 +69,7 @@ export default [ length: 0, }, }, - values: ["pendingValue", "columns", "binding"], + values: ["pendingValue", "target", "columns", "binding"], estimatedSize: true, }), ]; diff --git a/src/bun.js/bindings/ErrorCode.cpp b/src/bun.js/bindings/ErrorCode.cpp index 1fc96a4da2..8a7d9c2e97 100644 --- a/src/bun.js/bindings/ErrorCode.cpp +++ b/src/bun.js/bindings/ErrorCode.cpp @@ -50,6 +50,9 @@ static JSC::JSObject* createErrorPrototype(JSC::VM& vm, JSC::JSGlobalObject* glo case JSC::ErrorType::URIError: prototype = JSC::constructEmptyObject(globalObject, globalObject->m_URIErrorStructure.prototype(globalObject)); break; + case JSC::ErrorType::SyntaxError: + prototype = JSC::constructEmptyObject(globalObject, globalObject->m_syntaxErrorStructure.prototype(globalObject)); + break; default: { RELEASE_ASSERT_NOT_REACHED_WITH_MESSAGE("TODO: Add support for more error types"); break; diff --git a/src/bun.js/bindings/ErrorCode.ts b/src/bun.js/bindings/ErrorCode.ts index bb72e160d2..14e93b2c85 100644 --- a/src/bun.js/bindings/ErrorCode.ts +++ b/src/bun.js/bindings/ErrorCode.ts @@ -98,7 +98,37 @@ export default [ ["ERR_ASYNC_CALLBACK", TypeError], // Postgres - ["ERR_POSTGRES_ERROR_RESPONSE", Error, "PostgresError"], + ["ERR_POSTGRES_AUTHENTICATION_FAILED_PBKDF2", Error, "PostgresError"], + ["ERR_POSTGRES_SERVER_ERROR", Error, "PostgresError"], + ["ERR_POSTGRES_SYNTAX_ERROR", SyntaxError, "PostgresError"], + ["ERR_POSTGRES_CONNECTION_CLOSED", Error, "PostgresError"], + ["ERR_POSTGRES_EXPECTED_REQUEST", Error, "PostgresError"], + ["ERR_POSTGRES_EXPECTED_STATEMENT", Error, "PostgresError"], + ["ERR_POSTGRES_INVALID_BACKEND_KEY_DATA", TypeError, "PostgresError"], + ["ERR_POSTGRES_INVALID_BINARY_DATA", TypeError, "PostgresError"], + ["ERR_POSTGRES_INVALID_BYTE_SEQUENCE_FOR_ENCODING", TypeError, "PostgresError"], + ["ERR_POSTGRES_INVALID_BYTE_SEQUENCE", TypeError, "PostgresError"], + ["ERR_POSTGRES_INVALID_CHARACTER", TypeError, "PostgresError"], + ["ERR_POSTGRES_INVALID_MESSAGE_LENGTH", Error, "PostgresError"], + ["ERR_POSTGRES_INVALID_MESSAGE", Error, "PostgresError"], + ["ERR_POSTGRES_INVALID_QUERY_BINDING", Error, "PostgresError"], + ["ERR_POSTGRES_INVALID_SERVER_KEY", Error, "PostgresError"], + ["ERR_POSTGRES_INVALID_SERVER_SIGNATURE", Error, "PostgresError"], + ["ERR_POSTGRES_MULTIDIMENSIONAL_ARRAY_NOT_SUPPORTED_YET", Error, "PostgresError"], + ["ERR_POSTGRES_NULLS_IN_ARRAY_NOT_SUPPORTED_YET", Error, "PostgresError"], + ["ERR_POSTGRES_OVERFLOW", TypeError, "PostgresError"], + ["ERR_POSTGRES_SASL_SIGNATURE_INVALID_BASE64", Error, "PostgresError"], + ["ERR_POSTGRES_SASL_SIGNATURE_MISMATCH", Error, "PostgresError"], + ["ERR_POSTGRES_TLS_NOT_AVAILABLE", Error, "PostgresError"], + ["ERR_POSTGRES_TLS_UPGRADE_FAILED", Error, "PostgresError"], + ["ERR_POSTGRES_UNEXPECTED_MESSAGE", Error, "PostgresError"], + ["ERR_POSTGRES_UNKNOWN_AUTHENTICATION_METHOD", Error, "PostgresError"], + ["ERR_POSTGRES_UNSUPPORTED_AUTHENTICATION_METHOD", Error, "PostgresError"], + ["ERR_POSTGRES_UNSUPPORTED_BYTEA_FORMAT", TypeError, "PostgresError"], + ["ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE", TypeError, "PostgresError"], + ["ERR_POSTGRES_IDLE_TIMEOUT", Error, "PostgresError"], + ["ERR_POSTGRES_CONNECTION_TIMEOUT", Error, "PostgresError"], + ["ERR_POSTGRES_LIFETIME_TIMEOUT", Error, "PostgresError"], // AWS ["ERR_AWS_MISSING_CREDENTIALS", Error], diff --git a/src/bun.js/bindings/JSPropertyIterator.cpp b/src/bun.js/bindings/JSPropertyIterator.cpp index 8d4657f469..89e64a8ac8 100644 --- a/src/bun.js/bindings/JSPropertyIterator.cpp +++ b/src/bun.js/bindings/JSPropertyIterator.cpp @@ -90,6 +90,36 @@ extern "C" JSPropertyIterator* Bun__JSPropertyIterator__create(JSC::JSGlobalObje return JSPropertyIterator::create(vm, array.releaseData()); } +// The only non-own property that we sometimes want to get is the code property. +extern "C" EncodedJSValue Bun__JSPropertyIterator__getCodeProperty(JSPropertyIterator* iter, JSC::JSGlobalObject* globalObject, JSC::JSObject* object) +{ + if (UNLIKELY(!iter)) { + return {}; + } + + auto& vm = iter->vm; + auto scope = DECLARE_THROW_SCOPE(vm); + RETURN_IF_EXCEPTION(scope, {}); + if (UNLIKELY(object->type() == JSC::ProxyObjectType)) { + return {}; + } + + auto& builtinNames = WebCore::builtinNames(vm); + + PropertySlot slot(object, PropertySlot::InternalMethodType::VMInquiry, vm.ptr()); + if (!object->getNonIndexPropertySlot(globalObject, builtinNames.codePublicName(), slot)) { + return {}; + } + + if (slot.isAccessor() || slot.isCustom()) { + return {}; + } + + RETURN_IF_EXCEPTION(scope, {}); + + return JSValue::encode(slot.getPureResult()); +} + extern "C" size_t Bun__JSPropertyIterator__getLongestPropertyName(JSPropertyIterator* iter, JSC::JSGlobalObject* globalObject, JSC::JSObject* object) { size_t longest = 0; diff --git a/src/bun.js/bindings/JSPropertyIterator.zig b/src/bun.js/bindings/JSPropertyIterator.zig index ff4a4e77f6..bd55ea078c 100644 --- a/src/bun.js/bindings/JSPropertyIterator.zig +++ b/src/bun.js/bindings/JSPropertyIterator.zig @@ -8,7 +8,7 @@ extern "C" fn Bun__JSPropertyIterator__getNameAndValueNonObservable(iter: ?*anyo extern "C" fn Bun__JSPropertyIterator__getName(iter: ?*anyopaque, propertyName: *bun.String, i: usize) void; extern "C" fn Bun__JSPropertyIterator__deinit(iter: ?*anyopaque) void; extern "C" fn Bun__JSPropertyIterator__getLongestPropertyName(iter: ?*anyopaque, globalObject: *JSC.JSGlobalObject, object: *anyopaque) usize; - +extern "C" fn Bun__JSPropertyIterator__getCodeProperty(iter: ?*anyopaque, globalObject: *JSC.JSGlobalObject, object: *anyopaque) JSC.JSValue; pub const JSPropertyIteratorOptions = struct { skip_empty_name: bool, include_value: bool, @@ -27,6 +27,7 @@ pub fn JSPropertyIterator(comptime options: JSPropertyIteratorOptions) type { globalObject: *JSC.JSGlobalObject, object: *JSC.JSCell = undefined, value: JSC.JSValue = .zero, + tried_code_property: bool = false, pub fn getLongestPropertyName(this: *@This()) usize { if (this.impl == null) return 0; @@ -53,6 +54,7 @@ pub fn JSPropertyIterator(comptime options: JSPropertyIteratorOptions) type { pub fn reset(this: *@This()) void { this.iter_i = 0; this.i = 0; + this.tried_code_property = false; } /// The bun.String returned has not incremented it's reference count. @@ -90,5 +92,27 @@ pub fn JSPropertyIterator(comptime options: JSPropertyIteratorOptions) type { return name; } + + /// "code" is not always an own property, and we want to get it without risking exceptions. + pub fn getCodeProperty(this: *@This()) ?bun.String { + if (comptime !options.include_value) { + @compileError("TODO"); + } + + if (this.tried_code_property) { + return null; + } + + this.tried_code_property = true; + + const current = Bun__JSPropertyIterator__getCodeProperty(this.impl, this.globalObject, this.object); + if (current == .zero) { + return null; + } + current.ensureStillAlive(); + this.value = current; + + return bun.String.static("code"); + } }; } diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index b143919289..9786b87e46 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -6739,10 +6739,10 @@ pub const CallFrame = opaque { /// arguments(n).mut() -> `var args = argumentsAsArray(n); &args` pub fn arguments_old(self: *const CallFrame, comptime max: usize) Arguments(max) { const slice = self.arguments(); - comptime bun.assert(max <= 10); + comptime bun.assert(max <= 13); return switch (@as(u4, @min(slice.len, max))) { 0 => .{ .ptr = undefined, .len = 0 }, - inline 1...10 => |count| Arguments(max).init(comptime @min(count, max), slice.ptr), + inline 1...13 => |count| Arguments(max).init(comptime @min(count, max), slice.ptr), else => unreachable, }; } diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 6c5274dd0a..3444695992 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -3956,7 +3956,7 @@ pub const VirtualMachine = struct { defer iterator.deinit(); const longest_name = @min(iterator.getLongestPropertyName(), 10); var is_first_property = true; - while (iterator.next()) |field| { + while (iterator.next() orelse iterator.getCodeProperty()) |field| { const value = iterator.value; if (field.eqlComptime("message") or field.eqlComptime("name") or field.eqlComptime("stack")) { continue; @@ -3966,6 +3966,7 @@ pub const VirtualMachine = struct { if (field.eqlComptime("code")) { if (value.isString()) { const str = value.toBunString(this.global); + defer str.deref(); if (!str.isEmpty()) { if (str.eql(name)) { continue; diff --git a/src/js/bun/sql.ts b/src/js/bun/sql.ts index f4f29f431f..8ce069cb72 100644 --- a/src/js/bun/sql.ts +++ b/src/js/bun/sql.ts @@ -75,6 +75,15 @@ class Query extends PublicPromise { [_handler]; [_queryStatus] = 0; + [Symbol.for("nodejs.util.inspect.custom")]() { + const status = this[_queryStatus]; + const active = (status & QueryStatus.active) != 0; + const cancelled = (status & QueryStatus.cancelled) != 0; + const executed = (status & QueryStatus.executed) != 0; + const error = (status & QueryStatus.error) != 0; + return `PostgresQuery { ${active ? "active" : ""} ${cancelled ? "cancelled" : ""} ${executed ? "executed" : ""} ${error ? "error" : ""} }`; + } + constructor(handle, handler) { var resolve_, reject_; super((resolve, reject) => { @@ -182,7 +191,7 @@ class Query extends PublicPromise { Object.defineProperty(Query, Symbol.species, { value: PublicPromise }); Object.defineProperty(Query, Symbol.toStringTag, { value: "Query" }); init( - function (query, result, commandTag, count) { + function onResolvePostgresQuery(query, result, commandTag, count, queries) { $assert(result instanceof SQLResultArray, "Invalid result array"); if (typeof commandTag === "string") { if (commandTag.length > 0) { @@ -194,18 +203,48 @@ init( result.count = count || 0; + if (queries) { + const queriesIndex = queries.indexOf(query); + if (queriesIndex !== -1) { + queries.splice(queriesIndex, 1); + } + } + try { query.resolve(result); } catch (e) {} }, - function (query, reject) { + function onRejectPostgresQuery(query, reject, queries) { + if (queries) { + const queriesIndex = queries.indexOf(query); + if (queriesIndex !== -1) { + queries.splice(queriesIndex, 1); + } + } + try { query.reject(reject); } catch (e) {} }, ); -function createConnection({ hostname, port, username, password, tls, query, database, sslMode }, onConnected, onClose) { +function createConnection( + { + hostname, + port, + username, + password, + tls, + query, + database, + sslMode, + idleTimeout = 0, + connectionTimeout = 30 * 1000, + maxLifetime = 0, + }, + onConnected, + onClose, +) { return _createConnection( hostname, Number(port), @@ -221,6 +260,9 @@ function createConnection({ hostname, port, username, password, tls, query, data query || "", onConnected, onClose, + idleTimeout, + connectionTimeout, + maxLifetime, ); } @@ -312,7 +354,20 @@ class SQLArrayParameter { } function loadOptions(o) { - var hostname, port, username, password, database, tls, url, query, adapter; + var hostname, + port, + username, + password, + database, + tls, + url, + query, + adapter, + idleTimeout, + connectionTimeout, + maxLifetime, + onconnect, + onclose; const env = Bun.env; var sslMode: SSLMode = SSLMode.disable; @@ -375,6 +430,48 @@ function loadOptions(o) { tls ||= o.tls || o.ssl; adapter ||= o.adapter || "postgres"; + idleTimeout ??= o.idleTimeout; + idleTimeout ??= o.idle_timeout; + connectionTimeout ??= o.connectionTimeout; + connectionTimeout ??= o.connection_timeout; + maxLifetime ??= o.maxLifetime; + maxLifetime ??= o.max_lifetime; + + onconnect ??= o.onconnect; + onclose ??= o.onclose; + if (onconnect !== undefined) { + if (!$isCallable(onconnect)) { + throw $ERR_INVALID_ARG_TYPE("onconnect", "function", onconnect); + } + } + + if (onclose !== undefined) { + if (!$isCallable(onclose)) { + throw $ERR_INVALID_ARG_TYPE("onclose", "function", onclose); + } + } + + if (idleTimeout != null) { + idleTimeout = Number(idleTimeout); + if (idleTimeout > 2 ** 31 || idleTimeout < 0 || idleTimeout !== idleTimeout) { + throw $ERR_INVALID_ARG_VALUE("idle_timeout must be a non-negative integer less than 2^31"); + } + } + + if (connectionTimeout != null) { + connectionTimeout = Number(connectionTimeout); + if (connectionTimeout > 2 ** 31 || connectionTimeout < 0 || connectionTimeout !== connectionTimeout) { + throw $ERR_INVALID_ARG_VALUE("connection_timeout must be a non-negative integer less than 2^31"); + } + } + + if (maxLifetime != null) { + maxLifetime = Number(maxLifetime); + if (maxLifetime > 2 ** 31 || maxLifetime < 0 || maxLifetime !== maxLifetime) { + throw $ERR_INVALID_ARG_VALUE("max_lifetime must be a non-negative integer less than 2^31"); + } + } + if (sslMode !== SSLMode.disable && !tls?.serverName) { if (hostname) { tls = { @@ -398,7 +495,23 @@ function loadOptions(o) { throw new Error(`Unsupported adapter: ${adapter}. Only \"postgres\" is supported for now`); } - return { hostname, port, username, password, database, tls, query, sslMode }; + const ret: any = { hostname, port, username, password, database, tls, query, sslMode }; + if (idleTimeout != null) { + ret.idleTimeout = idleTimeout; + } + if (connectionTimeout != null) { + ret.connectionTimeout = connectionTimeout; + } + if (maxLifetime != null) { + ret.maxLifetime = maxLifetime; + } + if (onconnect !== undefined) { + ret.onconnect = onconnect; + } + if (onclose !== undefined) { + ret.onclose = onclose; + } + return ret; } function SQL(o) { @@ -407,6 +520,7 @@ function SQL(o) { connecting = false, closed = false, onConnect: any[] = [], + storedErrorForClosedConnection, connectionInfo = loadOptions(o); function connectedHandler(query, handle, err) { @@ -415,7 +529,7 @@ function SQL(o) { } if (!connected) { - return query.reject(new Error("Not connected")); + return query.reject(storedErrorForClosedConnection || new Error("Not connected")); } if (query.cancelled) { @@ -423,6 +537,10 @@ function SQL(o) { } handle.run(connection, query); + + // if the above throws, we don't want it to be in the array. + // This array exists mostly to keep the in-flight queries alive. + connection.queries.push(query); } function pendingConnectionHandler(query, handle) { @@ -434,7 +552,7 @@ function SQL(o) { } function closedConnectionHandler(query, handle) { - query.reject(new Error("Connection closed")); + query.reject(storedErrorForClosedConnection || new Error("Connection closed")); } function onConnected(err, result) { @@ -443,11 +561,31 @@ function SQL(o) { handler(err); } onConnect = []; + + if (connected && connectionInfo?.onconnect) { + connectionInfo.onconnect(err); + } } - function onClose(err) { + function onClose(err, queries) { closed = true; + storedErrorForClosedConnection = err; + if (sql === lazyDefaultSQL) { + resetDefaultSQL(initialDefaultSQL); + } + onConnected(err, undefined); + if (queries) { + const queriesCopy = queries.slice(); + queries.length = 0; + for (const handler of queriesCopy) { + handler.reject(err); + } + } + + if (connectionInfo?.onclose) { + connectionInfo.onclose(err); + } } function doCreateQuery(strings, values) { @@ -568,18 +706,23 @@ function SQL(o) { } var lazyDefaultSQL; -var defaultSQLObject = function sql(strings, ...values) { + +function resetDefaultSQL(sql) { + lazyDefaultSQL = sql; + Object.assign(defaultSQLObject, lazyDefaultSQL); + exportsObject.default = exportsObject.sql = lazyDefaultSQL; +} + +var initialDefaultSQL; +var defaultSQLObject = (initialDefaultSQL = function sql(strings, ...values) { if (new.target) { return SQL(strings); } - if (!lazyDefaultSQL) { - lazyDefaultSQL = SQL(undefined); - Object.assign(defaultSQLObject, lazyDefaultSQL); - exportsObject.default = exportsObject.sql = lazyDefaultSQL; + resetDefaultSQL(SQL(undefined)); } return lazyDefaultSQL(strings, ...values); -}; +}); var exportsObject = { sql: defaultSQLObject, diff --git a/src/sql/postgres.zig b/src/sql/postgres.zig index 026706100e..296ce7ee1c 100644 --- a/src/sql/postgres.zig +++ b/src/sql/postgres.zig @@ -13,6 +13,37 @@ pub const PostgresShort = u16; const Crypto = JSC.API.Bun.Crypto; const JSValue = JSC.JSValue; const BoringSSL = @import("../boringssl.zig"); +pub const AnyPostgresError = error{ + ConnectionClosed, + ExpectedRequest, + ExpectedStatement, + InvalidBackendKeyData, + InvalidBinaryData, + InvalidByteSequence, + InvalidByteSequenceForEncoding, + InvalidCharacter, + InvalidMessage, + InvalidMessageLength, + InvalidQueryBinding, + InvalidServerKey, + InvalidServerSignature, + JSError, + MultidimensionalArrayNotSupportedYet, + NullsInArrayNotSupportedYet, + OutOfMemory, + Overflow, + PBKDFD2, + SASL_SIGNATURE_MISMATCH, + SASL_SIGNATURE_INVALID_BASE64, + ShortRead, + TLSNotAvailable, + TLSUpgradeFailed, + UnexpectedMessage, + UNKNOWN_AUTHENTICATION_METHOD, + UNSUPPORTED_AUTHENTICATION_METHOD, + UnsupportedByteaFormat, + UnsupportedIntegerSize, +}; pub const SSLMode = enum(u8) { disable = 0, @@ -176,16 +207,23 @@ pub const PostgresSQLQuery = struct { statement: ?*PostgresSQLStatement = null, query: bun.String = bun.String.empty, cursor_name: bun.String = bun.String.empty, + + // Kept alive by being in the "queries" array from JS. thisValue: JSValue = .undefined, - target: JSC.Strong = JSC.Strong.init(), + status: Status = Status.pending, is_done: bool = false, ref_count: std.atomic.Value(u32) = std.atomic.Value(u32).init(1), binary: bool = false, - pending_value: JSC.Strong = .{}, pub usingnamespace JSC.Codegen.JSPostgresSQLQuery; + pub fn getTarget(this: *PostgresSQLQuery, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + const target = PostgresSQLQuery.targetGetCached(this.thisValue) orelse return .zero; + PostgresSQLQuery.targetSetCached(this.thisValue, globalObject, .zero); + return target; + } + pub const Status = enum(u8) { pending, written, @@ -209,9 +247,6 @@ pub const PostgresSQLQuery = struct { } this.query.deref(); this.cursor_name.deref(); - this.target.deinit(); - this.pending_value.deinit(); - bun.default_allocator.destroy(this); } @@ -233,12 +268,12 @@ pub const PostgresSQLQuery = struct { bun.assert(this.ref_count.fetchAdd(1, .monotonic) > 0); } - pub fn onNoData(this: *@This(), globalObject: *JSC.JSGlobalObject) void { + pub fn onNoData(this: *@This(), globalObject: *JSC.JSGlobalObject, queries_array: JSValue) void { this.status = .success; defer this.deref(); const thisValue = this.thisValue; - const targetValue = this.target.trySwap() orelse JSValue.zero; + const targetValue = this.getTarget(globalObject); if (thisValue == .zero or targetValue == .zero) { return; } @@ -251,13 +286,18 @@ pub const PostgresSQLQuery = struct { this.pending_value.trySwap() orelse .undefined, JSValue.jsNumber(0), JSValue.jsNumber(0), + queries_array, }); } - pub fn onWriteFail(this: *@This(), err: anyerror, globalObject: *JSC.JSGlobalObject) void { + pub fn onWriteFail( + this: *@This(), + err: AnyPostgresError, + globalObject: *JSC.JSGlobalObject, + queries_array: JSValue, + ) void { this.status = .fail; - this.pending_value.deinit(); const thisValue = this.thisValue; - const targetValue = this.target.trySwap() orelse JSValue.zero; + const targetValue = this.getTarget(globalObject); if (thisValue == .zero or targetValue == .zero) { return; } @@ -271,6 +311,7 @@ pub const PostgresSQLQuery = struct { event_loop.runCallback(function, globalObject, thisValue, &.{ targetValue, instance, + queries_array, }); } @@ -279,7 +320,7 @@ pub const PostgresSQLQuery = struct { defer this.deref(); const thisValue = this.thisValue; - const targetValue = this.target.trySwap() orelse JSValue.zero; + const targetValue = this.getTarget(globalObject); if (thisValue == .zero or targetValue == .zero) { return; } @@ -388,14 +429,31 @@ pub const PostgresSQLQuery = struct { } }; - pub fn onSuccess(this: *@This(), command_tag_str: []const u8, globalObject: *JSC.JSGlobalObject) void { + pub fn allowGC(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject) void { + if (thisValue == .zero) { + return; + } + + defer thisValue.ensureStillAlive(); + PostgresSQLQuery.bindingSetCached(thisValue, globalObject, .zero); + PostgresSQLQuery.pendingValueSetCached(thisValue, globalObject, .zero); + PostgresSQLQuery.targetSetCached(thisValue, globalObject, .zero); + } + + fn consumePendingValue(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject) ?JSValue { + const pending_value = PostgresSQLQuery.pendingValueGetCached(thisValue) orelse return null; + PostgresSQLQuery.pendingValueSetCached(thisValue, globalObject, .zero); + return pending_value; + } + + pub fn onSuccess(this: *@This(), command_tag_str: []const u8, globalObject: *JSC.JSGlobalObject, connection: JSC.JSValue) void { this.status = .success; defer this.deref(); const thisValue = this.thisValue; - const targetValue = this.target.trySwap() orelse JSValue.zero; + const targetValue = this.getTarget(globalObject); + defer allowGC(thisValue, globalObject); if (thisValue == .zero or targetValue == .zero) { - this.pending_value.deinit(); return; } @@ -407,9 +465,10 @@ pub const PostgresSQLQuery = struct { event_loop.runCallback(function, globalObject, thisValue, &.{ targetValue, - this.pending_value.trySwap() orelse .undefined, + consumePendingValue(thisValue, globalObject) orelse .undefined, tag.toJSTag(globalObject), tag.toJSNumber(), + PostgresSQLConnection.queriesGetCached(connection) orelse .undefined, }); } @@ -458,7 +517,6 @@ pub const PostgresSQLQuery = struct { if (columns != .undefined) { PostgresSQLQuery.columnsSetCached(this_value, globalThis, columns); } - ptr.pending_value.set(globalThis, pending_value); return this_value; } @@ -477,7 +535,7 @@ pub const PostgresSQLQuery = struct { pub fn doRun(this: *PostgresSQLQuery, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { var arguments_ = callframe.arguments_old(2); const arguments = arguments_.slice(); - var connection = arguments[0].as(PostgresSQLConnection) orelse { + const connection: *PostgresSQLConnection = arguments[0].as(PostgresSQLConnection) orelse { return globalObject.throw("connection must be a PostgresSQLConnection", .{}); }; var query = arguments[1]; @@ -486,11 +544,11 @@ pub const PostgresSQLQuery = struct { return globalObject.throwInvalidArgumentType("run", "query", "Query"); } - this.target.set(globalObject, query); - const binding_value = PostgresSQLQuery.bindingGetCached(callframe.this()) orelse .zero; + const this_value = callframe.this(); + const binding_value = PostgresSQLQuery.bindingGetCached(this_value) orelse .zero; var query_str = this.query.toUTF8(bun.default_allocator); defer query_str.deinit(); - const columns_value = PostgresSQLQuery.columnsGetCached(callframe.this()) orelse .undefined; + const columns_value = PostgresSQLQuery.columnsGetCached(this_value) orelse .undefined; var signature = Signature.generate(globalObject, query_str.slice(), binding_value, columns_value) catch |err| { if (!globalObject.hasException()) @@ -568,9 +626,12 @@ pub const PostgresSQLQuery = struct { connection.requests.writeItem(this) catch {}; this.ref(); this.status = if (did_write) .binding else .pending; + PostgresSQLQuery.targetSetCached(this_value, globalObject, query); if (connection.is_ready_for_query) - connection.flushData(); + connection.flushDataAndResetTimeout() + else if (did_write) + connection.resetConnectionTimeout(); return .undefined; } @@ -665,8 +726,10 @@ pub const PostgresRequest = struct { try writer.int4(@bitCast(@as(i32, -1))); continue; } + if (comptime bun.Environment.enable_logs) { + debug(" -> {s}", .{tag.name() orelse "(unknown)"}); + } - debug(" -> {s}", .{@tagName(tag)}); switch ( // If they pass a value as a string, let's avoid attempting to // convert it to the binary representation. This minimizes the room @@ -674,7 +737,7 @@ pub const PostgresRequest = struct { // differently than what Postgres does when given a timestamp with // timezone. if (tag.isBinaryFormatSupported() and value.isString()) .text else tag) { - .json => { + .jsonb, .json => { var str = bun.String.empty; defer str.deref(); value.jsonStringify(globalObject, 0, &str); @@ -761,7 +824,7 @@ pub const PostgresRequest = struct { params: []const int4, comptime Context: type, writer: protocol.NewWriter(Context), - ) !void { + ) AnyPostgresError!void { { var q = protocol.Parse{ .name = name, @@ -790,7 +853,7 @@ pub const PostgresRequest = struct { comptime Context: type, writer: protocol.NewWriter(Context), signature: *Signature, - ) !void { + ) AnyPostgresError!void { try writeQuery(query, signature.name, signature.fields, Context, writer); try writeBind(signature.name, bun.String.empty, globalObject, array_value, .zero, &.{}, &.{}, Context, writer); var exec = protocol.Execute{ @@ -863,7 +926,7 @@ pub const PostgresRequest = struct { connection.tls_status = .ssl_not_available; debug("Server does not support SSL", .{}); if (connection.ssl_mode == .require) { - connection.fail("Server does not support SSL", error.SSLNotAvailable); + connection.fail("Server does not support SSL", error.TLSNotAvailable); return; } continue; @@ -912,9 +975,6 @@ pub const PostgresSQLConnection = struct { pending_disconnect: bool = false, - on_connect: JSC.Strong = .{}, - on_close: JSC.Strong = .{}, - database: []const u8 = "", user: []const u8 = "", password: []const u8 = "", @@ -928,6 +988,31 @@ pub const PostgresSQLConnection = struct { tls_status: TLSStatus = .none, ssl_mode: SSLMode = .disable, + idle_timeout_interval_ms: u32 = 0, + connection_timeout_ms: u32 = 0, + + /// Before being connected, this is a connection timeout timer. + /// After being connected, this is an idle timeout timer. + timer: JSC.BunTimer.EventLoopTimer = .{ + .tag = .PostgresSQLConnectionTimeout, + .next = .{ + .sec = 0, + .nsec = 0, + }, + }, + + /// This timer controls the maximum lifetime of a connection. + /// It starts when the connection successfully starts (i.e. after handshake is complete). + /// It stops when the connection is closed. + max_lifetime_interval_ms: u32 = 0, + max_lifetime_timer: JSC.BunTimer.EventLoopTimer = .{ + .tag = .PostgresSQLConnectionMaxLifetime, + .next = .{ + .sec = 0, + .nsec = 0, + }, + }, + pub const TLSStatus = union(enum) { none, pending, @@ -942,100 +1027,107 @@ pub const PostgresSQLConnection = struct { pub const AuthenticationState = union(enum) { pending: void, - SASL: SASL, + none: void, ok: void, + SASL: SASL, + md5: void, pub fn zero(this: *AuthenticationState) void { - const bytes = std.mem.asBytes(this); - @memset(bytes, 0); + switch (this.*) { + .SASL => |*sasl| { + sasl.deinit(); + }, + else => {}, + } + this.* = .{ .none = {} }; + } + }; + + pub const SASL = struct { + const nonce_byte_len = 18; + const nonce_base64_len = bun.base64.encodeLenFromSize(nonce_byte_len); + + const server_signature_byte_len = 32; + const server_signature_base64_len = bun.base64.encodeLenFromSize(server_signature_byte_len); + + const salted_password_byte_len = 32; + + nonce_base64_bytes: [nonce_base64_len]u8 = .{0} ** nonce_base64_len, + nonce_len: u8 = 0, + + server_signature_base64_bytes: [server_signature_base64_len]u8 = .{0} ** server_signature_base64_len, + server_signature_len: u8 = 0, + + salted_password_bytes: [salted_password_byte_len]u8 = .{0} ** salted_password_byte_len, + salted_password_created: bool = false, + + status: SASLStatus = .init, + + pub const SASLStatus = enum { + init, + @"continue", + }; + + fn hmac(password: []const u8, data: []const u8) ?[32]u8 { + var buf = std.mem.zeroes([bun.BoringSSL.EVP_MAX_MD_SIZE]u8); + + // TODO: I don't think this is failable. + const result = bun.hmac.generate(password, data, .sha256, &buf) orelse return null; + + assert(result.len == 32); + return buf[0..32].*; } - pub const SASL = struct { - const nonce_byte_len = 18; - const nonce_base64_len = bun.base64.encodeLenFromSize(nonce_byte_len); - - const server_signature_byte_len = 32; - const server_signature_base64_len = bun.base64.encodeLenFromSize(server_signature_byte_len); - - const salted_password_byte_len = 32; - - nonce_base64_bytes: [nonce_base64_len]u8 = .{0} ** nonce_base64_len, - nonce_len: u8 = 0, - - server_signature_base64_bytes: [server_signature_base64_len]u8 = .{0} ** server_signature_base64_len, - server_signature_len: u8 = 0, - - salted_password_bytes: [salted_password_byte_len]u8 = .{0} ** salted_password_byte_len, - salted_password_created: bool = false, - - status: SASLStatus = .init, - - pub const SASLStatus = enum { - init, - @"continue", - }; - - fn hmac(password: []const u8, data: []const u8) ?[32]u8 { - var buf = std.mem.zeroes([bun.BoringSSL.EVP_MAX_MD_SIZE]u8); - - // TODO: I don't think this is failable. - const result = bun.hmac.generate(password, data, .sha256, &buf) orelse return null; - - assert(result.len == 32); - return buf[0..32].*; + pub fn computeSaltedPassword(this: *SASL, salt_bytes: []const u8, iteration_count: u32, connection: *PostgresSQLConnection) !void { + this.salted_password_created = true; + if (Crypto.EVP.pbkdf2(&this.salted_password_bytes, connection.password, salt_bytes, iteration_count, .sha256) == null) { + return error.PBKDFD2; } + } - pub fn computeSaltedPassword(this: *SASL, salt_bytes: []const u8, iteration_count: u32, connection: *PostgresSQLConnection) !void { - this.salted_password_created = true; - if (Crypto.EVP.pbkdf2(&this.salted_password_bytes, connection.password, salt_bytes, iteration_count, .sha256) == null) { - return error.PBKDF2Failed; - } + pub fn saltedPassword(this: *const SASL) []const u8 { + assert(this.salted_password_created); + return this.salted_password_bytes[0..salted_password_byte_len]; + } + + pub fn serverSignature(this: *const SASL) []const u8 { + assert(this.server_signature_len > 0); + return this.server_signature_base64_bytes[0..this.server_signature_len]; + } + + pub fn computeServerSignature(this: *SASL, auth_string: []const u8) !void { + assert(this.server_signature_len == 0); + + const server_key = hmac(this.saltedPassword(), "Server Key") orelse return error.InvalidServerKey; + const server_signature_bytes = hmac(&server_key, auth_string) orelse return error.InvalidServerSignature; + this.server_signature_len = @intCast(bun.base64.encode(&this.server_signature_base64_bytes, &server_signature_bytes)); + } + + pub fn clientKey(this: *const SASL) [32]u8 { + return hmac(this.saltedPassword(), "Client Key").?; + } + + pub fn clientKeySignature(_: *const SASL, client_key: []const u8, auth_string: []const u8) [32]u8 { + var sha_digest = std.mem.zeroes(bun.sha.SHA256.Digest); + bun.sha.SHA256.hash(client_key, &sha_digest, JSC.VirtualMachine.get().rareData().boringEngine()); + return hmac(&sha_digest, auth_string).?; + } + + pub fn nonce(this: *SASL) []const u8 { + if (this.nonce_len == 0) { + var bytes: [nonce_byte_len]u8 = .{0} ** nonce_byte_len; + bun.rand(&bytes); + this.nonce_len = @intCast(bun.base64.encode(&this.nonce_base64_bytes, &bytes)); } + return this.nonce_base64_bytes[0..this.nonce_len]; + } - pub fn saltedPassword(this: *const SASL) []const u8 { - assert(this.salted_password_created); - return this.salted_password_bytes[0..salted_password_byte_len]; - } - - pub fn serverSignature(this: *const SASL) []const u8 { - assert(this.server_signature_len > 0); - return this.server_signature_base64_bytes[0..this.server_signature_len]; - } - - pub fn computeServerSignature(this: *SASL, auth_string: []const u8) !void { - assert(this.server_signature_len == 0); - - const server_key = hmac(this.saltedPassword(), "Server Key") orelse return error.InvalidServerKey; - const server_signature_bytes = hmac(&server_key, auth_string) orelse return error.InvalidServerSignature; - this.server_signature_len = @intCast(bun.base64.encode(&this.server_signature_base64_bytes, &server_signature_bytes)); - } - - pub fn clientKey(this: *const SASL) [32]u8 { - return hmac(this.saltedPassword(), "Client Key").?; - } - - pub fn clientKeySignature(_: *const SASL, client_key: []const u8, auth_string: []const u8) [32]u8 { - var sha_digest = std.mem.zeroes(bun.sha.SHA256.Digest); - bun.sha.SHA256.hash(client_key, &sha_digest, JSC.VirtualMachine.get().rareData().boringEngine()); - return hmac(&sha_digest, auth_string).?; - } - - pub fn nonce(this: *SASL) []const u8 { - if (this.nonce_len == 0) { - var bytes: [nonce_byte_len]u8 = .{0} ** nonce_byte_len; - bun.rand(&bytes); - this.nonce_len = @intCast(bun.base64.encode(&this.nonce_base64_bytes, &bytes)); - } - return this.nonce_base64_bytes[0..this.nonce_len]; - } - - pub fn deinit(this: *SASL) void { - this.nonce_len = 0; - this.salted_password_created = false; - this.server_signature_len = 0; - this.status = .init; - } - }; + pub fn deinit(this: *SASL) void { + this.nonce_len = 0; + this.salted_password_created = false; + this.server_signature_len = 0; + this.status = .init; + } }; pub const Status = enum { @@ -1050,6 +1142,64 @@ pub const PostgresSQLConnection = struct { pub usingnamespace JSC.Codegen.JSPostgresSQLConnection; + fn getTimeoutInterval(this: *const PostgresSQLConnection) u32 { + return switch (this.status) { + .connected => this.idle_timeout_interval_ms, + .failed => 0, + else => this.connection_timeout_ms, + }; + } + + pub fn resetConnectionTimeout(this: *PostgresSQLConnection) void { + const interval = this.getTimeoutInterval(); + if (this.timer.state == .ACTIVE) { + this.globalObject.bunVM().timer.remove(&this.timer); + } + if (interval == 0) { + return; + } + + this.timer.next = bun.timespec.msFromNow(@intCast(interval)); + this.globalObject.bunVM().timer.insert(&this.timer); + } + + pub fn getQueries(_: *PostgresSQLConnection, thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + if (PostgresSQLConnection.queriesGetCached(thisValue)) |value| { + return value; + } + + const array = JSC.JSValue.createEmptyArray(globalObject, 0); + PostgresSQLConnection.queriesSetCached(thisValue, globalObject, array); + + return array; + } + + pub fn getOnConnect(_: *PostgresSQLConnection, thisValue: JSC.JSValue, _: *JSC.JSGlobalObject) JSC.JSValue { + if (PostgresSQLConnection.onconnectGetCached(thisValue)) |value| { + return value; + } + + return .undefined; + } + + pub fn setOnConnect(_: *PostgresSQLConnection, thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) bool { + PostgresSQLConnection.onconnectSetCached(thisValue, globalObject, value); + return true; + } + + pub fn getOnClose(_: *PostgresSQLConnection, thisValue: JSC.JSValue, _: *JSC.JSGlobalObject) JSC.JSValue { + if (PostgresSQLConnection.oncloseGetCached(thisValue)) |value| { + return value; + } + + return .undefined; + } + + pub fn setOnClose(_: *PostgresSQLConnection, thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) bool { + PostgresSQLConnection.oncloseSetCached(thisValue, globalObject, value); + return true; + } + pub fn setupTLS(this: *PostgresSQLConnection) void { debug("setupTLS", .{}); const new_socket = uws.us_socket_upgrade_to_tls(this.socket.SocketTCP.socket.connected, this.tls_ctx.?, this.tls_config.server_name) orelse { @@ -1066,8 +1216,47 @@ pub const PostgresSQLConnection = struct { this.start(); } + fn setupMaxLifetimeTimerIfNecessary(this: *PostgresSQLConnection) void { + if (this.max_lifetime_interval_ms == 0) return; + if (this.max_lifetime_timer.state == .ACTIVE) return; + + this.max_lifetime_timer.next = bun.timespec.msFromNow(@intCast(this.max_lifetime_interval_ms)); + this.globalObject.bunVM().timer.insert(&this.max_lifetime_timer); + } + + pub fn onConnectionTimeout(this: *PostgresSQLConnection) JSC.BunTimer.EventLoopTimer.Arm { + debug("onConnectionTimeout", .{}); + this.timer.state = .FIRED; + if (this.getTimeoutInterval() == 0) { + this.resetConnectionTimeout(); + return .disarm; + } + + switch (this.status) { + .connected => { + this.failFmt(.ERR_POSTGRES_IDLE_TIMEOUT, "Idle timeout reached after {}", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.idle_timeout_interval_ms) *| std.time.ns_per_ms)}); + }, + else => { + this.failFmt(.ERR_POSTGRES_CONNECTION_TIMEOUT, "Connection timeout after {}", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.connection_timeout_ms) *| std.time.ns_per_ms)}); + }, + .sent_startup_message => { + this.failFmt(.ERR_POSTGRES_CONNECTION_TIMEOUT, "Connection timed out after {} (sent startup message, but never received response)", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.connection_timeout_ms) *| std.time.ns_per_ms)}); + }, + } + return .disarm; + } + + pub fn onMaxLifetimeTimeout(this: *PostgresSQLConnection) JSC.BunTimer.EventLoopTimer.Arm { + debug("onMaxLifetimeTimeout", .{}); + this.max_lifetime_timer.state = .FIRED; + if (this.status == .failed) return .disarm; + this.failFmt(.ERR_POSTGRES_LIFETIME_TIMEOUT, "Max lifetime timeout reached after {}", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.max_lifetime_interval_ms) *| std.time.ns_per_ms)}); + return .disarm; + } fn start(this: *PostgresSQLConnection) void { + this.setupMaxLifetimeTimerIfNecessary(); + this.resetConnectionTimeout(); this.sendStartupMessage(); const event_loop = this.globalObject.bunVM().eventLoop(); @@ -1094,10 +1283,11 @@ pub const PostgresSQLConnection = struct { if (this.status == status) return; this.status = status; + this.resetConnectionTimeout(); + switch (status) { .connected => { - const on_connect = this.on_connect.swap(); - if (on_connect == .zero) return; + const on_connect = this.consumeOnConnectCallback(this.globalObject) orelse return; const js_value = this.js_value; js_value.ensureStillAlive(); this.globalObject.queueMicrotask(on_connect, &[_]JSValue{ JSValue.jsNull(), js_value }); @@ -1110,10 +1300,16 @@ pub const PostgresSQLConnection = struct { pub fn finalize(this: *PostgresSQLConnection) void { debug("PostgresSQLConnection finalize", .{}); + this.stopTimers(); this.js_value = .zero; this.deref(); } + pub fn flushDataAndResetTimeout(this: *PostgresSQLConnection) void { + this.resetConnectionTimeout(); + this.flushData(); + } + pub fn flushData(this: *PostgresSQLConnection) void { const chunk = this.write_buffer.remaining(); if (chunk.len == 0) return; @@ -1126,27 +1322,78 @@ pub const PostgresSQLConnection = struct { pub fn failWithJSValue(this: *PostgresSQLConnection, value: JSValue) void { defer this.updateHasPendingActivity(); + this.stopTimers(); if (this.status == .failed) return; this.status = .failed; - if (!this.socket.isClosed()) this.socket.close(); - const on_close = this.on_close.swap(); - if (on_close == .zero) return; + this.ref(); + defer this.deref(); + if (!this.socket.isClosed()) this.socket.close(); + const on_close = this.consumeOnCloseCallback(this.globalObject) orelse return; + + const loop = this.globalObject.bunVM().eventLoop(); + loop.enter(); + defer loop.exit(); _ = on_close.call( this.globalObject, this.js_value, &[_]JSValue{ value, + this.getQueriesArray(), }, ) catch |e| this.globalObject.reportActiveExceptionAsUnhandled(e); } - pub fn fail(this: *PostgresSQLConnection, message: []const u8, err: anyerror) void { + pub fn failFmt(this: *PostgresSQLConnection, comptime error_code: JSC.Error, comptime fmt: [:0]const u8, args: anytype) void { + this.failWithJSValue(error_code.fmt(this.globalObject, fmt, args)); + } + + pub fn fail(this: *PostgresSQLConnection, message: []const u8, err: AnyPostgresError) void { debug("failed: {s}: {s}", .{ message, @errorName(err) }); - const instance = this.globalObject.createErrorInstance("{s}", .{message}); - instance.put(this.globalObject, JSC.ZigString.static("code"), String.init(@errorName(err)).toJS(this.globalObject)); - this.failWithJSValue(instance); + + const globalObject = this.globalObject; + const error_code: JSC.Error = switch (err) { + error.ConnectionClosed => JSC.Error.ERR_POSTGRES_CONNECTION_CLOSED, + error.ExpectedRequest => JSC.Error.ERR_POSTGRES_EXPECTED_REQUEST, + error.ExpectedStatement => JSC.Error.ERR_POSTGRES_EXPECTED_STATEMENT, + error.InvalidBackendKeyData => JSC.Error.ERR_POSTGRES_INVALID_BACKEND_KEY_DATA, + error.InvalidBinaryData => JSC.Error.ERR_POSTGRES_INVALID_BINARY_DATA, + error.InvalidByteSequence => JSC.Error.ERR_POSTGRES_INVALID_BYTE_SEQUENCE, + error.InvalidByteSequenceForEncoding => JSC.Error.ERR_POSTGRES_INVALID_BYTE_SEQUENCE_FOR_ENCODING, + error.InvalidCharacter => JSC.Error.ERR_POSTGRES_INVALID_CHARACTER, + error.InvalidMessage => JSC.Error.ERR_POSTGRES_INVALID_MESSAGE, + error.InvalidMessageLength => JSC.Error.ERR_POSTGRES_INVALID_MESSAGE_LENGTH, + error.InvalidQueryBinding => JSC.Error.ERR_POSTGRES_INVALID_QUERY_BINDING, + error.InvalidServerKey => JSC.Error.ERR_POSTGRES_INVALID_SERVER_KEY, + error.InvalidServerSignature => JSC.Error.ERR_POSTGRES_INVALID_SERVER_SIGNATURE, + error.MultidimensionalArrayNotSupportedYet => JSC.Error.ERR_POSTGRES_MULTIDIMENSIONAL_ARRAY_NOT_SUPPORTED_YET, + error.NullsInArrayNotSupportedYet => JSC.Error.ERR_POSTGRES_NULLS_IN_ARRAY_NOT_SUPPORTED_YET, + error.Overflow => JSC.Error.ERR_POSTGRES_OVERFLOW, + error.PBKDFD2 => JSC.Error.ERR_POSTGRES_AUTHENTICATION_FAILED_PBKDF2, + error.SASL_SIGNATURE_MISMATCH => JSC.Error.ERR_POSTGRES_SASL_SIGNATURE_MISMATCH, + error.SASL_SIGNATURE_INVALID_BASE64 => JSC.Error.ERR_POSTGRES_SASL_SIGNATURE_INVALID_BASE64, + error.TLSNotAvailable => JSC.Error.ERR_POSTGRES_TLS_NOT_AVAILABLE, + error.TLSUpgradeFailed => JSC.Error.ERR_POSTGRES_TLS_UPGRADE_FAILED, + error.UnexpectedMessage => JSC.Error.ERR_POSTGRES_UNEXPECTED_MESSAGE, + error.UNKNOWN_AUTHENTICATION_METHOD => JSC.Error.ERR_POSTGRES_UNKNOWN_AUTHENTICATION_METHOD, + error.UNSUPPORTED_AUTHENTICATION_METHOD => JSC.Error.ERR_POSTGRES_UNSUPPORTED_AUTHENTICATION_METHOD, + error.UnsupportedByteaFormat => JSC.Error.ERR_POSTGRES_UNSUPPORTED_BYTEA_FORMAT, + error.UnsupportedIntegerSize => JSC.Error.ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE, + error.JSError => { + this.failWithJSValue(globalObject.takeException(error.JSError)); + return; + }, + error.OutOfMemory => { + // TODO: add binding for creating an out of memory error? + this.failWithJSValue(globalObject.takeException(globalObject.throwOutOfMemory())); + return; + }, + error.ShortRead => { + bun.unreachablePanic("Assertion failed: ShortRead should be handled by the caller in postgres", .{}); + }, + }; + this.failWithJSValue(error_code.fmt(globalObject, "{s}", .{message})); } pub fn onClose(this: *PostgresSQLConnection) void { @@ -1210,22 +1457,35 @@ pub const PostgresSQLConnection = struct { pub fn onHandshake(this: *PostgresSQLConnection, success: i32, ssl_error: uws.us_bun_verify_error_t) void { debug("onHandshake: {d} {d}", .{ success, ssl_error.error_no }); + if (this.tls_config.reject_unauthorized == 0) { + return; + } + + const do_tls_verification = switch (this.ssl_mode) { + // https://github.com/porsager/postgres/blob/6ec85a432b17661ccacbdf7f765c651e88969d36/src/connection.js#L272-L279 + .verify_ca, .verify_full => true, + else => false, + }; + + if (!do_tls_verification) { + return; + } + if (success != 1) { this.failWithJSValue(ssl_error.toJS(this.globalObject)); return; } - if (this.tls_config.reject_unauthorized == 1) { - if (ssl_error.error_no != 0) { + if (ssl_error.error_no != 0) { + this.failWithJSValue(ssl_error.toJS(this.globalObject)); + return; + } + + const ssl_ptr = @as(*BoringSSL.SSL, @ptrCast(this.socket.getNativeHandle())); + if (BoringSSL.SSL_get_servername(ssl_ptr, 0)) |servername| { + const hostname = servername[0..bun.len(servername)]; + if (!BoringSSL.checkServerIdentity(ssl_ptr, hostname)) { this.failWithJSValue(ssl_error.toJS(this.globalObject)); - return; - } - const ssl_ptr = @as(*BoringSSL.SSL, @ptrCast(this.socket.getNativeHandle())); - if (BoringSSL.SSL_get_servername(ssl_ptr, 0)) |servername| { - const hostname = servername[0..bun.len(servername)]; - if (!BoringSSL.checkServerIdentity(ssl_ptr, hostname)) { - this.failWithJSValue(ssl_error.toJS(this.globalObject)); - } } } } @@ -1264,6 +1524,7 @@ pub const PostgresSQLConnection = struct { this.poll_ref.ref(vm); } + this.resetConnectionTimeout(); this.deref(); } @@ -1299,11 +1560,8 @@ pub const PostgresSQLConnection = struct { this.read_buffer.byte_list.len = 0; this.read_buffer.write(bun.default_allocator, data[offset..]) catch @panic("failed to write to read buffer"); } else { - if (comptime bun.Environment.allow_assert) { - if (@errorReturnTrace()) |trace| { - debug("Error: {s}\n{}", .{ @errorName(err), trace }); - } - } + bun.handleErrorReturnTrace(err, @errorReturnTrace()); + this.fail("Failed to read data", err); } }; @@ -1315,11 +1573,7 @@ pub const PostgresSQLConnection = struct { this.read_buffer.write(bun.default_allocator, data) catch @panic("failed to write to read buffer"); PostgresRequest.onData(this, Reader, this.bufferedReader()) catch |err| { if (err != error.ShortRead) { - if (comptime bun.Environment.allow_assert) { - if (@errorReturnTrace()) |trace| { - debug("Error: {s}\n{}", .{ @errorName(err), trace }); - } - } + bun.handleErrorReturnTrace(err, @errorReturnTrace()); this.fail("Failed to read data", err); return; } @@ -1363,7 +1617,7 @@ pub const PostgresSQLConnection = struct { pub fn call(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { var vm = globalObject.bunVM(); - const arguments = callframe.arguments_old(10).slice(); + const arguments = callframe.arguments_old(13).slice(); const hostname_str = arguments[0].toBunString(globalObject); defer hostname_str.deref(); const port = arguments[1].coerce(i32, globalObject); @@ -1460,13 +1714,15 @@ pub const PostgresSQLConnection = struct { const on_connect = arguments[8]; const on_close = arguments[9]; + const idle_timeout = arguments[10].toInt32(); + const connection_timeout = arguments[11].toInt32(); + const max_lifetime = arguments[12].toInt32(); - var ptr = try bun.default_allocator.create(PostgresSQLConnection); + const ptr: *PostgresSQLConnection = try bun.default_allocator.create(PostgresSQLConnection); ptr.* = PostgresSQLConnection{ .globalObject = globalObject, - .on_connect = JSC.Strong.create(on_connect, globalObject), - .on_close = JSC.Strong.create(on_close, globalObject), + .database = database, .user = username, .password = password, @@ -1479,6 +1735,9 @@ pub const PostgresSQLConnection = struct { .tls_ctx = tls_ctx, .ssl_mode = ssl_mode, .tls_status = if (ssl_mode != .disable) .pending else .none, + .idle_timeout_interval_ms = @intCast(idle_timeout), + .connection_timeout_ms = @intCast(connection_timeout), + .max_lifetime_interval_ms = @intCast(max_lifetime), }; ptr.updateHasPendingActivity(); @@ -1487,6 +1746,9 @@ pub const PostgresSQLConnection = struct { js_value.ensureStillAlive(); ptr.js_value = js_value; + PostgresSQLConnection.onconnectSetCached(js_value, globalObject, on_connect); + PostgresSQLConnection.oncloseSetCached(js_value, globalObject, on_close); + { const hostname = hostname_str.toUTF8(bun.default_allocator); defer hostname.deinit(); @@ -1498,6 +1760,7 @@ pub const PostgresSQLConnection = struct { vm.rareData().postgresql_context.tcp = ctx_; break :brk ctx_; }; + ptr.socket = .{ .SocketTCP = uws.SocketTCP.connectAnon(hostname.slice(), port, ctx, ptr, false) catch |err| { tls_config.deinit(); @@ -1508,6 +1771,8 @@ pub const PostgresSQLConnection = struct { return globalObject.throwError(err, "failed to connect to postgresql"); }, }; + + ptr.resetConnectionTimeout(); } return js_value; @@ -1600,7 +1865,17 @@ pub const PostgresSQLConnection = struct { return .undefined; } + pub fn stopTimers(this: *PostgresSQLConnection) void { + if (this.timer.state == .ACTIVE) { + this.globalObject.bunVM().timer.remove(&this.timer); + } + if (this.max_lifetime_timer.state == .ACTIVE) { + this.globalObject.bunVM().timer.remove(&this.max_lifetime_timer); + } + } + pub fn deinit(this: *@This()) void { + this.stopTimers(); var iter = this.statements.valueIterator(); while (iter.next()) |stmt_ptr| { var stmt = stmt_ptr.*; @@ -1609,8 +1884,6 @@ pub const PostgresSQLConnection = struct { this.statements.deinit(bun.default_allocator); this.write_buffer.deinit(bun.default_allocator); this.read_buffer.deinit(bun.default_allocator); - this.on_close.deinit(); - this.on_connect.deinit(); this.backend_parameters.deinit(); bun.default_allocator.free(this.options_buf); this.tls_config.deinit(); @@ -1618,6 +1891,8 @@ pub const PostgresSQLConnection = struct { } pub fn disconnect(this: *@This()) void { + this.stopTimers(); + if (this.status == .connected) { this.status = .disconnected; this.poll_ref.disable(); @@ -1636,12 +1911,12 @@ pub const PostgresSQLConnection = struct { pub const Writer = struct { connection: *PostgresSQLConnection, - pub fn write(this: Writer, data: []const u8) anyerror!void { + pub fn write(this: Writer, data: []const u8) AnyPostgresError!void { var buffer = &this.connection.write_buffer; try buffer.write(bun.default_allocator, data); } - pub fn pwrite(this: Writer, data: []const u8, index: usize) anyerror!void { + pub fn pwrite(this: Writer, data: []const u8, index: usize) AnyPostgresError!void { @memcpy(this.connection.write_buffer.byte_list.slice()[index..][0..data.len], data); } @@ -1676,7 +1951,7 @@ pub const PostgresSQLConnection = struct { pub fn ensureCapacity(this: Reader, count: usize) bool { return @as(usize, this.connection.read_buffer.head) + count <= @as(usize, this.connection.read_buffer.byte_list.len); } - pub fn read(this: Reader, count: usize) anyerror!Data { + pub fn read(this: Reader, count: usize) AnyPostgresError!Data { var remaining = this.connection.read_buffer.remaining(); if (@as(usize, remaining.len) < count) { return error.ShortRead; @@ -1687,7 +1962,7 @@ pub const PostgresSQLConnection = struct { .temporary = remaining[0..count], }; } - pub fn readZ(this: Reader) anyerror!Data { + pub fn readZ(this: Reader) AnyPostgresError!Data { const remain = this.connection.read_buffer.remaining(); if (bun.strings.indexOfChar(remain, 0)) |zero| { @@ -1799,7 +2074,7 @@ pub const PostgresSQLConnection = struct { } } - pub fn fromBytes(binary: bool, oid: int4, bytes: []const u8, globalObject: *JSC.JSGlobalObject) anyerror!DataCell { + pub fn fromBytes(binary: bool, oid: int4, bytes: []const u8, globalObject: *JSC.JSGlobalObject) !DataCell { switch (@as(types.Tag, @enumFromInt(@as(short, @intCast(oid))))) { // TODO: .int2_array, .float8_array inline .int4_array, .float4_array => |tag| { @@ -1876,7 +2151,7 @@ pub const PostgresSQLConnection = struct { return DataCell{ .tag = .float8, .value = .{ .float8 = float4 } }; } }, - .json => { + .jsonb, .json => { return DataCell{ .tag = .json, .value = .{ .json = String.createUTF8(bytes).value.WTFStringImpl }, .free_value = 1 }; }, .bool => { @@ -1956,7 +2231,7 @@ pub const PostgresSQLConnection = struct { return pg_ntoT(32, x); } - pub fn parseBinary(comptime tag: types.Tag, comptime ReturnType: type, bytes: []const u8) anyerror!ReturnType { + pub fn parseBinary(comptime tag: types.Tag, comptime ReturnType: type, bytes: []const u8) AnyPostgresError!ReturnType { switch (comptime tag) { .float8 => { return @as(f64, @bitCast(try parseBinary(.int8, i64, bytes))); @@ -2017,7 +2292,7 @@ pub const PostgresSQLConnection = struct { return JSC__constructObjectFromDataCell(globalObject, array, structure, this.list.ptr, @truncate(this.fields.len)); } - pub fn put(this: *Putter, index: u32, optional_bytes: ?*Data) anyerror!bool { + pub fn put(this: *Putter, index: u32, optional_bytes: ?*Data) !bool { const oid = this.fields[index].type_oid; debug("index: {d}, oid: {d}", .{ index, oid }); @@ -2072,7 +2347,7 @@ pub const PostgresSQLConnection = struct { const binding_value = PostgresSQLQuery.bindingGetCached(req.thisValue) orelse .zero; const columns_value = PostgresSQLQuery.columnsGetCached(req.thisValue) orelse .zero; PostgresRequest.bindAndExecute(this.globalObject, stmt, binding_value, columns_value, PostgresSQLConnection.Writer, this.writer()) catch |err| { - req.onWriteFail(err, this.globalObject); + req.onWriteFail(err, this.globalObject, this.getQueriesArray()); req.deref(); this.requests.discard(1); continue; @@ -2091,7 +2366,11 @@ pub const PostgresSQLConnection = struct { return any; } - pub fn on(this: *PostgresSQLConnection, comptime MessageType: @Type(.EnumLiteral), comptime Context: type, reader: protocol.NewReader(Context)) !void { + pub fn getQueriesArray(this: *const PostgresSQLConnection) JSValue { + return PostgresSQLConnection.queriesGetCached(this.js_value) orelse .zero; + } + + pub fn on(this: *PostgresSQLConnection, comptime MessageType: @Type(.EnumLiteral), comptime Context: type, reader: protocol.NewReader(Context)) AnyPostgresError!void { debug("on({s})", .{@tagName(MessageType)}); if (comptime MessageType != .ReadyForQuery) { this.is_ready_for_query = false; @@ -2181,7 +2460,7 @@ pub const PostgresSQLConnection = struct { debug("-> {s}", .{cmd.command_tag.slice()}); _ = this.requests.discard(1); defer this.updateRef(); - request.onSuccess(cmd.command_tag.slice(), this.globalObject); + request.onSuccess(cmd.command_tag.slice(), this.globalObject, this.js_value); }, .BindComplete => { try reader.eatMessage(protocol.BindComplete); @@ -2255,7 +2534,12 @@ pub const PostgresSQLConnection = struct { const iteration_count = try cont.iterationCount(); - const server_salt_decoded_base64 = try bun.base64.decodeAlloc(bun.z_allocator, cont.s); + const server_salt_decoded_base64 = bun.base64.decodeAlloc(bun.z_allocator, cont.s) catch |err| { + return switch (err) { + error.DecodingFailed => error.SASL_SIGNATURE_INVALID_BASE64, + else => |e| e, + }; + }; defer bun.z_allocator.free(server_salt_decoded_base64); try sasl.computeSaltedPassword(server_salt_decoded_base64, iteration_count, this); @@ -2352,8 +2636,46 @@ pub const PostgresSQLConnection = struct { this.flushData(); }, + .MD5Password => |md5| { + debug("MD5Password", .{}); + // Format is: md5 + md5(md5(password + username) + salt) + var first_hash_buf: bun.sha.MD5.Digest = undefined; + var first_hash_str: [32]u8 = undefined; + var final_hash_buf: bun.sha.MD5.Digest = undefined; + var final_hash_str: [32]u8 = undefined; + var final_password_buf: [36]u8 = undefined; + + // First hash: md5(password + username) + var first_hasher = bun.sha.MD5.init(); + first_hasher.update(this.password); + first_hasher.update(this.user); + first_hasher.final(&first_hash_buf); + const first_hash_str_output = std.fmt.bufPrint(&first_hash_str, "{x}", .{std.fmt.fmtSliceHexLower(&first_hash_buf)}) catch unreachable; + + // Second hash: md5(first_hash + salt) + var final_hasher = bun.sha.MD5.init(); + final_hasher.update(first_hash_str_output); + final_hasher.update(&md5.salt); + final_hasher.final(&final_hash_buf); + const final_hash_str_output = std.fmt.bufPrint(&final_hash_str, "{x}", .{std.fmt.fmtSliceHexLower(&final_hash_buf)}) catch unreachable; + + // Format final password as "md5" + final_hash + const final_password = std.fmt.bufPrintZ(&final_password_buf, "md5{s}", .{final_hash_str_output}) catch unreachable; + + var response = protocol.PasswordMessage{ + .password = .{ + .temporary = final_password, + }, + }; + + this.authentication_state = .{ .md5 = {} }; + try response.writeInternal(PostgresSQLConnection.Writer, this.writer()); + this.flushData(); + }, + else => { debug("TODO auth: {s}", .{@tagName(std.meta.activeTag(auth))}); + this.fail("TODO: support authentication method: {s}", error.UNSUPPORTED_AUTHENTICATION_METHOD); }, } }, @@ -2371,19 +2693,12 @@ pub const PostgresSQLConnection = struct { var err: protocol.ErrorResponse = undefined; try err.decodeInternal(Context, reader); - if (this.status == .connecting) { - this.status = .failed; + if (this.status == .connecting or this.status == .sent_startup_message) { defer { err.deinit(); - this.poll_ref.unref(this.globalObject.bunVM()); - this.updateHasPendingActivity(); } - const on_connect = this.on_connect.swap(); - if (on_connect == .zero) return; - const js_value = this.js_value; - js_value.ensureStillAlive(); - this.globalObject.queueMicrotask(on_connect, &[_]JSValue{ err.toJS(this.globalObject), js_value }); + this.failWithJSValue(err.toJS(this.globalObject)); // it shouldn't enqueue any requests while connecting bun.assert(this.requests.count == 0); @@ -2426,7 +2741,7 @@ pub const PostgresSQLConnection = struct { try reader.eatMessage(protocol.CloseComplete); var request = this.current() orelse return error.ExpectedRequest; _ = this.requests.discard(1); - request.onSuccess("CLOSECOMPLETE", this.globalObject); + request.onSuccess("CLOSECOMPLETE", this.globalObject, this.getQueriesArray()); }, .CopyInResponse => { debug("TODO CopyInResponse", .{}); @@ -2443,7 +2758,7 @@ pub const PostgresSQLConnection = struct { var request = this.current() orelse return error.ExpectedRequest; _ = this.requests.discard(1); this.updateRef(); - request.onSuccess("", this.globalObject); + request.onSuccess("", this.globalObject, this.getQueriesArray()); }, .CopyOutResponse => { debug("TODO CopyOutResponse", .{}); @@ -2467,25 +2782,21 @@ pub const PostgresSQLConnection = struct { } } - pub fn doFlush(this: *PostgresSQLConnection, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { - _ = callframe; - _ = globalObject; - _ = this; - - return .undefined; - } - - pub fn createQuery(this: *PostgresSQLConnection, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSValue { - _ = callframe; - _ = globalObject; - _ = this; - - return .undefined; - } - pub fn getConnected(this: *PostgresSQLConnection, _: *JSC.JSGlobalObject) JSValue { return JSValue.jsBoolean(this.status == Status.connected); } + + pub fn consumeOnConnectCallback(this: *const PostgresSQLConnection, globalObject: *JSC.JSGlobalObject) ?JSC.JSValue { + const on_connect = PostgresSQLConnection.onconnectGetCached(this.js_value) orelse return null; + PostgresSQLConnection.onconnectSetCached(this.js_value, globalObject, .zero); + return on_connect; + } + + pub fn consumeOnCloseCallback(this: *const PostgresSQLConnection, globalObject: *JSC.JSGlobalObject) ?JSC.JSValue { + const on_close = PostgresSQLConnection.oncloseGetCached(this.js_value) orelse return null; + PostgresSQLConnection.oncloseSetCached(this.js_value, globalObject, .zero); + return on_close; + } }; pub const PostgresSQLStatement = struct { @@ -2723,7 +3034,7 @@ const Signature = struct { .float8 => try name.appendSlice(".float8"), .float4 => try name.appendSlice(".float4"), .numeric => try name.appendSlice(".numeric"), - .json => try name.appendSlice(".json"), + .json, .jsonb => try name.appendSlice(".json"), .bool => try name.appendSlice(".bool"), .timestamp => try name.appendSlice(".timestamp"), .timestamptz => try name.appendSlice(".timestamptz"), diff --git a/src/sql/postgres/postgres_protocol.zig b/src/sql/postgres/postgres_protocol.zig index 4aee1791f9..60eeaf9f9d 100644 --- a/src/sql/postgres/postgres_protocol.zig +++ b/src/sql/postgres/postgres_protocol.zig @@ -15,7 +15,7 @@ const int4 = postgres.int4; const int8 = postgres.int8; const PostgresInt64 = postgres.PostgresInt64; const types = postgres.types; - +const AnyPostgresError = postgres.AnyPostgresError; pub const ArrayList = struct { array: *std.ArrayList(u8), @@ -23,11 +23,11 @@ pub const ArrayList = struct { return this.array.items.len; } - pub fn write(this: @This(), bytes: []const u8) anyerror!void { + pub fn write(this: @This(), bytes: []const u8) AnyPostgresError!void { try this.array.appendSlice(bytes); } - pub fn pwrite(this: @This(), bytes: []const u8, i: usize) anyerror!void { + pub fn pwrite(this: @This(), bytes: []const u8, i: usize) AnyPostgresError!void { @memcpy(this.array.items[i..][0..bytes.len], bytes); } @@ -71,7 +71,7 @@ pub const StackReader = struct { pub fn ensureCapacity(this: StackReader, count: usize) bool { return this.buffer.len >= (this.offset.* + count); } - pub fn read(this: StackReader, count: usize) anyerror!Data { + pub fn read(this: StackReader, count: usize) AnyPostgresError!Data { const offset = this.offset.*; if (!this.ensureCapacity(count)) { return error.ShortRead; @@ -82,7 +82,7 @@ pub const StackReader = struct { .temporary = this.buffer[offset..this.offset.*], }; } - pub fn readZ(this: StackReader) anyerror!Data { + pub fn readZ(this: StackReader) AnyPostgresError!Data { const remaining = this.peek(); if (bun.strings.indexOfChar(remaining, 0)) |zero| { this.skip(zero + 1); @@ -98,8 +98,8 @@ pub const StackReader = struct { pub fn NewWriterWrap( comptime Context: type, comptime offsetFn_: (fn (ctx: Context) usize), - comptime writeFunction_: (fn (ctx: Context, bytes: []const u8) anyerror!void), - comptime pwriteFunction_: (fn (ctx: Context, bytes: []const u8, offset: usize) anyerror!void), + comptime writeFunction_: (fn (ctx: Context, bytes: []const u8) AnyPostgresError!void), + comptime pwriteFunction_: (fn (ctx: Context, bytes: []const u8, offset: usize) AnyPostgresError!void), ) type { return struct { wrapped: Context, @@ -111,7 +111,7 @@ pub fn NewWriterWrap( pub const WrappedWriter = @This(); - pub inline fn write(this: @This(), data: []const u8) anyerror!void { + pub inline fn write(this: @This(), data: []const u8) AnyPostgresError!void { try writeFn(this.wrapped, data); } @@ -119,16 +119,16 @@ pub fn NewWriterWrap( index: usize, context: WrappedWriter, - pub fn write(this: LengthWriter) anyerror!void { + pub fn write(this: LengthWriter) AnyPostgresError!void { try this.context.pwrite(&Int32(this.context.offset() - this.index), this.index); } - pub fn writeExcludingSelf(this: LengthWriter) anyerror!void { + pub fn writeExcludingSelf(this: LengthWriter) AnyPostgresError!void { try this.context.pwrite(&Int32(this.context.offset() -| (this.index + 4)), this.index); } }; - pub inline fn length(this: @This()) anyerror!LengthWriter { + pub inline fn length(this: @This()) AnyPostgresError!LengthWriter { const i = this.offset(); try this.int4(0); return LengthWriter{ @@ -141,7 +141,7 @@ pub fn NewWriterWrap( return offsetFn(this.wrapped); } - pub inline fn pwrite(this: @This(), data: []const u8, i: usize) anyerror!void { + pub inline fn pwrite(this: @This(), data: []const u8, i: usize) AnyPostgresError!void { try pwriteFn(this.wrapped, data, i); } @@ -208,81 +208,81 @@ pub fn NewWriterWrap( pub const FieldType = enum(u8) { /// Severity: the field contents are ERROR, FATAL, or PANIC (in an error message), or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a localized translation of one of these. Always present. - S = 'S', + severity = 'S', /// Severity: the field contents are ERROR, FATAL, or PANIC (in an error message), or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message). This is identical to the S field except that the contents are never localized. This is present only in messages generated by PostgreSQL versions 9.6 and later. - V = 'V', + localized_severity = 'V', /// Code: the SQLSTATE code for the error (see Appendix A). Not localizable. Always present. - C = 'C', + code = 'C', /// Message: the primary human-readable error message. This should be accurate but terse (typically one line). Always present. - M = 'M', + message = 'M', /// Detail: an optional secondary error message carrying more detail about the problem. Might run to multiple lines. - D = 'D', + detail = 'D', /// Hint: an optional suggestion what to do about the problem. This is intended to differ from Detail in that it offers advice (potentially inappropriate) rather than hard facts. Might run to multiple lines. - H = 'H', + hint = 'H', /// Position: the field value is a decimal ASCII integer, indicating an error cursor position as an index into the original query string. The first character has index 1, and positions are measured in characters not bytes. - P = 'P', + position = 'P', /// Internal position: this is defined the same as the P field, but it is used when the cursor position refers to an internally generated command rather than the one submitted by the client. The q field will always appear when this field appears. - p = 'p', + internal_position = 'p', /// Internal query: the text of a failed internally-generated command. This could be, for example, an SQL query issued by a PL/pgSQL function. - q = 'q', + internal = 'q', /// Where: an indication of the context in which the error occurred. Presently this includes a call stack traceback of active procedural language functions and internally-generated queries. The trace is one entry per line, most recent first. - W = 'W', + where = 'W', /// Schema name: if the error was associated with a specific database object, the name of the schema containing that object, if any. - s = 's', + schema = 's', /// Table name: if the error was associated with a specific table, the name of the table. (Refer to the schema name field for the name of the table's schema.) - t = 't', + table = 't', /// Column name: if the error was associated with a specific table column, the name of the column. (Refer to the schema and table name fields to identify the table.) - c = 'c', + column = 'c', /// Data type name: if the error was associated with a specific data type, the name of the data type. (Refer to the schema name field for the name of the data type's schema.) - d = 'd', + datatype = 'd', /// Constraint name: if the error was associated with a specific constraint, the name of the constraint. Refer to fields listed above for the associated table or domain. (For this purpose, indexes are treated as constraints, even if they weren't created with constraint syntax.) - n = 'n', + constraint = 'n', /// File: the file name of the source-code location where the error was reported. - F = 'F', + file = 'F', /// Line: the line number of the source-code location where the error was reported. - L = 'L', + line = 'L', /// Routine: the name of the source-code routine reporting the error. - R = 'R', + routine = 'R', _, }; pub const FieldMessage = union(FieldType) { - S: String, - V: String, - C: String, - M: String, - D: String, - H: String, - P: String, - p: String, - q: String, - W: String, - s: String, - t: String, - c: String, - d: String, - n: String, - F: String, - L: String, - R: String, + severity: String, + localized_severity: String, + code: String, + message: String, + detail: String, + hint: String, + position: String, + internal_position: String, + internal: String, + where: String, + schema: String, + table: String, + column: String, + datatype: String, + constraint: String, + file: String, + line: String, + routine: String, pub fn format(this: FieldMessage, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { switch (this) { @@ -319,24 +319,25 @@ pub const FieldMessage = union(FieldType) { pub fn init(tag: FieldType, message: []const u8) !FieldMessage { return switch (tag) { - .S => FieldMessage{ .S = String.createUTF8(message) }, - .V => FieldMessage{ .V = String.createUTF8(message) }, - .C => FieldMessage{ .C = String.createUTF8(message) }, - .M => FieldMessage{ .M = String.createUTF8(message) }, - .D => FieldMessage{ .D = String.createUTF8(message) }, - .H => FieldMessage{ .H = String.createUTF8(message) }, - .P => FieldMessage{ .P = String.createUTF8(message) }, - .p => FieldMessage{ .p = String.createUTF8(message) }, - .q => FieldMessage{ .q = String.createUTF8(message) }, - .W => FieldMessage{ .W = String.createUTF8(message) }, - .s => FieldMessage{ .s = String.createUTF8(message) }, - .t => FieldMessage{ .t = String.createUTF8(message) }, - .c => FieldMessage{ .c = String.createUTF8(message) }, - .d => FieldMessage{ .d = String.createUTF8(message) }, - .n => FieldMessage{ .n = String.createUTF8(message) }, - .F => FieldMessage{ .F = String.createUTF8(message) }, - .L => FieldMessage{ .L = String.createUTF8(message) }, - .R => FieldMessage{ .R = String.createUTF8(message) }, + .severity => FieldMessage{ .severity = String.createUTF8(message) }, + // Ignore this one for now. + // .localized_severity => FieldMessage{ .localized_severity = String.createUTF8(message) }, + .code => FieldMessage{ .code = String.createUTF8(message) }, + .message => FieldMessage{ .message = String.createUTF8(message) }, + .detail => FieldMessage{ .detail = String.createUTF8(message) }, + .hint => FieldMessage{ .hint = String.createUTF8(message) }, + .position => FieldMessage{ .position = String.createUTF8(message) }, + .internal_position => FieldMessage{ .internal_position = String.createUTF8(message) }, + .internal => FieldMessage{ .internal = String.createUTF8(message) }, + .where => FieldMessage{ .where = String.createUTF8(message) }, + .schema => FieldMessage{ .schema = String.createUTF8(message) }, + .table => FieldMessage{ .table = String.createUTF8(message) }, + .column => FieldMessage{ .column = String.createUTF8(message) }, + .datatype => FieldMessage{ .datatype = String.createUTF8(message) }, + .constraint => FieldMessage{ .constraint = String.createUTF8(message) }, + .file => FieldMessage{ .file = String.createUTF8(message) }, + .line => FieldMessage{ .line = String.createUTF8(message) }, + .routine => FieldMessage{ .routine = String.createUTF8(message) }, else => error.UnknownFieldType, }; } @@ -348,8 +349,8 @@ pub fn NewReaderWrap( comptime peekFn_: (fn (ctx: Context) []const u8), comptime skipFn_: (fn (ctx: Context, count: usize) void), comptime ensureCapacityFn_: (fn (ctx: Context, count: usize) bool), - comptime readFunction_: (fn (ctx: Context, count: usize) anyerror!Data), - comptime readZ_: (fn (ctx: Context) anyerror!Data), + comptime readFunction_: (fn (ctx: Context, count: usize) AnyPostgresError!Data), + comptime readZ_: (fn (ctx: Context) AnyPostgresError!Data), ) type { return struct { wrapped: Context, @@ -366,11 +367,11 @@ pub fn NewReaderWrap( markMessageStartFn(this.wrapped); } - pub inline fn read(this: @This(), count: usize) anyerror!Data { + pub inline fn read(this: @This(), count: usize) AnyPostgresError!Data { return try readFn(this.wrapped, count); } - pub inline fn eatMessage(this: @This(), comptime msg_: anytype) anyerror!void { + pub inline fn eatMessage(this: @This(), comptime msg_: anytype) AnyPostgresError!void { const msg = msg_[1..]; try this.ensureCapacity(msg.len); @@ -380,7 +381,7 @@ pub fn NewReaderWrap( return error.InvalidMessage; } - pub fn skip(this: @This(), count: usize) anyerror!void { + pub fn skip(this: @This(), count: usize) AnyPostgresError!void { skipFn(this.wrapped, count); } @@ -388,11 +389,11 @@ pub fn NewReaderWrap( return peekFn(this.wrapped); } - pub inline fn readZ(this: @This()) anyerror!Data { + pub inline fn readZ(this: @This()) AnyPostgresError!Data { return try readZFn(this.wrapped); } - pub inline fn ensureCapacity(this: @This(), count: usize) anyerror!void { + pub inline fn ensureCapacity(this: @This(), count: usize) AnyPostgresError!void { if (!ensureCapacityFn(this.wrapped, count)) { return error.ShortRead; } @@ -457,7 +458,7 @@ pub fn NewWriter(comptime Context: type) type { fn decoderWrap(comptime Container: type, comptime decodeFn: anytype) type { return struct { - pub fn decode(this: *Container, context: anytype) anyerror!void { + pub fn decode(this: *Container, context: anytype) AnyPostgresError!void { const Context = @TypeOf(context); try decodeFn(this, Context, NewReader(Context){ .wrapped = context }); } @@ -466,7 +467,7 @@ fn decoderWrap(comptime Container: type, comptime decodeFn: anytype) type { fn writeWrap(comptime Container: type, comptime writeFn: anytype) type { return struct { - pub fn write(this: *Container, context: anytype) anyerror!void { + pub fn write(this: *Container, context: anytype) AnyPostgresError!void { const Context = @TypeOf(context); try writeFn(this, Context, NewWriter(Context){ .wrapped = context }); } @@ -538,9 +539,6 @@ pub const Authentication = union(enum) { }, 5 => { if (message_length != 12) return error.InvalidMessageLength; - if (!try reader.expectInt(u32, 5)) { - return error.InvalidMessage; - } var salt_data = try reader.bytes(4); defer salt_data.deinit(); this.* = .{ @@ -722,23 +720,117 @@ pub const ErrorResponse = struct { var b = bun.StringBuilder{}; defer b.deinit(bun.default_allocator); - for (this.messages.items) |msg| { - b.cap += switch (msg) { + // Pre-calculate capacity to avoid reallocations + for (this.messages.items) |*msg| { + b.cap += switch (msg.*) { inline else => |m| m.utf8ByteLength(), } + 1; } b.allocate(bun.default_allocator) catch {}; - for (this.messages.items) |msg| { - var str = switch (msg) { - inline else => |m| m.toUTF8(bun.default_allocator), - }; - defer str.deinit(); - _ = b.append(str.slice()); - _ = b.append("\n"); + // Build a more structured error message + var severity: String = String.dead; + var code: String = String.dead; + var message: String = String.dead; + var detail: String = String.dead; + var hint: String = String.dead; + var position: String = String.dead; + var where: String = String.dead; + var schema: String = String.dead; + var table: String = String.dead; + var column: String = String.dead; + var datatype: String = String.dead; + var constraint: String = String.dead; + var file: String = String.dead; + var line: String = String.dead; + var routine: String = String.dead; + + for (this.messages.items) |*msg| { + switch (msg.*) { + .severity => |str| severity = str, + .code => |str| code = str, + .message => |str| message = str, + .detail => |str| detail = str, + .hint => |str| hint = str, + .position => |str| position = str, + .where => |str| where = str, + .schema => |str| schema = str, + .table => |str| table = str, + .column => |str| column = str, + .datatype => |str| datatype = str, + .constraint => |str| constraint = str, + .file => |str| file = str, + .line => |str| line = str, + .routine => |str| routine = str, + else => {}, + } } - return globalObject.createSyntaxErrorInstance("Postgres error occurred\n{s}", .{b.allocatedSlice()[0..b.len]}); + var needs_newline = false; + construct_message: { + if (!message.isEmpty()) { + _ = b.appendStr(message); + needs_newline = true; + break :construct_message; + } + if (!detail.isEmpty()) { + if (needs_newline) { + _ = b.append("\n"); + } else { + _ = b.append(" "); + } + needs_newline = true; + _ = b.appendStr(detail); + } + if (!hint.isEmpty()) { + if (needs_newline) { + _ = b.append("\n"); + } else { + _ = b.append(" "); + } + needs_newline = true; + _ = b.appendStr(hint); + } + } + + const possible_fields = .{ + .{ "detail", detail, void }, + .{ "hint", hint, void }, + .{ "column", column, void }, + .{ "constraint", constraint, void }, + .{ "datatype", datatype, void }, + .{ "errno", code, i32 }, + .{ "position", position, i32 }, + .{ "schema", schema, void }, + .{ "table", table, void }, + .{ "where", where, void }, + }; + + const error_code: JSC.Error = + // https://www.postgresql.org/docs/8.1/errcodes-appendix.html + if (code.toInt32() orelse 0 == 42601) + JSC.Error.ERR_POSTGRES_SYNTAX_ERROR + else + JSC.Error.ERR_POSTGRES_SERVER_ERROR; + const err = error_code.fmt(globalObject, "{s}", .{b.allocatedSlice()[0..b.len]}); + + inline for (possible_fields) |field| { + if (!field.@"1".isEmpty()) { + const value = brk: { + if (field.@"2" == i32) { + if (field.@"1".toInt32()) |val| { + break :brk JSC.JSValue.jsNumberFromInt32(val); + } + } + + break :brk field.@"1".toJS(globalObject); + }; + + err.put(globalObject, JSC.ZigString.static(field.@"0"), value); + } + } + + return err; } }; @@ -847,7 +939,7 @@ pub const FormatCode = enum { pub const null_int4 = 4294967295; pub const DataRow = struct { - pub fn decode(context: anytype, comptime ContextType: type, reader: NewReader(ContextType), comptime forEach: fn (@TypeOf(context), index: u32, bytes: ?*Data) anyerror!bool) anyerror!void { + pub fn decode(context: anytype, comptime ContextType: type, reader: NewReader(ContextType), comptime forEach: fn (@TypeOf(context), index: u32, bytes: ?*Data) AnyPostgresError!bool) AnyPostgresError!void { var remaining_bytes = try reader.length(); remaining_bytes -|= 4; @@ -885,7 +977,7 @@ pub const FieldDescription = struct { this.name.deinit(); } - pub fn decodeInternal(this: *@This(), comptime Container: type, reader: NewReader(Container)) !void { + pub fn decodeInternal(this: *@This(), comptime Container: type, reader: NewReader(Container)) AnyPostgresError!void { var name = try reader.readZ(); errdefer { name.deinit(); @@ -1355,6 +1447,29 @@ pub const NoticeResponse = struct { } } pub const decode = decoderWrap(NoticeResponse, decodeInternal).decode; + + pub fn toJS(this: NoticeResponse, globalObject: *JSC.JSGlobalObject) JSValue { + var b = bun.StringBuilder{}; + defer b.deinit(bun.default_allocator); + + for (this.messages.items) |msg| { + b.cap += switch (msg) { + inline else => |m| m.utf8ByteLength(), + } + 1; + } + b.allocate(bun.default_allocator) catch {}; + + for (this.messages.items) |msg| { + var str = switch (msg) { + inline else => |m| m.toUTF8(bun.default_allocator), + }; + defer str.deinit(); + _ = b.append(str.slice()); + _ = b.append("\n"); + } + + return JSC.ZigString.init(b.allocatedSlice()[0..b.len]).toJS(globalObject); + } }; pub const CopyFail = struct { diff --git a/src/sql/postgres/postgres_types.zig b/src/sql/postgres/postgres_types.zig index 498b7f1d0a..74e8ff104b 100644 --- a/src/sql/postgres/postgres_types.zig +++ b/src/sql/postgres/postgres_types.zig @@ -12,6 +12,7 @@ const JSValue = JSC.JSValue; const JSC = bun.JSC; const short = postgres.short; const int4 = postgres.int4; +const AnyPostgresError = postgres.AnyPostgresError; // select b.typname, b.oid, b.typarray // from pg_catalog.pg_type a @@ -169,8 +170,17 @@ pub const Tag = enum(short) { bit_array = 1561, varbit_array = 1563, numeric_array = 1231, + jsonb = 3802, + jsonb_array = 3807, + // Not really sure what this is. + jsonpath = 4072, + jsonpath_array = 4073, _, + pub fn name(this: Tag) ?[]const u8 { + return std.enums.tagName(Tag, this); + } + pub fn isBinaryFormatSupported(this: Tag) bool { return switch (this) { // TODO: .int2_array, .float8_array, @@ -282,7 +292,7 @@ pub const Tag = enum(short) { globalObject: *JSC.JSGlobalObject, comptime Type: type, value: Type, - ) anyerror!JSValue { + ) AnyPostgresError!JSValue { switch (tag) { .numeric => { return numeric.toJS(globalObject, value); @@ -292,7 +302,7 @@ pub const Tag = enum(short) { return numeric.toJS(globalObject, value); }, - .json => { + .json, .jsonb => { return json.toJS(globalObject, value); }, @@ -326,7 +336,7 @@ pub const Tag = enum(short) { tag: Tag, globalObject: *JSC.JSGlobalObject, value: anytype, - ) anyerror!JSValue { + ) AnyPostgresError!JSValue { return toJSWithType(tag, globalObject, @TypeOf(value), value); } @@ -363,16 +373,16 @@ pub const Tag = enum(short) { // Ban these types: if (tag == .NumberObject) { - return error.JSError; + return globalObject.ERR_INVALID_ARG_TYPE("Number object is ambiguous and cannot be used as a PostgreSQL type", .{}).throw(); } if (tag == .BooleanObject) { - return error.JSError; + return globalObject.ERR_INVALID_ARG_TYPE("Boolean object is ambiguous and cannot be used as a PostgreSQL type", .{}).throw(); } // It's something internal if (!tag.isIndexable()) { - return error.JSError; + return globalObject.ERR_INVALID_ARG_TYPE("Unknown object is not a valid PostgreSQL type", .{}).throw(); } // We will JSON.stringify anything else. @@ -414,7 +424,7 @@ pub const string = struct { globalThis: *JSC.JSGlobalObject, comptime Type: type, value: Type, - ) anyerror!JSValue { + ) AnyPostgresError!JSValue { switch (comptime Type) { [:0]u8, []u8, []const u8, [:0]const u8 => { var str = String.fromUTF8(value); @@ -456,7 +466,7 @@ pub const numeric = struct { pub fn toJS( _: *JSC.JSGlobalObject, value: anytype, - ) anyerror!JSValue { + ) AnyPostgresError!JSValue { return JSValue.jsNumber(value); } }; @@ -468,12 +478,12 @@ pub const json = struct { pub fn toJS( globalObject: *JSC.JSGlobalObject, value: *Data, - ) anyerror!JSValue { + ) AnyPostgresError!JSValue { defer value.deinit(); var str = bun.String.fromUTF8(value.slice()); defer str.deref(); const parse_result = JSValue.parse(str.toJS(globalObject), globalObject); - if (parse_result.isAnyError()) { + if (parse_result.AnyPostgresError()) { return globalObject.throwValue(parse_result); } @@ -488,7 +498,7 @@ pub const @"bool" = struct { pub fn toJS( _: *JSC.JSGlobalObject, value: bool, - ) anyerror!JSValue { + ) AnyPostgresError!JSValue { return JSValue.jsBoolean(value); } }; @@ -548,7 +558,7 @@ pub const bytea = struct { pub fn toJS( globalObject: *JSC.JSGlobalObject, value: *Data, - ) anyerror!JSValue { + ) AnyPostgresError!JSValue { defer value.deinit(); // var slice = value.slice()[@min(1, value.len)..]; diff --git a/src/string.zig b/src/string.zig index 30bc054a53..4f874a9864 100644 --- a/src/string.zig +++ b/src/string.zig @@ -323,6 +323,12 @@ pub const String = extern struct { extern fn BunString__fromUTF16ToLatin1(bytes: [*]const u16, len: usize) String; extern fn BunString__fromLatin1Unitialized(len: usize) String; extern fn BunString__fromUTF16Unitialized(len: usize) String; + extern fn BunString__toInt32(this: String) i64; + pub fn toInt32(this: String) ?i32 { + const val = BunString__toInt32(this); + if (val > std.math.maxInt(i32)) return null; + return @intCast(val); + } pub fn ascii(bytes: []const u8) String { return String{ .tag = .ZigString, .value = .{ .ZigString = ZigString.init(bytes) } }; diff --git a/src/string_builder.zig b/src/string_builder.zig index e5e3d0bd47..0178663a4f 100644 --- a/src/string_builder.zig +++ b/src/string_builder.zig @@ -89,6 +89,12 @@ pub fn appendZ(this: *StringBuilder, slice: string) [:0]const u8 { return result; } +pub fn appendStr(this: *StringBuilder, str: bun.String) string { + const slice = str.toUTF8(bun.default_allocator); + defer slice.deinit(); + return this.append(slice.slice()); +} + pub fn append(this: *StringBuilder, slice: string) string { if (comptime Environment.allow_assert) { assert(this.len <= this.cap); // didn't count everything diff --git a/test/js/sql/sql.test.ts b/test/js/sql/sql.test.ts index 8c0089c760..92fd82931b 100644 --- a/test/js/sql/sql.test.ts +++ b/test/js/sql/sql.test.ts @@ -1,5 +1,5 @@ import { postgres, sql } from "bun:sql"; -import { expect, test } from "bun:test"; +import { expect, test, mock } from "bun:test"; import { $ } from "bun"; import { bunExe, isCI, withoutAggressiveGC } from "harness"; import path from "path"; @@ -13,18 +13,20 @@ if (!isCI) { // local all postgres trust // local all bun_sql_test_scram scram-sha-256 // local all bun_sql_test trust - // + // local all bun_sql_test_md5 md5 + // # IPv4 local connections: // host all ${USERNAME} 127.0.0.1/32 trust // host all postgres 127.0.0.1/32 trust // host all bun_sql_test_scram 127.0.0.1/32 scram-sha-256 // host all bun_sql_test 127.0.0.1/32 trust + // host all bun_sql_test_md5 127.0.0.1/32 md5 // # IPv6 local connections: // host all ${USERNAME} ::1/128 trust // host all postgres ::1/128 trust // host all bun_sql_test ::1/128 trust // host all bun_sql_test_scram ::1/128 scram-sha-256 - // + // host all bun_sql_test_md5 ::1/128 md5 // # Allow replication connections from localhost, by a user with the // # replication privilege. // local replication all trust @@ -33,9 +35,6 @@ if (!isCI) { // --- Expected pg_hba.conf --- process.env.DATABASE_URL = "postgres://bun_sql_test@localhost:5432/bun_sql_test"; - const delay = ms => Bun.sleep(ms); - const rel = x => new URL(x, import.meta.url); - const login = { username: "bun_sql_test", }; @@ -54,8 +53,8 @@ if (!isCI) { db: "bun_sql_test", username: login.username, password: login.password, - idle_timeout: 1, - connect_timeout: 1, + idle_timeout: 0, + connect_timeout: 0, max: 1, }; @@ -67,6 +66,97 @@ if (!isCI) { expect(result).toBe(1); }); + test("Connection timeout works", async () => { + const onclose = mock(); + const onconnect = mock(); + await using sql = postgres({ + ...options, + hostname: "unreachable_host", + connection_timeout: 1, + onconnect, + onclose, + }); + let error: any; + try { + await sql`select pg_sleep(2)`; + } catch (e) { + error = e; + } + expect(error.code).toBe(`ERR_POSTGRES_CONNECTION_TIMEOUT`); + expect(error.message).toContain("Connection timeout after 1ms"); + expect(onconnect).not.toHaveBeenCalled(); + expect(onclose).toHaveBeenCalledTimes(1); + }); + + test("Idle timeout works at start", async () => { + const onclose = mock(); + const onconnect = mock(); + await using sql = postgres({ + ...options, + idle_timeout: 1, + onconnect, + onclose, + }); + let error: any; + try { + await sql`select pg_sleep(2)`; + } catch (e) { + error = e; + } + expect(error.code).toBe(`ERR_POSTGRES_IDLE_TIMEOUT`); + expect(onconnect).toHaveBeenCalled(); + expect(onclose).toHaveBeenCalledTimes(1); + }); + + test("Idle timeout is reset when a query is run", async () => { + const onClosePromise = Promise.withResolvers(); + const onclose = mock(err => { + onClosePromise.resolve(err); + }); + const onconnect = mock(); + await using sql = postgres({ + ...options, + idle_timeout: 100, + onconnect, + onclose, + }); + expect(await sql`select 123 as x`).toEqual([{ x: 123 }]); + expect(onconnect).toHaveBeenCalledTimes(1); + expect(onclose).not.toHaveBeenCalled(); + const err = await onClosePromise.promise; + expect(err.code).toBe(`ERR_POSTGRES_IDLE_TIMEOUT`); + }); + + test("Max lifetime works", async () => { + const onClosePromise = Promise.withResolvers(); + const onclose = mock(err => { + onClosePromise.resolve(err); + }); + const onconnect = mock(); + const sql = postgres({ + ...options, + max_lifetime: 64, + onconnect, + onclose, + }); + let error: any; + expect(await sql`select 1 as x`).toEqual([{ x: 1 }]); + expect(onconnect).toHaveBeenCalledTimes(1); + try { + while (true) { + for (let i = 0; i < 100; i++) { + await sql`select pg_sleep(1)`; + } + } + } catch (e) { + error = e; + } + + expect(onclose).toHaveBeenCalledTimes(1); + + expect(error.code).toBe(`ERR_POSTGRES_LIFETIME_TIMEOUT`); + }); + test("Uses default database without slash", async () => { const sql = postgres("postgres://localhost"); expect(sql.options.username).toBe(sql.options.database); @@ -145,10 +235,9 @@ if (!isCI) { expect(x).toEqual({ a: "hello", b: 42 }); }); - // It's treating as a string. - test.todo("implicit jsonb", async () => { + test("implicit jsonb", async () => { const x = (await sql`select ${{ a: "hello", b: 42 }}::jsonb as x`)[0].x; - expect([x.a, x.b].join(",")).toBe("hello,42"); + expect(x).toEqual({ a: "hello", b: 42 }); }); test("bulk insert nested sql()", async () => { @@ -428,9 +517,11 @@ if (!isCI) { test("Null sets to null", async () => expect((await sql`select ${null} as x`)[0].x).toBeNull()); // Add code property. - test.todo("Throw syntax error", async () => { - const code = await sql`wat 1`.catch(x => x); - console.log({ code }); + test("Throw syntax error", async () => { + const err = await sql`wat 1`.catch(x => x); + expect(err.code).toBe("ERR_POSTGRES_SYNTAX_ERROR"); + expect(err.errno).toBe(42601); + expect(err).toBeInstanceOf(SyntaxError); }); // t('Connect using uri', async() => @@ -502,13 +593,26 @@ if (!isCI) { // return [1, (await sql`select 1 as x`)[0].x] // }) - // t('Login without password', async() => { - // return [true, (await postgres({ ...options, ...login })`select true as x`)[0].x] - // }) + test("Login without password", async () => { + await using sql = postgres({ ...options, ...login }); + expect((await sql`select true as x`)[0].x).toBe(true); + }); - // t('Login using MD5', async() => { - // return [true, (await postgres({ ...options, ...login_md5 })`select true as x`)[0].x] - // }) + test("Login using MD5", async () => { + await using sql = postgres({ ...options, ...login_md5 }); + expect(await sql`select true as x`).toEqual([{ x: true }]); + }); + + test("Login with bad credentials propagates error from server", async () => { + const sql = postgres({ ...options, ...login_md5, username: "bad_user", password: "bad_password" }); + let err; + try { + await sql`select true as x`; + } catch (e) { + err = e; + } + expect(err.code).toBe("ERR_POSTGRES_SERVER_ERROR"); + }); test("Login using scram-sha-256", async () => { await using sql = postgres({ ...options, ...login_scram }); @@ -1159,9 +1263,10 @@ if (!isCI) { // ] // }) - // t('dynamic column name', async() => { - // return ['!not_valid', Object.keys((await sql`select 1 as ${ sql('!not_valid') }`)[0])[0]] - // }) + test.todo("dynamic column name", async () => { + const result = await sql`select 1 as ${"\\!not_valid"}`; + expect(Object.keys(result[0])[0]).toBe("!not_valid"); + }); // t('dynamic select as', async() => { // return ['2', (await sql`select ${ sql({ a: 1, b: 2 }) }`)[0].b] @@ -1178,12 +1283,12 @@ if (!isCI) { // return ['the answer', (await sql`insert into test ${ sql(x) } returning *`)[0].b, await sql`drop table test`] // }) - // t('dynamic insert pluck', async() => { - // await sql`create table test (a int, b text)` - // const x = { a: 42, b: 'the answer' } - - // return [null, (await sql`insert into test ${ sql(x, 'a') } returning *`)[0].b, await sql`drop table test`] - // }) + // test.todo("dynamic insert pluck", async () => { + // await sql`create table test (a int, b text)`; + // const x = { a: 42, b: "the answer" }; + // const [{ b }] = await sql`insert into test ${sql(x, "a")} returning *`; + // expect(b).toBe("the answer"); + // }); // t('dynamic in with empty array', async() => { // await sql`create table test (a int)` From e96dded366e4520e46bdddadba2acb960af86a0a Mon Sep 17 00:00:00 2001 From: Lars Volkheimer <40475367+laesse@users.noreply.github.com> Date: Mon, 30 Dec 2024 22:44:40 +0100 Subject: [PATCH 109/125] fix formatting of Set in Bun.inspect() (#16013) --- src/bun.js/ConsoleObject.zig | 6 +----- test/regression/issue/16007.test.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 test/regression/issue/16007.test.ts diff --git a/src/bun.js/ConsoleObject.zig b/src/bun.js/ConsoleObject.zig index 33ebd2fa14..9def500ece 100644 --- a/src/bun.js/ConsoleObject.zig +++ b/src/bun.js/ConsoleObject.zig @@ -2728,10 +2728,6 @@ pub const Formatter = struct { this.quote_strings = true; defer this.quote_strings = prev_quote_strings; - if (!this.single_line) { - this.writeIndent(Writer, writer_) catch {}; - } - const set_name = if (value.jsType() == .WeakSet) "WeakSet" else "Set"; if (length == 0) { @@ -2762,7 +2758,7 @@ pub const Formatter = struct { }, } } - if (this.single_line) { + if (!this.single_line) { this.writeIndent(Writer, writer_) catch {}; } writer.writeAll("}"); diff --git a/test/regression/issue/16007.test.ts b/test/regression/issue/16007.test.ts new file mode 100644 index 0000000000..fa09d4fedc --- /dev/null +++ b/test/regression/issue/16007.test.ts @@ -0,0 +1,12 @@ +import { it, expect } from "bun:test"; + +it("Set is propperly formatted in Bun.inspect()", () => { + const set = new Set(["foo", "bar"]); + const formatted = Bun.inspect({ set }); + expect(formatted).toBe(`{ + set: Set(2) { + "foo", + "bar", + }, +}`); +}); From ab52058439d080fa6f9541889fe2996065cb1208 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Tue, 31 Dec 2024 01:20:15 -0500 Subject: [PATCH 110/125] fix(us): memory leak when getting root certificate (#16073) --- packages/bun-usockets/src/crypto/root_certs.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/bun-usockets/src/crypto/root_certs.cpp b/packages/bun-usockets/src/crypto/root_certs.cpp index f675a0ab16..0e8c8541d9 100644 --- a/packages/bun-usockets/src/crypto/root_certs.cpp +++ b/packages/bun-usockets/src/crypto/root_certs.cpp @@ -35,6 +35,9 @@ us_ssl_ctx_get_X509_without_callback_from(struct us_cert_string_t content) { OPENSSL_PUT_ERROR(SSL, ERR_R_PEM_LIB); goto end; } + + // NOTE: PEM_read_bio_X509 allocates, so input BIO must be freed. + BIO_free(in); return x; end: X509_free(x); @@ -140,4 +143,4 @@ extern "C" X509_STORE *us_get_default_ca_store() { } return store; -} \ No newline at end of file +} From babd8b60286f28631f1ca06a65c1abdd486b64aa Mon Sep 17 00:00:00 2001 From: Navishkar Rao Date: Tue, 31 Dec 2024 17:26:19 +1100 Subject: [PATCH 111/125] Update nextjs.md docs with starter example (#16072) --- docs/guides/ecosystem/nextjs.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/guides/ecosystem/nextjs.md b/docs/guides/ecosystem/nextjs.md index c3147d703b..1183b430e0 100644 --- a/docs/guides/ecosystem/nextjs.md +++ b/docs/guides/ecosystem/nextjs.md @@ -15,6 +15,14 @@ $ bun create next-app Creating a new Next.js app in /path/to/my-app. ``` +You can specify a starter template using the `--example` flag. + +```sh +$ bun create next-app --example with-supabase +✔ What is your project named? … my-app +... +``` + --- To start the dev server with Bun, run `bun --bun run dev` from the project root. From 37e7f5ba8ff38e7ae93a333130881a5bfb6e6d43 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Tue, 31 Dec 2024 12:09:09 -0500 Subject: [PATCH 112/125] transpiler: fix crash with malformed enums (#16084) --- src/js_parser.zig | 2 ++ test/bundler/transpiler/transpiler.test.js | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/js_parser.zig b/src/js_parser.zig index db61971b20..9d3803f751 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -11917,6 +11917,8 @@ fn NewParser_( needs_symbol = true; } else { try p.lexer.expect(.t_identifier); + // error early, name is still `undefined` + return error.SyntaxError; } try p.lexer.next(); diff --git a/test/bundler/transpiler/transpiler.test.js b/test/bundler/transpiler/transpiler.test.js index 0b0103848f..0a49f8723f 100644 --- a/test/bundler/transpiler/transpiler.test.js +++ b/test/bundler/transpiler/transpiler.test.js @@ -315,6 +315,13 @@ describe("Bun.Transpiler", () => { exp("f<{}>()\nfunction f() {}", "let f = function() {\n};\nf()"); }); + it("malformed enums", () => { + const err = ts.expectParseError; + + err("enum Foo { [2]: 'hi' }", 'Expected identifier but found "["'); + err("enum [] { a }", 'Expected identifier but found "["'); + }); + // TODO: fix all the cases that report generic "Parse error" it("types", () => { const exp = ts.expectPrinted_; From 82f9b13e082e483e696380b37d858910034cec13 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Tue, 31 Dec 2024 11:40:28 -0800 Subject: [PATCH 113/125] docs: fix `bun.lock` section (#16088) --- docs/install/lockfile.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install/lockfile.md b/docs/install/lockfile.md index 315b90f48d..01df57fe0f 100644 --- a/docs/install/lockfile.md +++ b/docs/install/lockfile.md @@ -72,6 +72,8 @@ $ bun install --yarn print = "yarn" ``` +{% /codetabs %} + ### Text-based lockfile Bun v1.1.39 introduced `bun.lock`, a JSONC formatted lockfile. `bun.lock` is human-readable and git-diffable without configuration, at [no cost to performance](https://bun.sh/blog/bun-lock-text-lockfile#cached-bun-install-gets-30-faster). @@ -90,8 +92,6 @@ Once `bun.lock` is generated, Bun will use it for all subsequent installs and up Bun v1.2.0 will switch the default lockfile format to `bun.lock`. -{% /codetabs %} - {% details summary="Configuring lockfile" %} ```toml From b406509afd4f5960ff9107b16a00876203a0252b Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Tue, 31 Dec 2024 16:31:33 -0500 Subject: [PATCH 114/125] refactor: remove unused script execution context file (#16059) --- src/bun.js/script_execution_context.zig | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 src/bun.js/script_execution_context.zig diff --git a/src/bun.js/script_execution_context.zig b/src/bun.js/script_execution_context.zig deleted file mode 100644 index 3753952363..0000000000 --- a/src/bun.js/script_execution_context.zig +++ /dev/null @@ -1,7 +0,0 @@ -const JSC = bun.JSC; - -pub const ScriptExecutionContext = extern struct { - main_file_path: JSC.ZigString, - is_macro: bool = false, - js_global_object: bool = false, -}; From 5058bd391364d110a4a2f05884c7371c4f8e2f23 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Tue, 31 Dec 2024 13:40:55 -0800 Subject: [PATCH 115/125] handle `bundle(d)Dependencies` in `bun install` (#16055) --- .lldbinit | 2 +- src/bun.zig | 8 + src/cli/outdated_command.zig | 10 +- src/cli/pack_command.zig | 4 +- src/install/bun.lock.zig | 119 +- src/install/dependency.zig | 105 +- src/install/install.zig | 97 +- src/install/lockfile.zig | 157 +- src/install/migration.zig | 8 +- src/install/npm.zig | 88 +- src/install/resolvers/folder_resolver.zig | 82 +- src/install/semver.zig | 34 - src/resolver/resolver.zig | 2 +- .../__snapshots__/bun-workspaces.test.ts.snap | 30 +- .../registry/bun-install-registry.test.ts | 308 ++ .../packages/bundled-1/bundled-1-1.0.0.tgz | Bin 0 -> 375 bytes .../registry/packages/bundled-1/package.json | 47 + .../bundled-transitive-1.0.0.tgz | Bin 0 -> 388 bytes .../packages/bundled-transitive/package.json | 48 + .../bundled-true/bundled-true-1.0.0.tgz | Bin 0 -> 451 bytes .../packages/bundled-true/package.json | 43 + .../dev-server-ssr-100.test.ts.snap | 1672 ++++----- .../__snapshots__/dev-server.test.ts.snap | 1672 ++++----- .../__snapshots__/next-build.test.ts.snap | 3344 ++++++++--------- 24 files changed, 4232 insertions(+), 3648 deletions(-) create mode 100644 test/cli/install/registry/packages/bundled-1/bundled-1-1.0.0.tgz create mode 100644 test/cli/install/registry/packages/bundled-1/package.json create mode 100644 test/cli/install/registry/packages/bundled-transitive/bundled-transitive-1.0.0.tgz create mode 100644 test/cli/install/registry/packages/bundled-transitive/package.json create mode 100644 test/cli/install/registry/packages/bundled-true/bundled-true-1.0.0.tgz create mode 100644 test/cli/install/registry/packages/bundled-true/package.json diff --git a/.lldbinit b/.lldbinit index b54a4195c3..a2357365bb 100644 --- a/.lldbinit +++ b/.lldbinit @@ -1,4 +1,4 @@ -command script import vendor/zig/tools/lldb_pretty_printers.py +# command script import vendor/zig/tools/lldb_pretty_printers.py command script import vendor/WebKit/Tools/lldb/lldb_webkit.py # type summary add --summary-string "${var} | inner=${var[0-30]}, source=${var[33-64]}, tag=${var[31-32]}" "unsigned long" diff --git a/src/bun.zig b/src/bun.zig index b96006c618..77d75c1f0d 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -1871,6 +1871,14 @@ pub const StringSet = struct { } } + pub fn contains(self: *StringSet, key: []const u8) bool { + return self.map.contains(key); + } + + pub fn swapRemove(self: *StringSet, key: []const u8) bool { + return self.map.swapRemove(key); + } + pub fn deinit(self: *StringSet) void { for (self.map.keys()) |key| { self.map.allocator.free(key); diff --git a/src/cli/outdated_command.zig b/src/cli/outdated_command.zig index 447f309bea..caa67f7b38 100644 --- a/src/cli/outdated_command.zig +++ b/src/cli/outdated_command.zig @@ -453,10 +453,10 @@ pub const OutdatedCommand = struct { for (workspace_pkg_ids) |workspace_pkg_id| { inline for ( .{ - Behavior{ .normal = true }, - Behavior{ .dev = true }, - Behavior{ .peer = true }, - Behavior{ .optional = true }, + Behavior.prod, + Behavior.dev, + Behavior.peer, + Behavior.optional, }, ) |group_behavior| { for (outdated_ids.items) |ids| { @@ -465,7 +465,7 @@ pub const OutdatedCommand = struct { const dep_id = ids.dep_id; const dep = dependencies[dep_id]; - if (@as(u8, @bitCast(group_behavior)) & @as(u8, @bitCast(dep.behavior)) == 0) continue; + if (!dep.behavior.includes(group_behavior)) continue; const package_name = pkg_names[package_id].slice(string_buf); const resolution = pkg_resolutions[package_id]; diff --git a/src/cli/pack_command.zig b/src/cli/pack_command.zig index 763ecead80..8918c21233 100644 --- a/src/cli/pack_command.zig +++ b/src/cli/pack_command.zig @@ -510,8 +510,8 @@ pub const PackCommand = struct { const dir = root_dir.openDirZ("node_modules", .{ .iterate = true }) catch |err| { switch (err) { - // ignore node_modules if it isn't a directory - error.NotDir => return bundled_pack_queue, + // ignore node_modules if it isn't a directory, or doesn't exist + error.NotDir, error.FileNotFound => return bundled_pack_queue, else => { Output.err(err, "failed to open \"node_modules\" to pack bundled dependencies", .{}); diff --git a/src/install/bun.lock.zig b/src/install/bun.lock.zig index 6a212b46f4..a865e21978 100644 --- a/src/install/bun.lock.zig +++ b/src/install/bun.lock.zig @@ -624,7 +624,7 @@ pub const Stringifier = struct { res.value.folder.fmtJson(buf, .{ .quote = false }), }); - try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); + try writePackageInfoObject(writer, dep.behavior, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, @@ -634,7 +634,7 @@ pub const Stringifier = struct { res.value.local_tarball.fmtJson(buf, .{ .quote = false }), }); - try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); + try writePackageInfoObject(writer, dep.behavior, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, @@ -644,7 +644,7 @@ pub const Stringifier = struct { res.value.remote_tarball.fmtJson(buf, .{ .quote = false }), }); - try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); + try writePackageInfoObject(writer, dep.behavior, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, @@ -654,7 +654,7 @@ pub const Stringifier = struct { res.value.symlink.fmtJson(buf, .{ .quote = false }), }); - try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); + try writePackageInfoObject(writer, dep.behavior, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, @@ -672,7 +672,7 @@ pub const Stringifier = struct { res.value.npm.url.slice(buf), }); - try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); + try writePackageInfoObject(writer, dep.behavior, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.print(", \"{}\"]", .{ pkg_meta.integrity, @@ -684,7 +684,7 @@ pub const Stringifier = struct { res.value.workspace.fmtJson(buf, .{ .quote = false }), }); - try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); + try writePackageInfoObject(writer, dep.behavior, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.writeByte(']'); }, @@ -695,7 +695,7 @@ pub const Stringifier = struct { repo.fmt(if (comptime tag == .git) "git+" else "github:", buf), }); - try writePackageInfoObject(writer, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); + try writePackageInfoObject(writer, dep.behavior, deps_buf, pkg_deps_sort_buf.items, &pkg_meta, &pkg_bin, buf, &optional_peers_buf, lockfile.buffers.extern_strings.items); try writer.print(", {}]", .{ repo.resolved.fmtJson(buf, .{}), @@ -720,6 +720,7 @@ pub const Stringifier = struct { /// { "devDependencies": { "one": "1.1.1", "two": "2.2.2" }, "os": "none" } fn writePackageInfoObject( writer: anytype, + dep_behavior: Dependency.Behavior, deps_buf: []const Dependency, pkg_dep_ids: []const DependencyID, meta: *const Meta, @@ -789,6 +790,18 @@ pub const Stringifier = struct { try writer.writeByte(']'); } + if (dep_behavior.isBundled()) { + if (any) { + try writer.writeByte(','); + } else { + any = true; + } + + try writer.writeAll( + \\ "bundled": true + ); + } + // TODO(dylan-conway) // if (meta.libc != .all) { // try writer.writeAll( @@ -977,7 +990,7 @@ pub const Stringifier = struct { }; const workspace_dependency_groups = [4]struct { []const u8, Dependency.Behavior }{ - .{ "dependencies", Dependency.Behavior.normal }, + .{ "dependencies", Dependency.Behavior.prod }, .{ "devDependencies", Dependency.Behavior.dev }, .{ "optionalDependencies", Dependency.Behavior.optional }, .{ "peerDependencies", Dependency.Behavior.peer }, @@ -1242,14 +1255,15 @@ pub fn parseIntoBinaryLockfile( const name = value.get("name").?.asString(allocator).?; const name_hash = String.Builder.stringHash(name); - var dep: Dependency = .{}; - dep.name = try string_buf.appendWithHash(name, name_hash); - dep.name_hash = name_hash; - dep.behavior = Dependency.Behavior.workspace; - dep.version = .{ - .tag = .workspace, - .value = .{ - .workspace = try string_buf.append(path), + const dep: Dependency = .{ + .name = try string_buf.appendWithHash(name, name_hash), + .name_hash = name_hash, + .behavior = Dependency.Behavior.workspace, + .version = .{ + .tag = .workspace, + .value = .{ + .workspace = try string_buf.append(path), + }, }, }; @@ -1267,7 +1281,11 @@ pub fn parseIntoBinaryLockfile( try lockfile.getOrPutID(0, root_pkg.name_hash); } - var pkg_map = bun.StringArrayHashMap(PackageID).init(allocator); + const PkgMapEntry = struct { + pkg_id: PackageID, + bundled: bool, + }; + var pkg_map = bun.StringArrayHashMap(PkgMapEntry).init(allocator); defer pkg_map.deinit(); if (root.get("packages")) |pkgs_expr| { @@ -1355,6 +1373,8 @@ pub fn parseIntoBinaryLockfile( var pkg: BinaryLockfile.Package = .{}; + var bundled = false; + // dependencies, os, cpu, libc switch (res.tag) { .npm, .folder, .git, .github, .local_tarball, .remote_tarball, .symlink, .workspace => { @@ -1363,29 +1383,38 @@ pub fn parseIntoBinaryLockfile( return error.InvalidPackageInfo; } - const deps_os_cpu_libc_bin_obj = pkg_info.at(i); + const deps_os_cpu_libc_bin_bundle_obj = pkg_info.at(i); i += 1; - if (!deps_os_cpu_libc_bin_obj.isObject()) { - try log.addError(source, deps_os_cpu_libc_bin_obj.loc, "Expected an object"); + if (!deps_os_cpu_libc_bin_bundle_obj.isObject()) { + try log.addError(source, deps_os_cpu_libc_bin_bundle_obj.loc, "Expected an object"); return error.InvalidPackageInfo; } - const off, const len = try parseAppendDependencies(lockfile, allocator, deps_os_cpu_libc_bin_obj, &string_buf, log, source, &optional_peers_buf); + if (deps_os_cpu_libc_bin_bundle_obj.get("bundled")) |bundled_expr| { + if (!bundled_expr.isBoolean()) { + try log.addError(source, bundled_expr.loc, "Expected a boolean"); + return error.InvalidPackageInfo; + } + + bundled = bundled_expr.data.e_boolean.value; + } + + const off, const len = try parseAppendDependencies(lockfile, allocator, deps_os_cpu_libc_bin_bundle_obj, &string_buf, log, source, &optional_peers_buf); pkg.dependencies = .{ .off = off, .len = len }; pkg.resolutions = .{ .off = off, .len = len }; - if (deps_os_cpu_libc_bin_obj.get("bin")) |bin| { + if (deps_os_cpu_libc_bin_bundle_obj.get("bin")) |bin| { pkg.bin = try Bin.parseAppend(allocator, bin, &string_buf, &lockfile.buffers.extern_strings); - } else if (deps_os_cpu_libc_bin_obj.get("binDir")) |bin_dir| { + } else if (deps_os_cpu_libc_bin_bundle_obj.get("binDir")) |bin_dir| { pkg.bin = try Bin.parseAppendFromDirectories(allocator, bin_dir, &string_buf); } if (res.tag != .workspace) { - if (deps_os_cpu_libc_bin_obj.get("os")) |os| { + if (deps_os_cpu_libc_bin_bundle_obj.get("os")) |os| { pkg.meta.os = try Negatable(Npm.OperatingSystem).fromJson(allocator, os); } - if (deps_os_cpu_libc_bin_obj.get("cpu")) |arch| { + if (deps_os_cpu_libc_bin_bundle_obj.get("cpu")) |arch| { pkg.meta.arch = try Negatable(Npm.Architecture).fromJson(allocator, arch); } // TODO(dylan-conway) @@ -1464,7 +1493,10 @@ pub fn parseIntoBinaryLockfile( return error.InvalidPackageKey; } - entry.value_ptr.* = pkg_id; + entry.value_ptr.* = .{ + .pkg_id = pkg_id, + .bundled = bundled, + }; } try lockfile.buffers.resolutions.ensureTotalCapacityPrecise(allocator, lockfile.buffers.dependencies.items.len); @@ -1485,7 +1517,7 @@ pub fn parseIntoBinaryLockfile( const dep_id: DependencyID = @intCast(_dep_id); const dep = lockfile.buffers.dependencies.items[dep_id]; - const res_pkg_id = pkg_map.get(dep.name.slice(lockfile.buffers.string_bytes.items)) orelse { + const entry = pkg_map.get(dep.name.slice(lockfile.buffers.string_bytes.items)) orelse { if (dep.behavior.optional) { continue; } @@ -1493,7 +1525,8 @@ pub fn parseIntoBinaryLockfile( return error.InvalidPackageInfo; }; - lockfile.buffers.resolutions.items[dep_id] = res_pkg_id; + lockfile.buffers.resolutions.items[dep_id] = entry.pkg_id; + lockfile.buffers.dependencies.items[dep_id].behavior.bundled = entry.bundled; } // TODO(dylan-conway) should we handle workspaces separately here for custom hoisting @@ -1508,14 +1541,14 @@ pub fn parseIntoBinaryLockfile( const pkg_path = key.asString(allocator).?; - const pkg_id = pkg_map.get(pkg_path) orelse { + const pkg_id = (pkg_map.get(pkg_path) orelse { return error.InvalidPackagesObject; - }; + }).pkg_id; // find resolutions. iterate up to root through the pkg path. deps: for (pkg_deps[pkg_id].begin()..pkg_deps[pkg_id].end()) |_dep_id| { const dep_id: DependencyID = @intCast(_dep_id); - const dep = lockfile.buffers.dependencies.items[dep_id]; + var dep = &lockfile.buffers.dependencies.items[dep_id]; const dep_name = dep.name.slice(lockfile.buffers.string_bytes.items); @memcpy(path_buf[0..pkg_path.len], pkg_path); @@ -1527,8 +1560,9 @@ pub fn parseIntoBinaryLockfile( @memcpy(path_buf[offset..][0..dep_name.len], dep_name); const res_path = path_buf[0 .. offset + dep_name.len]; - if (pkg_map.get(res_path)) |res_pkg_id| { - lockfile.buffers.resolutions.items[dep_id] = res_pkg_id; + if (pkg_map.get(res_path)) |entry| { + lockfile.buffers.resolutions.items[dep_id] = entry.pkg_id; + dep.behavior.bundled = entry.bundled; continue :deps; } @@ -1536,7 +1570,7 @@ pub fn parseIntoBinaryLockfile( if (dep.behavior.optional) { continue :deps; } - try dependencyResolutionFailure(&dep, pkg_path, allocator, lockfile.buffers.string_bytes.items, source, log, key.loc); + try dependencyResolutionFailure(dep, pkg_path, allocator, lockfile.buffers.string_bytes.items, source, log, key.loc); return error.InvalidPackageInfo; } @@ -1600,11 +1634,11 @@ pub fn parseIntoBinaryLockfile( } fn dependencyResolutionFailure(dep: *const Dependency, pkg_path: ?string, allocator: std.mem.Allocator, buf: string, source: *const logger.Source, log: *logger.Log, loc: logger.Loc) OOM!void { - const behavior_str = if (dep.behavior.isDev()) + const behavior_str = if (dep.behavior.dev) "dev" - else if (dep.behavior.isOptional()) + else if (dep.behavior.optional) "optional" - else if (dep.behavior.isPeer()) + else if (dep.behavior.peer) "peer" else if (dep.behavior.isWorkspaceOnly()) "workspace" @@ -1681,10 +1715,13 @@ fn parseAppendDependencies( const version = try buf.append(version_str); const version_sliced = version.sliced(buf.bytes.items); - var dep: Dependency = .{ + const dep: Dependency = .{ .name = name.value, .name_hash = name.hash, - .behavior = group_behavior, + .behavior = if (group_behavior.peer and optional_peers_buf.contains(name.hash)) + group_behavior.add(.optional) + else + group_behavior, .version = Dependency.parse( allocator, name.value, @@ -1699,10 +1736,6 @@ fn parseAppendDependencies( }, }; - if (dep.behavior.isPeer() and optional_peers_buf.contains(name.hash)) { - dep.behavior.optional = true; - } - try lockfile.buffers.dependencies.append(allocator, dep); } } diff --git a/src/install/dependency.zig b/src/install/dependency.zig index faeb476d2d..4ded9d5682 100644 --- a/src/install/dependency.zig +++ b/src/install/dependency.zig @@ -51,7 +51,7 @@ version: Dependency.Version = .{}, /// - `peerDependencies` /// Technically, having the same package name specified under multiple fields is invalid /// But we don't want to allocate extra arrays for them. So we use a bitfield instead. -behavior: Behavior = Behavior.uninitialized, +behavior: Behavior = .{}, /// Sorting order for dependencies is: /// 1. [ `peerDependencies`, `optionalDependencies`, `devDependencies`, `dependencies` ] @@ -1301,36 +1301,32 @@ pub fn fromJS(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JS } pub const Behavior = packed struct(u8) { - pub const uninitialized: Behavior = .{}; - - // these padding fields are to have compatibility - // with older versions of lockfile v2 _unused_1: u1 = 0, - - normal: bool = false, + prod: bool = false, optional: bool = false, dev: bool = false, peer: bool = false, workspace: bool = false, + /// Is not set for transitive bundled dependencies + bundled: bool = false, + _unused_2: u1 = 0, - _unused_2: u2 = 0, - - pub const normal = Behavior{ .normal = true }; + pub const prod = Behavior{ .prod = true }; pub const optional = Behavior{ .optional = true }; pub const dev = Behavior{ .dev = true }; pub const peer = Behavior{ .peer = true }; pub const workspace = Behavior{ .workspace = true }; - pub inline fn isNormal(this: Behavior) bool { - return this.normal; + pub inline fn isProd(this: Behavior) bool { + return this.prod; } pub inline fn isOptional(this: Behavior) bool { - return this.optional and !this.isPeer(); + return this.optional and !this.peer; } pub inline fn isOptionalPeer(this: Behavior) bool { - return this.optional and this.isPeer(); + return this.optional and this.peer; } pub inline fn isDev(this: Behavior) bool { @@ -1345,38 +1341,12 @@ pub const Behavior = packed struct(u8) { return this.workspace; } + pub inline fn isBundled(this: Behavior) bool { + return this.bundled; + } + pub inline fn isWorkspaceOnly(this: Behavior) bool { - return this.workspace and !this.dev and !this.normal and !this.optional and !this.peer; - } - - pub inline fn setNormal(this: Behavior, value: bool) Behavior { - var b = this; - b.normal = value; - return b; - } - - pub inline fn setOptional(this: Behavior, value: bool) Behavior { - var b = this; - b.optional = value; - return b; - } - - pub inline fn setDev(this: Behavior, value: bool) Behavior { - var b = this; - b.dev = value; - return b; - } - - pub inline fn setPeer(this: Behavior, value: bool) Behavior { - var b = this; - b.peer = value; - return b; - } - - pub inline fn setWorkspace(this: Behavior, value: bool) Behavior { - var b = this; - b.workspace = value; - return b; + return this.workspace and !this.dev and !this.prod and !this.optional and !this.peer; } pub inline fn eq(lhs: Behavior, rhs: Behavior) bool { @@ -1387,13 +1357,25 @@ pub const Behavior = packed struct(u8) { return @as(u8, @bitCast(lhs)) & @as(u8, @bitCast(rhs)) != 0; } + pub inline fn add(this: Behavior, kind: @Type(.EnumLiteral)) Behavior { + var new = this; + @field(new, @tagName(kind)) = true; + return new; + } + + pub inline fn set(this: Behavior, kind: @Type(.EnumLiteral), value: bool) Behavior { + var new = this; + @field(new, @tagName(kind)) = value; + return new; + } + pub inline fn cmp(lhs: Behavior, rhs: Behavior) std.math.Order { if (eq(lhs, rhs)) { return .eq; } - if (lhs.isNormal() != rhs.isNormal()) { - return if (lhs.isNormal()) + if (lhs.isProd() != rhs.isProd()) { + return if (lhs.isProd()) .gt else .lt; @@ -1435,40 +1417,15 @@ pub const Behavior = packed struct(u8) { } pub fn isEnabled(this: Behavior, features: Features) bool { - return this.isNormal() or + return this.isProd() or (features.optional_dependencies and this.isOptional()) or (features.dev_dependencies and this.isDev()) or (features.peer_dependencies and this.isPeer()) or (features.workspaces and this.isWorkspaceOnly()); } - pub fn format(self: Behavior, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { - const fields = .{ - "normal", - "optional", - "dev", - "peer", - "workspace", - }; - - var first = true; - inline for (fields) |field| { - if (@field(self, field)) { - if (!first) { - try writer.writeAll(" | "); - } - try writer.writeAll(field); - first = false; - } - } - - if (first) { - try writer.writeAll("-"); - } - } - comptime { - bun.assert(@as(u8, @bitCast(Behavior.normal)) == (1 << 1)); + bun.assert(@as(u8, @bitCast(Behavior.prod)) == (1 << 1)); bun.assert(@as(u8, @bitCast(Behavior.optional)) == (1 << 2)); bun.assert(@as(u8, @bitCast(Behavior.dev)) == (1 << 3)); bun.assert(@as(u8, @bitCast(Behavior.peer)) == (1 << 4)); diff --git a/src/install/install.zig b/src/install/install.zig index d64fc72cfb..495c63ee0a 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -155,12 +155,7 @@ const Behavior = @import("./dependency.zig").Behavior; const FolderResolution = @import("./resolvers/folder_resolver.zig").FolderResolution; pub fn ExternalSlice(comptime Type: type) type { - return ExternalSliceAligned(Type, null); -} - -pub fn ExternalSliceAligned(comptime Type: type, comptime alignment_: ?u29) type { return extern struct { - pub const alignment = alignment_ orelse @alignOf(*Type); pub const Slice = @This(); pub const Child: type = Type; @@ -168,6 +163,12 @@ pub fn ExternalSliceAligned(comptime Type: type, comptime alignment_: ?u29) type off: u32 = 0, len: u32 = 0, + pub const invalid: @This() = .{ .off = std.math.maxInt(u32), .len = std.math.maxInt(u32) }; + + pub inline fn isInvalid(this: Slice) bool { + return this.off == std.math.maxInt(u32) and this.len == std.math.maxInt(u32); + } + pub inline fn contains(this: Slice, id: u32) bool { return id >= this.off and id < (this.len + this.off); } @@ -211,10 +212,20 @@ pub fn ExternalSliceAligned(comptime Type: type, comptime alignment_: ?u29) type pub const PackageID = u32; pub const DependencyID = u32; + +// pub const DependencyID = enum(u32) { +// root = max - 1, +// invalid = max, +// _, + +// const max = std.math.maxInt(u32); +// }; + pub const invalid_package_id = std.math.maxInt(PackageID); pub const invalid_dependency_id = std.math.maxInt(DependencyID); pub const ExternalStringList = ExternalSlice(ExternalString); +pub const ExternalPackageNameHashList = ExternalSlice(PackageNameHash); pub const VersionSlice = ExternalSlice(Semver.Version); pub const ExternalStringMap = extern struct { @@ -3384,18 +3395,18 @@ pub const PackageManager = struct { pub fn determinePreinstallState( manager: *PackageManager, - this: Package, + pkg: Package, lockfile: *Lockfile, out_name_and_version_hash: *?u64, out_patchfile_hash: *?u64, ) PreinstallState { - switch (manager.getPreinstallState(this.meta.id)) { + switch (manager.getPreinstallState(pkg.meta.id)) { .unknown => { // Do not automatically start downloading packages which are disabled // i.e. don't download all of esbuild's versions or SWCs - if (this.isDisabled()) { - manager.setPreinstallState(this.meta.id, lockfile, .done); + if (pkg.isDisabled()) { + manager.setPreinstallState(pkg.meta.id, lockfile, .done); return .done; } @@ -3406,37 +3417,37 @@ pub const PackageManager = struct { sfb.get(), "{s}@{}", .{ - this.name.slice(manager.lockfile.buffers.string_bytes.items), - this.resolution.fmt(manager.lockfile.buffers.string_bytes.items, .posix), + pkg.name.slice(manager.lockfile.buffers.string_bytes.items), + pkg.resolution.fmt(manager.lockfile.buffers.string_bytes.items, .posix), }, ) catch unreachable; const name_and_version_hash = String.Builder.stringHash(name_and_version); const patched_dep = manager.lockfile.patched_dependencies.get(name_and_version_hash) orelse break :brk null; defer out_name_and_version_hash.* = name_and_version_hash; if (patched_dep.patchfile_hash_is_null) { - manager.setPreinstallState(this.meta.id, manager.lockfile, .calc_patch_hash); + manager.setPreinstallState(pkg.meta.id, manager.lockfile, .calc_patch_hash); return .calc_patch_hash; } out_patchfile_hash.* = patched_dep.patchfileHash().?; break :brk patched_dep.patchfileHash().?; }; - const folder_path = switch (this.resolution.tag) { - .git => manager.cachedGitFolderNamePrintAuto(&this.resolution.value.git, patch_hash), - .github => manager.cachedGitHubFolderNamePrintAuto(&this.resolution.value.github, patch_hash), - .npm => manager.cachedNPMPackageFolderName(lockfile.str(&this.name), this.resolution.value.npm.version, patch_hash), - .local_tarball => manager.cachedTarballFolderName(this.resolution.value.local_tarball, patch_hash), - .remote_tarball => manager.cachedTarballFolderName(this.resolution.value.remote_tarball, patch_hash), + const folder_path = switch (pkg.resolution.tag) { + .git => manager.cachedGitFolderNamePrintAuto(&pkg.resolution.value.git, patch_hash), + .github => manager.cachedGitHubFolderNamePrintAuto(&pkg.resolution.value.github, patch_hash), + .npm => manager.cachedNPMPackageFolderName(lockfile.str(&pkg.name), pkg.resolution.value.npm.version, patch_hash), + .local_tarball => manager.cachedTarballFolderName(pkg.resolution.value.local_tarball, patch_hash), + .remote_tarball => manager.cachedTarballFolderName(pkg.resolution.value.remote_tarball, patch_hash), else => "", }; if (folder_path.len == 0) { - manager.setPreinstallState(this.meta.id, lockfile, .extract); + manager.setPreinstallState(pkg.meta.id, lockfile, .extract); return .extract; } if (manager.isFolderInCache(folder_path)) { - manager.setPreinstallState(this.meta.id, lockfile, .done); + manager.setPreinstallState(pkg.meta.id, lockfile, .done); return .done; } @@ -3453,16 +3464,16 @@ pub const PackageManager = struct { const non_patched_path = manager.lockfile.allocator.dupeZ(u8, non_patched_path_) catch bun.outOfMemory(); defer manager.lockfile.allocator.free(non_patched_path); if (manager.isFolderInCache(non_patched_path)) { - manager.setPreinstallState(this.meta.id, manager.lockfile, .apply_patch); + manager.setPreinstallState(pkg.meta.id, manager.lockfile, .apply_patch); // yay step 1 is already done for us return .apply_patch; } // we need to extract non-patched pkg into the cache - manager.setPreinstallState(this.meta.id, lockfile, .extract); + manager.setPreinstallState(pkg.meta.id, lockfile, .extract); return .extract; } - manager.setPreinstallState(this.meta.id, lockfile, .extract); + manager.setPreinstallState(pkg.meta.id, lockfile, .extract); return .extract; }, else => |val| return val, @@ -6004,6 +6015,10 @@ pub const PackageManager = struct { resolution.value.github.resolved = builder.append(String, this.resolved); return resolution; } + + pub fn checkBundledDependencies() bool { + return true; + } }; const TarballResolver = struct { @@ -6027,6 +6042,10 @@ pub const PackageManager = struct { } return resolution; } + + pub fn checkBundledDependencies() bool { + return true; + } }; /// Returns true if we need to drain dependencies @@ -6060,7 +6079,7 @@ pub const PackageManager = struct { manager.allocator, manager.log, package_json_source, - *GitResolver, + GitResolver, &resolver, Features.npm, ) catch |err| { @@ -6133,6 +6152,11 @@ pub const PackageManager = struct { ); var package = Lockfile.Package{}; + var resolver: TarballResolver = .{ + .url = data.url, + .resolution = resolution, + }; + package.parse( manager.lockfile, manager, @@ -6140,10 +6164,7 @@ pub const PackageManager = struct { manager.log, package_json_source, TarballResolver, - TarballResolver{ - .url = data.url, - .resolution = resolution, - }, + &resolver, Features.npm, ) catch |err| { if (comptime log_level != .silent) { @@ -7691,7 +7712,7 @@ pub const PackageManager = struct { const dependency_groups = &.{ .{ "optionalDependencies", Dependency.Behavior.optional }, .{ "devDependencies", Dependency.Behavior.dev }, - .{ "dependencies", Dependency.Behavior.normal }, + .{ "dependencies", Dependency.Behavior.prod }, .{ "peerDependencies", Dependency.Behavior.peer }, }; @@ -9177,7 +9198,8 @@ pub const PackageManager = struct { }; lockfile.initEmpty(ctx.allocator); - try package.parse(&lockfile, manager, ctx.allocator, manager.log, package_json_source, void, {}, Features.folder); + var resolver: void = {}; + try package.parse(&lockfile, manager, ctx.allocator, manager.log, package_json_source, void, &resolver, Features.folder); name = lockfile.str(&package.name); if (name.len == 0) { if (manager.options.log_level != .silent) { @@ -9359,7 +9381,8 @@ pub const PackageManager = struct { }; lockfile.initEmpty(ctx.allocator); - try package.parse(&lockfile, manager, ctx.allocator, manager.log, package_json_source, void, {}, Features.folder); + var resolver: void = {}; + try package.parse(&lockfile, manager, ctx.allocator, manager.log, package_json_source, void, &resolver, Features.folder); name = lockfile.str(&package.name); if (name.len == 0) { if (manager.options.log_level != .silent) { @@ -11250,8 +11273,9 @@ pub const PackageManager = struct { Global.crash(); }; + var resolver: void = {}; var package = Lockfile.Package{}; - try package.parseWithJSON(lockfile, manager, manager.allocator, manager.log, package_json_source, json, void, {}, Features.folder); + try package.parseWithJSON(lockfile, manager, manager.allocator, manager.log, package_json_source, json, void, &resolver, Features.folder); const name = lockfile.str(&package.name); const actual_package = switch (lockfile.package_index.get(package.name_hash) orelse { @@ -11663,8 +11687,9 @@ pub const PackageManager = struct { Global.crash(); }; + var resolver: void = {}; var package = Lockfile.Package{}; - try package.parseWithJSON(lockfile, manager, manager.allocator, manager.log, package_json_source, json, void, {}, Features.folder); + try package.parseWithJSON(lockfile, manager, manager.allocator, manager.log, package_json_source, json, void, &resolver, Features.folder); const name = lockfile.str(&package.name); const actual_package = switch (lockfile.package_index.get(package.name_hash) orelse { @@ -14377,6 +14402,7 @@ pub const PackageManager = struct { lockfile.initEmpty(manager.allocator); var maybe_root = Lockfile.Package{}; + var resolver: void = {}; try maybe_root.parse( &lockfile, manager, @@ -14384,7 +14410,7 @@ pub const PackageManager = struct { manager.log, root_package_json_source, void, - {}, + &resolver, Features.main, ); const mapping = try manager.lockfile.allocator.alloc(PackageID, maybe_root.dependencies.len); @@ -14610,6 +14636,7 @@ pub const PackageManager = struct { Global.crash(); } + var resolver: void = {}; try root.parse( manager.lockfile, manager, @@ -14617,7 +14644,7 @@ pub const PackageManager = struct { manager.log, root_package_json_source, void, - {}, + &resolver, Features.main, ); diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 095c4c5e84..26528cc984 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -496,11 +496,14 @@ pub const Tree = struct { pub const HoistDependencyResult = union(enum) { dependency_loop, hoisted, - dest_id: Id, - replace: struct { - dest_id: Id, - dep_id: DependencyID, + placement: struct { + id: Id, + bundled: bool = false, }, + // replace: struct { + // dest_id: Id, + // dep_id: DependencyID, + // }, }; pub const SubtreeError = OOM || error{DependencyLoop}; @@ -759,6 +762,7 @@ pub const Tree = struct { pub fn processSubtree( this: *const Tree, dependency_id: DependencyID, + hoist_root_id: Tree.Id, comptime method: BuilderMethod, builder: *Builder(method), log_level: if (method == .filter) PackageManager.Options.LogLevel else void, @@ -833,7 +837,7 @@ pub const Tree = struct { // filter out disabled dependencies if (comptime method == .filter) { - if (builder.lockfile.isPackageDisabled( + if (builder.lockfile.isResolvedDependencyDisabled( dep_id, switch (pkg_resolutions[parent_pkg_id].tag) { .root, .workspace, .folder => builder.manager.options.local_package_features, @@ -857,13 +861,21 @@ pub const Tree = struct { } } - const dependency = builder.dependencies[dep_id]; - // Do not hoist folder dependencies - const res: HoistDependencyResult = if (pkg_resolutions[pkg_id].tag == .folder) - .{ .dest_id = next.id } - else - try next.hoistDependency( + const hoisted: HoistDependencyResult = hoisted: { + const dependency = builder.dependencies[dep_id]; + + // don't hoist if it's a folder dependency or a bundled dependency. + if (dependency.behavior.isBundled()) { + break :hoisted .{ .placement = .{ .id = next.id, .bundled = true } }; + } + + if (pkg_resolutions[pkg_id].tag == .folder) { + break :hoisted .{ .placement = .{ .id = next.id } }; + } + + break :hoisted try next.hoistDependency( true, + hoist_root_id, pkg_id, &dependency, dependency_lists, @@ -871,25 +883,20 @@ pub const Tree = struct { method, builder, ); + }; - switch (res) { + switch (hoisted) { .dependency_loop, .hoisted => continue, - .replace => |replacement| { - var dep_ids = dependency_lists[replacement.dest_id].items; - for (0..dep_ids.len) |i| { - if (dep_ids[i] == replacement.dep_id) { - dep_ids[i] = dep_id; - break; - } - } - }, - .dest_id => |dest_id| { - dependency_lists[dest_id].append(builder.allocator, dep_id) catch bun.outOfMemory(); - trees[dest_id].dependencies.len += 1; + .placement => |dest| { + dependency_lists[dest.id].append(builder.allocator, dep_id) catch bun.outOfMemory(); + trees[dest.id].dependencies.len += 1; if (builder.resolution_lists[pkg_id].len > 0) { try builder.queue.writeItem(.{ - .tree_id = dest_id, + .tree_id = dest.id, .dependency_id = dep_id, + + // if it's bundled, start a new hoist root + .hoist_root_id = if (dest.bundled) dest.id else hoist_root_id, }); } }, @@ -906,10 +913,10 @@ pub const Tree = struct { // 1 (return hoisted) - de-duplicate (skip) the package // 2 (return id) - move the package to the top directory // 3 (return dependency_loop) - leave the package at the same (relative) directory - // 4 (replace) - replace the existing (same name) parent dependency fn hoistDependency( this: *Tree, comptime as_defined: bool, + hoist_root_id: Id, package_id: PackageID, dependency: *const Dependency, dependency_lists: []Lockfile.DependencyIDList, @@ -973,9 +980,10 @@ pub const Tree = struct { } // this dependency was not found in this tree, try hoisting or placing in the next parent - if (this.parent != invalid_id) { + if (this.parent != invalid_id and this.id != hoist_root_id) { const id = trees[this.parent].hoistDependency( false, + hoist_root_id, package_id, dependency, dependency_lists, @@ -987,11 +995,11 @@ pub const Tree = struct { } // place the dependency in the current tree - return .{ .dest_id = this.id }; // 2 + return .{ .placement = .{ .id = this.id } }; // 2 } }; -pub fn isPackageDisabled( +pub fn isResolvedDependencyDisabled( lockfile: *const Lockfile, dep_id: DependencyID, features: Features, @@ -1001,7 +1009,7 @@ pub fn isPackageDisabled( const dep = lockfile.buffers.dependencies.items[dep_id]; - return !dep.behavior.isEnabled(features); + return dep.behavior.isBundled() or !dep.behavior.isEnabled(features); } /// This conditionally clones the lockfile with root packages marked as non-resolved @@ -1427,6 +1435,10 @@ pub fn fmtMetaHash(this: *const Lockfile) MetaHashFormatter { pub const FillItem = struct { tree_id: Tree.Id, dependency_id: DependencyID, + + /// If valid, dependencies will not hoist + /// beyond this tree if they're in a subtree + hoist_root_id: Tree.Id, }; pub const TreeFiller = std.fifo.LinearFifo(FillItem, .Dynamic); @@ -1497,10 +1509,23 @@ pub fn hoist( .manager = manager, }; - try (Tree{}).processSubtree(Tree.root_dep_id, method, &builder, if (method == .filter) manager.options.log_level else {}); + try (Tree{}).processSubtree( + Tree.root_dep_id, + Tree.invalid_id, + method, + &builder, + if (method == .filter) manager.options.log_level else {}, + ); + // This goes breadth-first while (builder.queue.readItem()) |item| { - try builder.list.items(.tree)[item.tree_id].processSubtree(item.dependency_id, method, &builder, if (method == .filter) manager.options.log_level else {}); + try builder.list.items(.tree)[item.tree_id].processSubtree( + item.dependency_id, + item.hoist_root_id, + method, + &builder, + if (method == .filter) manager.options.log_level else {}, + ); } const cleaned = try builder.clean(); @@ -1771,7 +1796,7 @@ pub const Printer = struct { // It's possible this package was installed but the dependency is disabled. // Have "zod@1.0.0" in dependencies and `zod2@npm:zod@1.0.0` in devDependencies // and install with --omit=dev. - if (this.lockfile.isPackageDisabled( + if (this.lockfile.isResolvedDependencyDisabled( dep_id, this.options.local_package_features, &pkg_metas[package_id], @@ -2267,14 +2292,14 @@ pub const Printer = struct { } if (dependencies.len > 0) { - var behavior = Behavior.uninitialized; + var behavior: Behavior = .{}; var dependency_behavior_change_count: u8 = 0; for (dependencies) |dep| { if (!dep.behavior.eq(behavior)) { if (dep.behavior.isOptional()) { try writer.writeAll(" optionalDependencies:\n"); if (comptime Environment.allow_assert) dependency_behavior_change_count += 1; - } else if (dep.behavior.isNormal()) { + } else if (dep.behavior.isProd()) { try writer.writeAll(" dependencies:\n"); if (comptime Environment.allow_assert) dependency_behavior_change_count += 1; } else if (dep.behavior.isDev()) { @@ -3597,7 +3622,7 @@ pub const Package = extern struct { field: string, behavior: Behavior, - pub const dependencies = DependencyGroup{ .prop = "dependencies", .field = "dependencies", .behavior = Behavior.normal }; + pub const dependencies = DependencyGroup{ .prop = "dependencies", .field = "dependencies", .behavior = Behavior.prod }; pub const dev = DependencyGroup{ .prop = "devDependencies", .field = "dev_dependencies", .behavior = Behavior.dev }; pub const optional = DependencyGroup{ .prop = "optionalDependencies", .field = "optional_dependencies", .behavior = Behavior.optional }; pub const peer = DependencyGroup{ .prop = "peerDependencies", .field = "peer_dependencies", .behavior = Behavior.peer }; @@ -3987,13 +4012,23 @@ pub const Package = extern struct { const dep_version = string_builder.appendWithHash(String, version_string_.slice(string_buf), version_string_.hash); const sliced = dep_version.sliced(lockfile.buffers.string_bytes.items); + var behavior = group.behavior; + if (comptime is_peer) { + behavior.optional = i < package_version.non_optional_peer_dependencies_start; + } + if (package_version_ptr.allDependenciesBundled()) { + behavior.bundled = true; + } else for (package_version.bundled_dependencies.get(manifest.bundled_deps_buf)) |bundled_dep_name_hash| { + if (bundled_dep_name_hash == name.hash) { + behavior.bundled = true; + break; + } + } + const dependency = Dependency{ .name = name.value, .name_hash = name.hash, - .behavior = if (comptime is_peer) - group.behavior.setOptional(i < package_version.non_optional_peer_dependencies_start) - else - group.behavior, + .behavior = behavior, .version = Dependency.parse( allocator, name.value, @@ -4306,6 +4341,7 @@ pub const Package = extern struct { const json = pm.workspace_package_json_cache.getWithSource(bun.default_allocator, log, source, .{}).unwrap() catch break :brk false; + var resolver: void = {}; try workspace.parseWithJSON( to_lockfile, pm, @@ -4314,7 +4350,7 @@ pub const Package = extern struct { source, json.root, void, - {}, + &resolver, Features.workspace, ); @@ -4395,7 +4431,7 @@ pub const Package = extern struct { log: *logger.Log, source: logger.Source, comptime ResolverContext: type, - resolver: ResolverContext, + resolver: *ResolverContext, comptime features: Features, ) !void { initializeStore(); @@ -4551,7 +4587,7 @@ pub const Package = extern struct { for (package_dependencies[0..dependencies_count]) |*dep| { if (dep.name_hash == name_hash and dep.version.tag == .workspace) { dep.* = .{ - .behavior = if (in_workspace) group.behavior.setWorkspace(true) else group.behavior, + .behavior = if (in_workspace) group.behavior.add(.workspace) else group.behavior, .name = external_alias.value, .name_hash = external_alias.hash, .version = dependency_version, @@ -4663,7 +4699,7 @@ pub const Package = extern struct { } const this_dep = Dependency{ - .behavior = if (in_workspace) group.behavior.setWorkspace(true) else group.behavior, + .behavior = if (in_workspace) group.behavior.add(.workspace) else group.behavior, .name = external_alias.value, .name_hash = external_alias.hash, .version = dependency_version, @@ -5085,7 +5121,7 @@ pub const Package = extern struct { source: logger.Source, json: Expr, comptime ResolverContext: type, - resolver: ResolverContext, + resolver: *ResolverContext, comptime features: Features, ) !void { var string_builder = lockfile.stringBuilder(); @@ -5107,7 +5143,7 @@ pub const Package = extern struct { } // name is not validated by npm, so fallback to creating a new from the version literal - if (ResolverContext == *PackageManager.GitResolver) { + if (ResolverContext == PackageManager.GitResolver) { const resolution: *const Resolution = resolver.resolution; const repo = switch (resolution.tag) { .git => resolution.value.git, @@ -5397,7 +5433,7 @@ pub const Package = extern struct { const package_dependencies = lockfile.buffers.dependencies.items.ptr[off..total_len]; name: { - if (ResolverContext == *PackageManager.GitResolver) { + if (ResolverContext == PackageManager.GitResolver) { if (resolver.new_name.len != 0) { defer lockfile.allocator.free(resolver.new_name); const external_string = string_builder.append(ExternalString, resolver.new_name); @@ -5545,6 +5581,25 @@ pub const Package = extern struct { try lockfile.scratch.duplicate_checker_map.ensureTotalCapacity(total_dependencies_count); } + var bundled_deps = bun.StringSet.init(allocator); + defer bundled_deps.deinit(); + var bundle_all_deps = false; + if (comptime ResolverContext != void and ResolverContext.checkBundledDependencies()) { + if (json.get("bundleDependencies") orelse json.get("bundledDependencies")) |bundled_deps_expr| { + switch (bundled_deps_expr.data) { + .e_boolean => |boolean| { + bundle_all_deps = boolean.value; + }, + .e_array => |arr| { + for (arr.slice()) |item| { + try bundled_deps.insert(item.asString(allocator) orelse continue); + } + }, + else => {}, + } + } + } + total_dependencies_count = 0; const in_workspace = lockfile.workspace_paths.contains(package.name_hash); @@ -5645,7 +5700,7 @@ pub const Package = extern struct { )) |_dep| { var dep = _dep; if (group.behavior.isPeer() and optional_peer_dependencies.contains(external_name.hash)) { - dep.behavior = dep.behavior.setOptional(true); + dep.behavior = dep.behavior.add(.optional); } package_dependencies[total_dependencies_count] = dep; @@ -5688,7 +5743,11 @@ pub const Package = extern struct { )) |_dep| { var dep = _dep; if (group.behavior.isPeer() and optional_peer_dependencies.contains(external_name.hash)) { - dep.behavior = dep.behavior.setOptional(true); + dep.behavior.optional = true; + } + + if (bundle_all_deps or bundled_deps.contains(dep.name.slice(lockfile.buffers.string_bytes.items))) { + dep.behavior.bundled = true; } package_dependencies[total_dependencies_count] = dep; diff --git a/src/install/migration.zig b/src/install/migration.zig index f57c59fb79..1810598c74 100644 --- a/src/install/migration.zig +++ b/src/install/migration.zig @@ -675,9 +675,7 @@ pub fn migrateNPMLockfile( .workspace = wksp_path, }, }, - .behavior = .{ - .workspace = true, - }, + .behavior = Dependency.Behavior.workspace, }; resolutions_buf[0] = entry1.new_package_id; @@ -768,7 +766,7 @@ pub fn migrateNPMLockfile( .name_hash = name_hash, .version = version, .behavior = .{ - .normal = dep_key == .dependencies, + .prod = dep_key == .dependencies, .optional = dep_key == .optionalDependencies, .dev = dep_key == .devDependencies, .peer = dep_key == .peerDependencies, @@ -945,7 +943,7 @@ pub fn migrateNPMLockfile( .name_hash = name_hash, .version = version, .behavior = .{ - .normal = dep_key == .dependencies, + .prod = dep_key == .dependencies, .optional = true, .dev = dep_key == .devDependencies, .peer = dep_key == .peerDependencies, diff --git a/src/install/npm.zig b/src/install/npm.zig index 3eeb230c78..e0801946d1 100644 --- a/src/install/npm.zig +++ b/src/install/npm.zig @@ -9,6 +9,8 @@ const string = @import("../string_types.zig").string; const strings = @import("../string_immutable.zig"); const PackageManager = @import("./install.zig").PackageManager; const ExternalStringMap = @import("./install.zig").ExternalStringMap; +const ExternalPackageNameHashList = bun.install.ExternalPackageNameHashList; +const PackageNameHash = bun.install.PackageNameHash; const ExternalStringList = @import("./install.zig").ExternalStringList; const ExternalSlice = @import("./install.zig").ExternalSlice; const initializeStore = @import("./install.zig").initializeMiniStore; @@ -857,8 +859,6 @@ pub const Architecture = enum(u16) { } }; -const BigExternalString = Semver.BigExternalString; - pub const PackageVersion = extern struct { /// `"integrity"` field || `"shasum"` field /// https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#dist @@ -880,6 +880,8 @@ pub const PackageVersion = extern struct { /// We keep it in the data layout so that if it turns out we do need it, we can add it without invalidating everyone's history. dev_dependencies: ExternalStringMap = ExternalStringMap{}, + bundled_dependencies: ExternalPackageNameHashList = .{}, + /// `"bin"` field in [package.json](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#bin) bin: Bin = Bin{}, @@ -909,10 +911,14 @@ pub const PackageVersion = extern struct { /// `hasInstallScript` field in registry API. has_install_script: bool = false, + + pub fn allDependenciesBundled(this: *const PackageVersion) bool { + return this.bundled_dependencies.isInvalid(); + } }; comptime { - if (@sizeOf(Npm.PackageVersion) != 224) { + if (@sizeOf(Npm.PackageVersion) != 232) { @compileError(std.fmt.comptimePrint("Npm.PackageVersion has unexpected size {d}", .{@sizeOf(Npm.PackageVersion)})); } } @@ -934,7 +940,6 @@ pub const NpmPackage = extern struct { versions_buf: VersionSlice = VersionSlice{}, string_lists_buf: ExternalStringList = ExternalStringList{}, - string_buf: BigExternalString = BigExternalString{}, }; pub const PackageManifest = struct { @@ -947,6 +952,7 @@ pub const PackageManifest = struct { external_strings_for_versions: []const ExternalString = &[_]ExternalString{}, package_versions: []const PackageVersion = &[_]PackageVersion{}, extern_strings_bin_entries: []const ExternalString = &[_]ExternalString{}, + bundled_deps_buf: []const PackageNameHash = &.{}, pub inline fn name(this: *const PackageManifest) string { return this.pkg.name.slice(this.string_buf); @@ -961,9 +967,10 @@ pub const PackageManifest = struct { } pub const Serializer = struct { - // - version 3: added serialization of registry url. it's used to invalidate when it changes - // - version 4: fixed bug with cpu & os tag not being added correctly - pub const version = "bun-npm-manifest-cache-v0.0.4\n"; + // - v0.0.3: added serialization of registry url. it's used to invalidate when it changes + // - v0.0.4: fixed bug with cpu & os tag not being added correctly + // - v0.0.5: added bundled dependencies + pub const version = "bun-npm-manifest-cache-v0.0.5\n"; const header_bytes: string = "#!/usr/bin/env bun\n" ++ version; pub const sizes = blk: { @@ -1581,6 +1588,12 @@ pub const PackageManifest = struct { var optional_peer_dep_names = std.ArrayList(u64).init(default_allocator); defer optional_peer_dep_names.deinit(); + var bundled_deps_set = bun.StringSet.init(allocator); + defer bundled_deps_set.deinit(); + var bundle_all_deps = false; + + var bundled_deps_count: usize = 0; + var string_builder = String.Builder{ .string_pool = string_pool, }; @@ -1693,6 +1706,22 @@ pub const PackageManifest = struct { } } + bundled_deps_set.map.clearRetainingCapacity(); + bundle_all_deps = false; + if (prop.value.?.get("bundleDependencies") orelse prop.value.?.get("bundledDependencies")) |bundled_deps_expr| { + switch (bundled_deps_expr.data) { + .e_boolean => |boolean| { + bundle_all_deps = boolean.value; + }, + .e_array => |arr| { + for (arr.slice()) |bundled_dep| { + try bundled_deps_set.insert(bundled_dep.asString(allocator) orelse continue); + } + }, + else => {}, + } + } + inline for (dependency_groups) |pair| { if (prop.value.?.asProperty(pair.prop)) |versioned_deps| { if (versioned_deps.expr.data == .e_object) { @@ -1700,6 +1729,11 @@ pub const PackageManifest = struct { const properties = versioned_deps.expr.data.e_object.properties.slice(); for (properties) |property| { if (property.key.?.asString(allocator)) |key| { + if (!bundle_all_deps and bundled_deps_set.swapRemove(key)) { + // swap remove the dependency name because it could exist in + // multiple behavior groups. + bundled_deps_count += 1; + } string_builder.count(key); string_builder.count(property.value.?.asString(allocator) orelse ""); } @@ -1745,6 +1779,8 @@ pub const PackageManifest = struct { var all_extern_strings_bin_entries = extern_strings_bin_entries; var all_tarball_url_strings = try allocator.alloc(ExternalString, tarball_urls_count); var tarball_url_strings = all_tarball_url_strings; + const bundled_deps_buf = try allocator.alloc(PackageNameHash, bundled_deps_count); + var bundled_deps_offset: usize = 0; if (versioned_packages.len > 0) { const versioned_packages_bytes = std.mem.sliceAsBytes(versioned_packages); @@ -1829,6 +1865,22 @@ pub const PackageManifest = struct { } if (!parsed_version.valid) continue; + bundled_deps_set.map.clearRetainingCapacity(); + bundle_all_deps = false; + if (prop.value.?.get("bundleDependencies") orelse prop.value.?.get("bundledDependencies")) |bundled_deps_expr| { + switch (bundled_deps_expr.data) { + .e_boolean => |boolean| { + bundle_all_deps = boolean.value; + }, + .e_array => |arr| { + for (arr.slice()) |bundled_dep| { + try bundled_deps_set.insert(bundled_dep.asString(allocator) orelse continue); + } + }, + else => {}, + } + } + var package_version: PackageVersion = empty_version; if (prop.value.?.asProperty("cpu")) |cpu_q| { @@ -2042,6 +2094,8 @@ pub const PackageManifest = struct { } } + const bundled_deps_begin = bundled_deps_offset; + var i: usize = 0; for (items) |item| { @@ -2051,6 +2105,11 @@ pub const PackageManifest = struct { this_names[i] = string_builder.append(ExternalString, name_str); this_versions[i] = string_builder.append(ExternalString, version_str); + if (!bundle_all_deps and bundled_deps_set.swapRemove(name_str)) { + bundled_deps_buf[bundled_deps_offset] = this_names[i].hash; + bundled_deps_offset += 1; + } + if (comptime is_peer) { if (std.mem.indexOfScalar(u64, optional_peer_dep_names.items, this_names[i].hash) != null) { // For optional peer dependencies, we store a length instead of a whole separate array @@ -2087,6 +2146,15 @@ pub const PackageManifest = struct { count = i; + if (bundle_all_deps) { + package_version.bundled_dependencies = ExternalPackageNameHashList.invalid; + } else { + package_version.bundled_dependencies = ExternalPackageNameHashList.init( + bundled_deps_buf, + bundled_deps_buf[bundled_deps_begin..bundled_deps_offset], + ); + } + var name_list = ExternalStringList.init(all_extern_strings, this_names); var version_list = ExternalStringList.init(version_extern_strings, this_versions); @@ -2368,15 +2436,11 @@ pub const PackageManifest = struct { result.external_strings_for_versions = version_extern_strings; result.package_versions = versioned_packages; result.extern_strings_bin_entries = all_extern_strings_bin_entries[0 .. all_extern_strings_bin_entries.len - extern_strings_bin_entries.len]; + result.bundled_deps_buf = bundled_deps_buf; result.pkg.public_max_age = public_max_age; if (string_builder.ptr) |ptr| { result.string_buf = ptr[0..string_builder.len]; - result.pkg.string_buf = BigExternalString{ - .off = 0, - .len = @as(u32, @truncate(string_builder.len)), - .hash = 0, - }; } return result; diff --git a/src/install/resolvers/folder_resolver.zig b/src/install/resolvers/folder_resolver.zig index 4528a41a27..dceff73f4b 100644 --- a/src/install/resolvers/folder_resolver.zig +++ b/src/install/resolvers/folder_resolver.zig @@ -77,6 +77,10 @@ pub const FolderResolution = union(Tag) { pub fn count(this: @This(), comptime Builder: type, builder: Builder, _: JSAst.Expr) void { builder.count(this.folder_path); } + + pub fn checkBundledDependencies() bool { + return tag == .folder or tag == .symlink; + } }; } @@ -99,6 +103,10 @@ pub const FolderResolution = union(Tag) { } pub fn count(_: @This(), comptime Builder: type, _: Builder, _: JSAst.Expr) void {} + + pub fn checkBundledDependencies() bool { + return true; + } }; const Paths = struct { @@ -165,7 +173,7 @@ pub const FolderResolution = union(Tag) { version: Dependency.Version, comptime features: Features, comptime ResolverType: type, - resolver: ResolverType, + resolver: *ResolverType, ) !Lockfile.Package { var body = Npm.Registry.BodyPool.get(manager.allocator); defer Npm.Registry.BodyPool.release(body); @@ -262,45 +270,63 @@ pub const FolderResolution = union(Tag) { if (entry.found_existing) return entry.value_ptr.*; const package: Lockfile.Package = switch (global_or_relative) { - .global => brk: { + .global => global: { var path: bun.PathBuffer = undefined; std.mem.copyForwards(u8, &path, non_normalized_path); - break :brk readPackageJSONFromDisk( + var resolver: SymlinkResolver = .{ + .folder_path = path[0..non_normalized_path.len], + }; + break :global readPackageJSONFromDisk( manager, abs, version, Features.link, SymlinkResolver, - SymlinkResolver{ .folder_path = path[0..non_normalized_path.len] }, + &resolver, ); }, .relative => |tag| switch (tag) { - .folder => readPackageJSONFromDisk( - manager, - abs, - version, - Features.folder, - Resolver, - Resolver{ .folder_path = rel }, - ), - .workspace => readPackageJSONFromDisk( - manager, - abs, - version, - Features.workspace, - WorkspaceResolver, - WorkspaceResolver{ .folder_path = rel }, - ), + .folder => folder: { + var resolver: Resolver = .{ + .folder_path = rel, + }; + break :folder readPackageJSONFromDisk( + manager, + abs, + version, + Features.folder, + Resolver, + &resolver, + ); + }, + .workspace => workspace: { + var resolver: WorkspaceResolver = .{ + .folder_path = rel, + }; + break :workspace readPackageJSONFromDisk( + manager, + abs, + version, + Features.workspace, + WorkspaceResolver, + &resolver, + ); + }, else => unreachable, }, - .cache_folder => readPackageJSONFromDisk( - manager, - abs, - version, - Features.npm, - CacheFolderResolver, - CacheFolderResolver{ .version = version.value.npm.version.toVersion() }, - ), + .cache_folder => cache_folder: { + var resolver: CacheFolderResolver = .{ + .version = version.value.npm.version.toVersion(), + }; + break :cache_folder readPackageJSONFromDisk( + manager, + abs, + version, + Features.npm, + CacheFolderResolver, + &resolver, + ); + }, } catch |err| { if (err == error.FileNotFound or err == error.ENOENT) { entry.value_ptr.* = .{ .err = error.MissingPackageJSON }; diff --git a/src/install/semver.zig b/src/install/semver.zig index d03e65ae78..a3f9ca2efd 100644 --- a/src/install/semver.zig +++ b/src/install/semver.zig @@ -704,34 +704,6 @@ pub const ExternalString = extern struct { } }; -pub const BigExternalString = extern struct { - off: u32 = 0, - len: u32 = 0, - hash: u64 = 0, - - pub fn from(in: string) BigExternalString { - return BigExternalString{ - .off = 0, - .len = @as(u32, @truncate(in.len)), - .hash = bun.Wyhash.hash(0, in), - }; - } - - pub inline fn init(buf: string, in: string, hash: u64) BigExternalString { - assert(@intFromPtr(buf.ptr) <= @intFromPtr(in.ptr) and ((@intFromPtr(in.ptr) + in.len) <= (@intFromPtr(buf.ptr) + buf.len))); - - return BigExternalString{ - .off = @as(u32, @truncate(@intFromPtr(in.ptr) - @intFromPtr(buf.ptr))), - .len = @as(u32, @truncate(in.len)), - .hash = hash, - }; - } - - pub fn slice(this: BigExternalString, buf: string) string { - return buf[this.off..][0..this.len]; - } -}; - pub const SlicedString = struct { buf: string, slice: string, @@ -771,14 +743,12 @@ pub const SlicedString = struct { } }; -const RawType = void; pub const Version = extern struct { major: u32 = 0, minor: u32 = 0, patch: u32 = 0, _tag_padding: [4]u8 = .{0} ** 4, // [see padding_checker.zig] tag: Tag = .{}, - // raw: RawType = RawType{}, /// Assumes that there is only one buffer for all the strings pub fn sortGt(ctx: []const u8, lhs: Version, rhs: Version) bool { @@ -1717,10 +1687,6 @@ pub const Version = extern struct { result.len = @as(u32, @intCast(i)); - if (comptime RawType != void) { - result.version.raw = sliced_string.sub(input[0..i]).external(); - } - return result; } diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index 557bd39e31..3ef06e90ee 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -1797,7 +1797,7 @@ pub const Resolver = struct { // check the global cache directory for a package.json file. const manager = r.getPackageManager(); var dependency_version = Dependency.Version{}; - var dependency_behavior = Dependency.Behavior.normal; + var dependency_behavior = Dependency.Behavior.prod; var string_buf = esm.version; // const initial_pending_tasks = manager.pending_tasks; diff --git a/test/cli/install/__snapshots__/bun-workspaces.test.ts.snap b/test/cli/install/__snapshots__/bun-workspaces.test.ts.snap index 2fca1723d8..423a2b49ae 100644 --- a/test/cli/install/__snapshots__/bun-workspaces.test.ts.snap +++ b/test/cli/install/__snapshots__/bun-workspaces.test.ts.snap @@ -25,7 +25,7 @@ exports[`dependency on workspace without version in package.json: version: * 1`] }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -152,7 +152,7 @@ exports[`dependency on workspace without version in package.json: version: *.*.* }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -279,7 +279,7 @@ exports[`dependency on workspace without version in package.json: version: =* 1` }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -406,7 +406,7 @@ exports[`dependency on workspace without version in package.json: version: kjwoe }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "dist_tag": { @@ -533,7 +533,7 @@ exports[`dependency on workspace without version in package.json: version: *.1.* }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -660,7 +660,7 @@ exports[`dependency on workspace without version in package.json: version: *-pre }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -787,7 +787,7 @@ exports[`dependency on workspace without version in package.json: version: 1 1`] }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -944,7 +944,7 @@ exports[`dependency on workspace without version in package.json: version: 1.* 1 }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -1101,7 +1101,7 @@ exports[`dependency on workspace without version in package.json: version: 1.1.* }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -1258,7 +1258,7 @@ exports[`dependency on workspace without version in package.json: version: 1.1.1 }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -1415,7 +1415,7 @@ exports[`dependency on workspace without version in package.json: version: *-pre }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -1572,7 +1572,7 @@ exports[`dependency on workspace without version in package.json: version: *+bui }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "id": 2, @@ -1729,7 +1729,7 @@ exports[`dependency on workspace without version in package.json: version: lates }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "dist_tag": { @@ -1886,7 +1886,7 @@ exports[`dependency on workspace without version in package.json: version: 1`] }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "dist_tag": { @@ -2043,7 +2043,7 @@ exports[`dependency on same name as workspace and dist-tag: with version 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, "workspace": true, }, "dist_tag": { diff --git a/test/cli/install/registry/bun-install-registry.test.ts b/test/cli/install/registry/bun-install-registry.test.ts index 00248aa9c6..846635dfd4 100644 --- a/test/cli/install/registry/bun-install-registry.test.ts +++ b/test/cli/install/registry/bun-install-registry.test.ts @@ -1898,6 +1898,314 @@ describe("text lockfile", () => { } }); +describe("bundledDependencies", () => { + for (const textLockfile of [true, false]) { + test(`(${textLockfile ? "bun.lock" : "bun.lockb"}) basic`, async () => { + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "bundled-basic", + version: "1.1.1", + dependencies: { + "bundled-1": "1.0.0", + }, + }), + ), + ]); + + const cmd = textLockfile ? [bunExe(), "install", "--save-text-lockfile"] : [bunExe(), "install"]; + let { exited } = spawn({ + cmd, + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + }); + + expect(await exited).toBe(0); + + expect( + await Promise.all([ + exists(join(packageDir, "node_modules", "no-deps", "package.json")), + exists(join(packageDir, "node_modules", "bundled-1", "node_modules", "no-deps", "package.json")), + ]), + ).toEqual([false, true]); + + ({ exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + })); + + expect(await exited).toBe(0); + + expect( + await Promise.all([ + exists(join(packageDir, "node_modules", "no-deps", "package.json")), + exists(join(packageDir, "node_modules", "bundled-1", "node_modules", "no-deps", "package.json")), + ]), + ).toEqual([false, true]); + }); + + test(`(${textLockfile ? "bun.lock" : "bun.lockb"}) bundledDependencies === true`, async () => { + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "bundled-true", + version: "1.1.1", + dependencies: { + "bundled-true": "1.0.0", + }, + }), + ), + ]); + + const cmd = textLockfile ? [bunExe(), "install", "--save-text-lockfile"] : [bunExe(), "install"]; + let { exited } = spawn({ + cmd, + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + }); + + expect(await exited).toBe(0); + + async function check() { + return Promise.all([ + exists(join(packageDir, "node_modules", "no-deps", "package.json")), + exists(join(packageDir, "node_modules", "one-dep", "package.json")), + exists(join(packageDir, "node_modules", "bundled-true", "node_modules", "no-deps", "package.json")), + exists(join(packageDir, "node_modules", "bundled-true", "node_modules", "one-dep", "package.json")), + exists( + join( + packageDir, + "node_modules", + "bundled-true", + "node_modules", + "one-dep", + "node_modules", + "no-deps", + "package.json", + ), + ), + ]); + } + + expect(await check()).toEqual([false, false, true, true, true]); + + ({ exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + })); + + expect(await exited).toBe(0); + + expect(await check()).toEqual([false, false, true, true, true]); + }); + + test(`(${textLockfile ? "bun.lock" : "bun.lockb"}) transitive bundled dependency collision`, async () => { + // Install a package with one bundled dependency and one regular dependency. + // The bundled dependency has a transitive dependency of the same regular dependency, + // but at a different version. Test that the regular dependency does not replace the + // other version (both should exist). + + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "bundled-collision", + dependencies: { + "bundled-transitive": "1.0.0", + // prevent both transitive dependencies from hoisting + "no-deps": "npm:a-dep@1.0.2", + "one-dep": "npm:a-dep@1.0.3", + }, + }), + ), + ]); + + const cmd = textLockfile ? [bunExe(), "install", "--save-text-lockfile"] : [bunExe(), "install"]; + let { exited } = spawn({ + cmd, + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + }); + + expect(await exited).toBe(0); + + async function check() { + expect( + await Promise.all([ + file(join(packageDir, "node_modules", "no-deps", "package.json")).json(), + file( + join(packageDir, "node_modules", "bundled-transitive", "node_modules", "no-deps", "package.json"), + ).json(), + file( + join( + packageDir, + "node_modules", + "bundled-transitive", + "node_modules", + "one-dep", + "node_modules", + "no-deps", + "package.json", + ), + ).json(), + exists(join(packageDir, "node_modules", "bundled-transitive", "node_modules", "one-dep", "package.json")), + ]), + ).toEqual([ + { name: "a-dep", version: "1.0.2" }, + { name: "no-deps", version: "1.0.0" }, + { name: "no-deps", version: "1.0.1" }, + true, + ]); + } + + await check(); + + ({ exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + })); + + expect(await exited).toBe(0); + + await check(); + }); + + test(`(${textLockfile ? "bun.lock" : "bun.lockb"}) git dependencies`, async () => { + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "bundled-git", + dependencies: { + // bundledDependencies: ["zod"], + "install-test1": "dylan-conway/bundled-install-test#7824752", + // bundledDependencies: true, + "install-test2": "git+ssh://git@github.com/dylan-conway/bundled-install-test#1301309", + }, + }), + ), + write( + join(packageDir, "bunfig.toml"), + ` +[install] +cache = "${join(packageDir, ".bun-cache")}" + `, + ), + ]); + + const cmd = textLockfile ? [bunExe(), "install", "--save-text-lockfile"] : [bunExe(), "install"]; + let { exited } = spawn({ + cmd, + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + }); + + expect(await exited).toBe(0); + + async function check() { + expect( + await Promise.all([ + exists(join(packageDir, "node_modules", "zod", "package.json")), + exists(join(packageDir, "node_modules", "install-test1", "node_modules", "zod", "package.json")), + exists(join(packageDir, "node_modules", "install-test2", "node_modules", "zod", "package.json")), + ]), + ).toEqual([false, true, true]); + } + + await check(); + + ({ exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + })); + + expect(await exited).toBe(0); + + await check(); + }); + + test(`(${textLockfile ? "bun.lock" : "bun.lockb"}) workspace dependencies bundle correctly`, async () => { + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "bundled-workspace", + workspaces: ["packages/*"], + }), + ), + write( + join(packageDir, "packages", "pkg-one-one-one", "package.json"), + JSON.stringify({ + name: "pkg-one-one-one", + dependencies: { + "no-deps": "1.0.0", + "bundled-1": "1.0.0", + }, + bundledDependencies: ["no-deps"], + }), + ), + ]); + + const cmd = textLockfile ? [bunExe(), "install", "--save-text-lockfile"] : [bunExe(), "install"]; + let { exited } = spawn({ + cmd, + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + }); + + expect(await exited).toBe(0); + + async function check() { + expect( + await Promise.all([ + exists(join(packageDir, "node_modules", "no-deps", "package.json")), + exists(join(packageDir, "packages", "pkg-one-one-one", "node_modules", "no-deps", "package.json")), + exists(join(packageDir, "node_modules", "bundled-1", "node_modules", "no-deps", "package.json")), + ]), + ).toEqual([true, false, true]); + } + + await check(); + + ({ exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "ignore", + stderr: "ignore", + env, + })); + + expect(await exited).toBe(0); + + await check(); + }); + } +}); + describe("optionalDependencies", () => { for (const optional of [true, false]) { test(`exit code is ${optional ? 0 : 1} when ${optional ? "optional" : ""} dependency tarball is missing`, async () => { diff --git a/test/cli/install/registry/packages/bundled-1/bundled-1-1.0.0.tgz b/test/cli/install/registry/packages/bundled-1/bundled-1-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a9f21c1b24fc263a088e913bb9eae9c095a0b213 GIT binary patch literal 375 zcmV--0f_z|iwFP!00002|LvAhYr;Sb$NSt*5&C37+nlW(D0}mLA3$WSy*O(1?$)cK zsNa3mI@Y?u7`Vd5{aymOT)1%jlc*%klNa(;ZM~J2!n!kv7=$mus;I#Kv`j_<|jDj2eM*%~l|1PM%+@rmcMXBKt3VPjU1@&UDH4|cYV%tkuKrfX- zmypu|E(3Lz4psyIUVM3I>GVm zy4R-jMZ}Dgnm4N8q})l>itMv(#QszL-)SlMPX8DUZ}k7bhLO>KSM$HI0lW|7e(nCW V0T>w>3=M}@_bL) zq*9b6fsa03vz!zOPGXsoamP?9m0GgLNtt>rfGY)+2OoI`P+WAbPo37)W_2|NFlU8h zX`7qx`$BSh-b%jPkm=vPdOsDM4*uHwvj4+T*zkW8TL0gN>o51|prp-G i@3sFcH-Ptjdt2I{7QeNT#bUAi6W##0kq==25C8z9!?*|l literal 0 HcmV?d00001 diff --git a/test/cli/install/registry/packages/bundled-transitive/package.json b/test/cli/install/registry/packages/bundled-transitive/package.json new file mode 100644 index 0000000000..45bb091b16 --- /dev/null +++ b/test/cli/install/registry/packages/bundled-transitive/package.json @@ -0,0 +1,48 @@ +{ + "name": "bundled-transitive", + "versions": { + "1.0.0": { + "name": "bundled-transitive", + "version": "1.0.0", + "dependencies": { + "no-deps": "1.0.0", + "one-dep": "1.0.0" + }, + "bundleDependencies": [ + "no-deps" + ], + "_id": "bundled-transitive@1.0.0", + "_integrity": "sha512-1CC+XKeBwsdseQEm4yOpfBzom2zEyrXQcgb6N4t83pL2DalEunEFO80yUpkzylsQYIH1uxGLI8G+4jhwvyH1bQ==", + "_nodeVersion": "22.6.0", + "_npmVersion": "10.8.3", + "integrity": "sha512-1CC+XKeBwsdseQEm4yOpfBzom2zEyrXQcgb6N4t83pL2DalEunEFO80yUpkzylsQYIH1uxGLI8G+4jhwvyH1bQ==", + "shasum": "8e0417711660590c7317add4a4a28388d4628cb1", + "dist": { + "integrity": "sha512-1CC+XKeBwsdseQEm4yOpfBzom2zEyrXQcgb6N4t83pL2DalEunEFO80yUpkzylsQYIH1uxGLI8G+4jhwvyH1bQ==", + "shasum": "8e0417711660590c7317add4a4a28388d4628cb1", + "tarball": "http://http://localhost:4873/bundled-transitive/-/bundled-transitive-1.0.0.tgz" + }, + "contributors": [] + } + }, + "time": { + "modified": "2024-12-30T22:05:28.027Z", + "created": "2024-12-30T22:05:28.027Z", + "1.0.0": "2024-12-30T22:05:28.027Z" + }, + "users": {}, + "dist-tags": { + "latest": "1.0.0" + }, + "_uplinks": {}, + "_distfiles": {}, + "_attachments": { + "bundled-transitive-1.0.0.tgz": { + "shasum": "8e0417711660590c7317add4a4a28388d4628cb1", + "version": "1.0.0" + } + }, + "_rev": "", + "_id": "bundled-transitive", + "readme": "" +} \ No newline at end of file diff --git a/test/cli/install/registry/packages/bundled-true/bundled-true-1.0.0.tgz b/test/cli/install/registry/packages/bundled-true/bundled-true-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..aad2709ff7f1673908b5e1805f79498d2f8dad88 GIT binary patch literal 451 zcmV;!0X+U6iwFP!00002|LvE{Zo)7SMYGOVj97t0gPp`dYSkV4egHz{k!i)tPU8eo z0sr0!;SC!Kq(%5{EKib&BhR_xM4jHS^NBU7LVO>qFdd<$$y11tuJvVzQ)i&9%fuK9 zd>>B5GkL-T%M$_PJO~)w$GBe?j7F;fr8?=vv=r;|k0ilnyc6YH?%*_1aiZZBV*E<` zF_zm-Ey`wk~)DQeuMgeW}6BHsZ3p9VN_N0Sn@cD{n9v~Ylhy|68#V@0R< zR}wP=xRxoL&A-d)!Z-XI{tf?s!v7le-2%8>|7U@F*#CtH0>gh1%1J88&KOJ2H0C>B zs^;Md#=5U$c7;34VI_mn!}tI5P2p_*T`uab;s4+9&kg?%#eXsVpL^oC{|j#TFN*&S z{i}Un(tq6hm(kthK3!Vd$I3RgKCwJ<8@%p@|0|*X8~$C79rDkGZ}=~s|86S75r$7m toZ`hMz}AO|wX1A@BFG$;dGhx)_OoR#H`ZZfWMp(}{Q$gt^Tq%i00196=k)*p literal 0 HcmV?d00001 diff --git a/test/cli/install/registry/packages/bundled-true/package.json b/test/cli/install/registry/packages/bundled-true/package.json new file mode 100644 index 0000000000..1eb11cb00b --- /dev/null +++ b/test/cli/install/registry/packages/bundled-true/package.json @@ -0,0 +1,43 @@ +{ + "name": "bundled-true", + "versions": { + "1.0.0": { + "name": "bundled-true", + "version": "1.0.0", + "dependencies": { + "no-deps": "1.0.0", + "one-dep": "1.0.0" + }, + "bundleDependencies": true, + "_id": "bundled-true@1.0.0", + "_nodeVersion": "23.5.0", + "_npmVersion": "10.9.2", + "dist": { + "integrity": "sha512-VRh+fxqRwtIsAn8P8EH8sETvUD8Yh5zMwujrjISki+37DHQr7jfj8tZW0LaE5rGZW49BeT83zqddRoI237zA/Q==", + "shasum": "e45979379fbf62c4f92e9d7297374c37cb191537", + "tarball": "http://localhost:4873/bundled-true/-/bundled-true-1.0.0.tgz" + }, + "contributors": [] + } + }, + "time": { + "modified": "2024-12-30T21:52:11.900Z", + "created": "2024-12-30T21:52:11.900Z", + "1.0.0": "2024-12-30T21:52:11.900Z" + }, + "users": {}, + "dist-tags": { + "latest": "1.0.0" + }, + "_uplinks": {}, + "_distfiles": {}, + "_attachments": { + "bundled-true-1.0.0.tgz": { + "shasum": "e45979379fbf62c4f92e9d7297374c37cb191537", + "version": "1.0.0" + } + }, + "_rev": "", + "_id": "bundled-true", + "readme": "ERROR: No README data found!" +} diff --git a/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap b/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap index e241842aa7..b1bb52a16f 100644 --- a/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap @@ -5,7 +5,7 @@ exports[`ssr works for 100-ish requests 1`] = ` "dependencies": [ { "behavior": { - "normal": true, + "prod": true, }, "id": 0, "literal": "20.7.0", @@ -18,7 +18,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 1, "literal": "18.2.22", @@ -31,7 +31,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 2, "literal": "18.2.7", @@ -44,7 +44,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 3, "literal": "10.4.16", @@ -57,7 +57,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 4, "literal": "^1.0.3", @@ -70,7 +70,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 5, "literal": "8.50.0", @@ -83,7 +83,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 6, "literal": "14.1.3", @@ -96,7 +96,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 7, "literal": "14.1.3", @@ -109,7 +109,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 8, "literal": "8.4.30", @@ -122,7 +122,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 9, "literal": "22.12.0", @@ -135,7 +135,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 10, "literal": "18.2.0", @@ -148,7 +148,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 11, "literal": "18.2.0", @@ -161,7 +161,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 12, "literal": "3.3.3", @@ -174,7 +174,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 13, "literal": "5.2.2", @@ -187,7 +187,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 14, "literal": "^5.0.2", @@ -200,7 +200,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 15, "literal": "^1.1.3", @@ -213,7 +213,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 16, "literal": "^1.18.2", @@ -226,7 +226,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 17, "literal": "^4.0.3", @@ -239,7 +239,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 18, "literal": "^8.4.23", @@ -252,7 +252,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 19, "literal": "^1.22.2", @@ -265,7 +265,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 20, "literal": "^3.32.0", @@ -278,7 +278,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 21, "literal": "^3.5.3", @@ -291,7 +291,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 22, "literal": "^3.2.12", @@ -304,7 +304,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 23, "literal": "^2.1.0", @@ -317,7 +317,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 24, "literal": "^1.2.2", @@ -330,7 +330,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 25, "literal": "^4.0.5", @@ -343,7 +343,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 26, "literal": "^1.0.0", @@ -356,7 +356,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 27, "literal": "^4.0.1", @@ -369,7 +369,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 28, "literal": "^6.0.2", @@ -382,7 +382,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 29, "literal": "^3.0.0", @@ -395,7 +395,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 30, "literal": "^3.0.0", @@ -408,7 +408,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 31, "literal": "^15.1.0", @@ -421,7 +421,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 32, "literal": "^6.0.1", @@ -434,7 +434,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 33, "literal": "^5.2.0", @@ -447,7 +447,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 34, "literal": "^4.0.1", @@ -460,7 +460,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 35, "literal": "^6.0.11", @@ -473,7 +473,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 36, "literal": "^3.0.0", @@ -486,7 +486,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 37, "literal": "^1.0.2", @@ -499,7 +499,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 38, "literal": "^2.3.4", @@ -512,7 +512,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 39, "literal": "^3.0.0", @@ -553,7 +553,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 42, "literal": "^3.3.6", @@ -566,7 +566,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 43, "literal": "^1.0.0", @@ -579,7 +579,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 44, "literal": "^1.0.2", @@ -592,7 +592,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 45, "literal": "^6.0.11", @@ -618,7 +618,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 47, "literal": "^4.0.0", @@ -631,7 +631,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 48, "literal": "^1.0.0", @@ -644,7 +644,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 49, "literal": "^1.1.7", @@ -670,7 +670,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 51, "literal": "^2.13.0", @@ -683,7 +683,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 52, "literal": "^1.0.7", @@ -696,7 +696,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 53, "literal": "^1.0.0", @@ -709,7 +709,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 54, "literal": "^2.0.0", @@ -722,7 +722,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 55, "literal": "^1.1.2", @@ -735,7 +735,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 56, "literal": "^2.3.0", @@ -748,7 +748,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 57, "literal": "^4.0.3", @@ -761,7 +761,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 58, "literal": "^2.1.1", @@ -774,7 +774,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 59, "literal": "^2.0.1", @@ -800,7 +800,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 61, "literal": "^3.0.3", @@ -813,7 +813,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 62, "literal": "^2.3.1", @@ -826,7 +826,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 63, "literal": "^7.1.1", @@ -839,7 +839,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 64, "literal": "^5.0.1", @@ -852,7 +852,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 65, "literal": "^7.0.0", @@ -865,7 +865,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 66, "literal": "^2.0.2", @@ -878,7 +878,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 67, "literal": "^1.2.3", @@ -891,7 +891,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 68, "literal": "^5.1.2", @@ -904,7 +904,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 69, "literal": "^1.3.0", @@ -917,7 +917,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 70, "literal": "^4.0.4", @@ -930,7 +930,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 71, "literal": "^4.0.1", @@ -943,7 +943,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 72, "literal": "2.1.5", @@ -956,7 +956,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 73, "literal": "^1.6.0", @@ -969,7 +969,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 74, "literal": "^1.0.4", @@ -982,7 +982,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 75, "literal": "2.0.5", @@ -995,7 +995,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 76, "literal": "^1.1.9", @@ -1008,7 +1008,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 77, "literal": "^1.2.2", @@ -1021,7 +1021,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 78, "literal": "~3.1.2", @@ -1034,7 +1034,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 79, "literal": "~3.0.2", @@ -1047,7 +1047,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 80, "literal": "~5.1.2", @@ -1060,7 +1060,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 81, "literal": "~2.1.0", @@ -1073,7 +1073,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 82, "literal": "~4.0.1", @@ -1086,7 +1086,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 83, "literal": "~3.0.0", @@ -1099,7 +1099,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 84, "literal": "~3.6.0", @@ -1125,7 +1125,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 86, "literal": "^2.2.1", @@ -1138,7 +1138,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 87, "literal": "^2.0.0", @@ -1151,7 +1151,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 88, "literal": "^3.0.0", @@ -1164,7 +1164,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 89, "literal": "^2.0.4", @@ -1177,7 +1177,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 90, "literal": "^0.3.2", @@ -1190,7 +1190,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 91, "literal": "^4.0.0", @@ -1203,7 +1203,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 92, "literal": "^10.3.10", @@ -1216,7 +1216,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 93, "literal": "^1.1.6", @@ -1229,7 +1229,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 94, "literal": "^2.7.0", @@ -1242,7 +1242,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 95, "literal": "^4.0.1", @@ -1255,7 +1255,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 96, "literal": "^0.1.9", @@ -1268,7 +1268,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 97, "literal": "^1.0.0", @@ -1281,7 +1281,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 98, "literal": "^4.0.1", @@ -1294,7 +1294,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 99, "literal": "^1.0.0", @@ -1307,7 +1307,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 100, "literal": ">= 3.1.0 < 4", @@ -1320,7 +1320,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 101, "literal": "^1.0.0", @@ -1333,7 +1333,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 102, "literal": "^3.1.0", @@ -1346,7 +1346,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 103, "literal": "^2.3.5", @@ -1359,7 +1359,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 104, "literal": "^9.0.1", @@ -1372,7 +1372,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 105, "literal": "^5.0.0 || ^6.0.2 || ^7.0.0", @@ -1385,7 +1385,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 106, "literal": "^1.10.1", @@ -1398,7 +1398,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 107, "literal": "^10.2.0", @@ -1411,7 +1411,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 108, "literal": "^5.0.0 || ^6.0.2 || ^7.0.0", @@ -1424,7 +1424,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 109, "literal": "^2.0.1", @@ -1437,7 +1437,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 110, "literal": "^1.0.0", @@ -1450,7 +1450,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 111, "literal": "^8.0.2", @@ -1476,7 +1476,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 113, "literal": "^5.1.2", @@ -1489,7 +1489,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 114, "is_alias": true, @@ -1503,7 +1503,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 115, "literal": "^7.0.1", @@ -1516,7 +1516,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 116, "is_alias": true, @@ -1530,7 +1530,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 117, "literal": "^8.1.0", @@ -1543,7 +1543,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 118, "is_alias": true, @@ -1557,7 +1557,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 119, "literal": "^4.0.0", @@ -1570,7 +1570,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 120, "literal": "^4.1.0", @@ -1583,7 +1583,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 121, "literal": "^6.0.0", @@ -1596,7 +1596,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 122, "literal": "^5.0.1", @@ -1609,7 +1609,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 123, "literal": "^8.0.0", @@ -1622,7 +1622,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 124, "literal": "^3.0.0", @@ -1635,7 +1635,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 125, "literal": "^6.0.1", @@ -1648,7 +1648,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 126, "literal": "^2.0.1", @@ -1661,7 +1661,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 127, "literal": "~1.1.4", @@ -1674,7 +1674,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 128, "literal": "^6.1.0", @@ -1687,7 +1687,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 129, "literal": "^5.0.1", @@ -1700,7 +1700,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 130, "literal": "^7.0.1", @@ -1713,7 +1713,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 131, "literal": "^6.0.1", @@ -1726,7 +1726,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 132, "literal": "^0.2.0", @@ -1739,7 +1739,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 133, "literal": "^9.2.2", @@ -1752,7 +1752,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 134, "literal": "^7.0.1", @@ -1765,7 +1765,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 135, "literal": "^7.0.0", @@ -1778,7 +1778,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 136, "literal": "^4.0.1", @@ -1791,7 +1791,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 137, "literal": "^3.1.0", @@ -1804,7 +1804,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 138, "literal": "^2.0.0", @@ -1817,7 +1817,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 139, "literal": "^2.0.1", @@ -1830,7 +1830,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 140, "literal": "^2.0.0", @@ -1843,7 +1843,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 141, "literal": "^3.0.0", @@ -1856,7 +1856,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 142, "literal": "^1.2.1", @@ -1869,7 +1869,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 143, "literal": "^1.4.10", @@ -1882,7 +1882,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 144, "literal": "^0.3.24", @@ -1895,7 +1895,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 145, "literal": "^3.1.0", @@ -1908,7 +1908,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 146, "literal": "^1.4.14", @@ -1921,7 +1921,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 147, "literal": "^0.23.0", @@ -1934,7 +1934,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 148, "literal": "^1.1.0", @@ -1960,7 +1960,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 150, "literal": "^1.1.0", @@ -1973,7 +1973,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 151, "literal": "^3.0.0 || ^4.0.0", @@ -1986,7 +1986,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 152, "literal": "^1.1.0", @@ -1999,7 +1999,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 153, "literal": "9.0.0", @@ -2012,7 +2012,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 154, "literal": "22.12.0", @@ -2025,7 +2025,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 155, "literal": "2.2.3", @@ -2038,7 +2038,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 156, "literal": "0.0.1299070", @@ -2051,7 +2051,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 157, "literal": "4.3.4", @@ -2064,7 +2064,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 158, "literal": "2.0.1", @@ -2077,7 +2077,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 159, "literal": "2.0.3", @@ -2090,7 +2090,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 160, "literal": "6.4.0", @@ -2103,7 +2103,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 161, "literal": "3.0.5", @@ -2116,7 +2116,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 162, "literal": "1.4.3", @@ -2129,7 +2129,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 163, "literal": "17.7.2", @@ -2142,7 +2142,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 164, "literal": "7.6.0", @@ -2155,7 +2155,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 165, "literal": "^6.0.0", @@ -2168,7 +2168,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 166, "literal": "^4.0.0", @@ -2181,7 +2181,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 167, "literal": "^8.0.1", @@ -2194,7 +2194,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 168, "literal": "^3.1.1", @@ -2207,7 +2207,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 169, "literal": "^2.0.5", @@ -2220,7 +2220,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 170, "literal": "^2.1.1", @@ -2233,7 +2233,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 171, "literal": "^4.2.3", @@ -2246,7 +2246,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 172, "literal": "^5.0.5", @@ -2259,7 +2259,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 173, "literal": "^21.1.1", @@ -2272,7 +2272,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 174, "literal": "^4.2.0", @@ -2285,7 +2285,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 175, "literal": "^6.0.1", @@ -2298,7 +2298,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 176, "literal": "^7.0.0", @@ -2311,7 +2311,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 177, "literal": "^5.2.1", @@ -2324,7 +2324,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 178, "literal": "^2.3.8", @@ -2337,7 +2337,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 179, "literal": "^1.3.1", @@ -2350,7 +2350,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 180, "literal": "^1.1.13", @@ -2363,7 +2363,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 181, "literal": "^3.0.0", @@ -2376,7 +2376,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 182, "literal": "^3.1.5", @@ -2415,7 +2415,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 185, "literal": "^2.1.0", @@ -2428,7 +2428,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 186, "literal": "^2.0.0", @@ -2441,7 +2441,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 187, "literal": "^2.0.0", @@ -2454,7 +2454,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 188, "literal": "^2.0.0", @@ -2467,7 +2467,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 189, "literal": "^2.18.0", @@ -2480,7 +2480,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 190, "literal": "^1.3.2", @@ -2493,7 +2493,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 191, "literal": "^1.0.1", @@ -2506,7 +2506,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 192, "literal": "^1.1.0", @@ -2532,7 +2532,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 194, "literal": "^1.6.4", @@ -2545,7 +2545,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 195, "literal": "^1.6.4", @@ -2558,7 +2558,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 196, "literal": "^1.2.0", @@ -2571,7 +2571,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 197, "literal": "^2.15.0", @@ -2584,7 +2584,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 198, "literal": "^1.1.0", @@ -2597,7 +2597,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 199, "literal": "^1.3.1", @@ -2610,7 +2610,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 200, "literal": "1", @@ -2623,7 +2623,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 201, "literal": "^1.4.0", @@ -2636,7 +2636,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 202, "literal": "^7.0.2", @@ -2649,7 +2649,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 203, "literal": "^4.3.4", @@ -2662,7 +2662,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 204, "literal": "^7.0.1", @@ -2675,7 +2675,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 205, "literal": "^7.0.3", @@ -2688,7 +2688,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 206, "literal": "^7.14.1", @@ -2701,7 +2701,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 207, "literal": "^7.0.1", @@ -2714,7 +2714,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 208, "literal": "^1.1.0", @@ -2727,7 +2727,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 209, "literal": "^8.0.2", @@ -2740,7 +2740,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 210, "literal": "^7.1.1", @@ -2753,7 +2753,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 211, "literal": "^4.3.4", @@ -2766,7 +2766,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 212, "literal": "^2.7.1", @@ -2779,7 +2779,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 213, "literal": "^9.0.5", @@ -2792,7 +2792,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 214, "literal": "^4.2.0", @@ -2805,7 +2805,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 215, "literal": "1.1.0", @@ -2818,7 +2818,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 216, "literal": "^1.1.3", @@ -2831,7 +2831,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 217, "literal": "2.1.2", @@ -2844,7 +2844,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 218, "literal": "^4.3.4", @@ -2857,7 +2857,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 219, "literal": "^0.23.0", @@ -2870,7 +2870,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 220, "literal": "^7.0.2", @@ -2883,7 +2883,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 221, "literal": "^4.3.4", @@ -2896,7 +2896,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 222, "literal": "^6.0.1", @@ -2909,7 +2909,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 223, "literal": "^7.0.0", @@ -2922,7 +2922,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 224, "literal": "^7.0.2", @@ -2935,7 +2935,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 225, "literal": "^7.0.0", @@ -2948,7 +2948,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 226, "literal": "^8.0.2", @@ -2961,7 +2961,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 227, "literal": "^5.0.0", @@ -2974,7 +2974,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 228, "literal": "^2.0.2", @@ -2987,7 +2987,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 229, "literal": "^0.13.4", @@ -3000,7 +3000,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 230, "literal": "^2.1.0", @@ -3013,7 +3013,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 231, "literal": "^4.0.1", @@ -3026,7 +3026,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 232, "literal": "^5.2.0", @@ -3039,7 +3039,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 233, "literal": "^2.0.2", @@ -3052,7 +3052,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 234, "literal": "^4.0.1", @@ -3078,7 +3078,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 236, "literal": "^2.0.1", @@ -3091,7 +3091,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 237, "literal": "^7.0.2", @@ -3104,7 +3104,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 238, "literal": "4", @@ -3117,7 +3117,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 239, "literal": "^7.1.0", @@ -3130,7 +3130,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 240, "literal": "^4.3.4", @@ -3143,7 +3143,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 241, "literal": "^5.0.2", @@ -3156,7 +3156,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 242, "literal": "^6.0.2", @@ -3169,7 +3169,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 243, "literal": "^4.3.4", @@ -3182,7 +3182,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 244, "literal": "^11.2.0", @@ -3195,7 +3195,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 245, "literal": "^4.2.0", @@ -3208,7 +3208,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 246, "literal": "^6.0.1", @@ -3221,7 +3221,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 247, "literal": "^2.0.0", @@ -3234,7 +3234,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 248, "literal": "^2.0.0", @@ -3260,7 +3260,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 250, "literal": "^4.1.1", @@ -3273,7 +3273,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 251, "literal": "^5.1.0", @@ -3286,7 +3286,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 252, "literal": "^2.10.0", @@ -3312,7 +3312,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 254, "literal": "*", @@ -3325,7 +3325,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 255, "literal": "~5.26.4", @@ -3338,7 +3338,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 256, "literal": "~1.1.0", @@ -3351,7 +3351,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 257, "literal": "~0.2.3", @@ -3364,7 +3364,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 258, "literal": "~1.2.0", @@ -3377,7 +3377,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 259, "literal": "^3.0.0", @@ -3390,7 +3390,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 260, "literal": "2.1.2", @@ -3403,7 +3403,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 261, "literal": "2.2.3", @@ -3416,7 +3416,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 262, "literal": "0.5.24", @@ -3429,7 +3429,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 263, "literal": "4.3.5", @@ -3442,7 +3442,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 264, "literal": "0.0.1299070", @@ -3455,7 +3455,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 265, "literal": "8.17.1", @@ -3496,7 +3496,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 268, "literal": "3.0.1", @@ -3509,7 +3509,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 269, "literal": "10.0.0", @@ -3522,7 +3522,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 270, "literal": "3.23.8", @@ -3548,7 +3548,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 272, "literal": "^2.2.1", @@ -3561,7 +3561,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 273, "literal": "^3.3.0", @@ -3574,7 +3574,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 274, "literal": "^4.1.0", @@ -3587,7 +3587,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 275, "literal": "^5.2.0", @@ -3614,7 +3614,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 277, "literal": "^7.0.0", @@ -3627,7 +3627,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 278, "literal": "^1.3.1", @@ -3640,7 +3640,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 279, "literal": "^2.3.0", @@ -3653,7 +3653,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 280, "literal": "^1.1.6", @@ -3666,7 +3666,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 281, "literal": "^0.2.1", @@ -3679,7 +3679,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 282, "literal": "^7.24.7", @@ -3692,7 +3692,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 283, "literal": "^1.0.0", @@ -3705,7 +3705,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 284, "literal": "^7.24.7", @@ -3718,7 +3718,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 285, "literal": "^2.4.2", @@ -3731,7 +3731,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 286, "literal": "^4.0.0", @@ -3744,7 +3744,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 287, "literal": "^1.0.0", @@ -3757,7 +3757,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 288, "literal": "^3.2.1", @@ -3770,7 +3770,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 289, "literal": "^1.0.5", @@ -3783,7 +3783,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 290, "literal": "^5.3.0", @@ -3796,7 +3796,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 291, "literal": "^3.0.0", @@ -3809,7 +3809,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 292, "literal": "^1.9.0", @@ -3822,7 +3822,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 293, "literal": "1.1.3", @@ -3835,7 +3835,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 294, "literal": "^2.0.1", @@ -3848,7 +3848,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 295, "literal": "^1.0.0", @@ -3861,7 +3861,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 296, "literal": "^4.0.0", @@ -3874,7 +3874,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 297, "literal": "^3.0.0", @@ -3887,7 +3887,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 298, "literal": "1.6.0", @@ -3900,7 +3900,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 299, "literal": "8.4.31", @@ -3913,7 +3913,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 300, "literal": "14.1.3", @@ -3926,7 +3926,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 301, "literal": "5.1.1", @@ -3939,7 +3939,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 302, "literal": "^4.2.11", @@ -3952,7 +3952,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 303, "literal": "0.5.2", @@ -3965,7 +3965,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 304, "literal": "^1.0.30001579", @@ -4149,7 +4149,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 318, "literal": "^2.4.0", @@ -4162,7 +4162,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 319, "literal": "0.0.1", @@ -4188,7 +4188,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 321, "literal": "^3.3.6", @@ -4201,7 +4201,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 322, "literal": "^1.0.0", @@ -4214,7 +4214,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 323, "literal": "^1.0.2", @@ -4227,7 +4227,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 324, "literal": "^1.1.0", @@ -4240,7 +4240,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 325, "literal": "^7.33.2", @@ -4253,7 +4253,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 326, "literal": "^2.28.1", @@ -4266,7 +4266,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 327, "literal": "^6.7.1", @@ -4279,7 +4279,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 328, "literal": "^1.3.3", @@ -4292,7 +4292,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 329, "literal": "14.1.3", @@ -4305,7 +4305,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 330, "literal": "^5.4.2 || ^6.0.0", @@ -4318,7 +4318,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 331, "literal": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705", @@ -4331,7 +4331,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 332, "literal": "^0.3.6", @@ -4344,7 +4344,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 333, "literal": "^3.5.2", @@ -4384,7 +4384,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 336, "literal": "^6.12.4", @@ -4397,7 +4397,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 337, "literal": "^0.4.1", @@ -4410,7 +4410,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 338, "literal": "^4.0.0", @@ -4423,7 +4423,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 339, "literal": "^4.3.2", @@ -4436,7 +4436,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 340, "literal": "^9.6.1", @@ -4449,7 +4449,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 341, "literal": "^5.2.0", @@ -4462,7 +4462,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 342, "literal": "^1.4.2", @@ -4475,7 +4475,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 343, "literal": "^2.0.2", @@ -4488,7 +4488,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 344, "literal": "^5.0.0", @@ -4501,7 +4501,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 345, "literal": "^13.19.0", @@ -4514,7 +4514,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 346, "literal": "^4.0.0", @@ -4527,7 +4527,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 347, "literal": "^4.1.0", @@ -4540,7 +4540,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 348, "literal": "^3.0.0", @@ -4553,7 +4553,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 349, "literal": "^1.4.0", @@ -4566,7 +4566,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 350, "literal": "^3.1.2", @@ -4579,7 +4579,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 351, "literal": "8.50.0", @@ -4592,7 +4592,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 352, "literal": "^0.9.3", @@ -4605,7 +4605,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 353, "literal": "^6.0.1", @@ -4618,7 +4618,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 354, "literal": "^0.2.0", @@ -4631,7 +4631,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 355, "literal": "^7.0.2", @@ -4644,7 +4644,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 356, "literal": "^6.0.2", @@ -4657,7 +4657,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 357, "literal": "^0.1.4", @@ -4670,7 +4670,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 358, "literal": "^7.2.2", @@ -4683,7 +4683,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 359, "literal": "^4.6.2", @@ -4696,7 +4696,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 360, "literal": "^3.0.3", @@ -4709,7 +4709,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 361, "literal": "^3.1.3", @@ -4722,7 +4722,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 362, "literal": "^1.4.0", @@ -4735,7 +4735,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 363, "literal": "^2.1.2", @@ -4748,7 +4748,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 364, "literal": "^1.2.8", @@ -4761,7 +4761,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 365, "literal": "^6.0.1", @@ -4774,7 +4774,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 366, "literal": "^3.4.3", @@ -4787,7 +4787,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 367, "literal": "^4.0.0", @@ -4800,7 +4800,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 368, "literal": "^4.6.1", @@ -4813,7 +4813,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 369, "literal": "^0.11.11", @@ -4826,7 +4826,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 370, "literal": "^4.2.0", @@ -4839,7 +4839,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 371, "literal": "^1.0.1", @@ -4852,7 +4852,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 372, "literal": "^1.0.1", @@ -4865,7 +4865,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 373, "literal": "^3.3.0", @@ -4891,7 +4891,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 375, "literal": "^2.0.2", @@ -4904,7 +4904,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 376, "literal": "^4.3.1", @@ -4917,7 +4917,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 377, "literal": "^3.0.5", @@ -4930,7 +4930,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 378, "literal": "^1.1.7", @@ -4943,7 +4943,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 379, "literal": "^1.0.0", @@ -4956,7 +4956,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 380, "literal": "0.0.1", @@ -4969,7 +4969,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 381, "literal": "^3.0.4", @@ -4982,7 +4982,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 382, "literal": "^3.2.9", @@ -4995,7 +4995,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 383, "literal": "^4.5.3", @@ -5008,7 +5008,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 384, "literal": "^3.0.2", @@ -5021,7 +5021,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 385, "literal": "^7.1.3", @@ -5034,7 +5034,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 386, "literal": "^1.0.0", @@ -5047,7 +5047,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 387, "literal": "^1.0.4", @@ -5060,7 +5060,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 388, "literal": "2", @@ -5073,7 +5073,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 389, "literal": "^3.1.1", @@ -5086,7 +5086,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 390, "literal": "^1.3.0", @@ -5099,7 +5099,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 391, "literal": "^1.0.0", @@ -5112,7 +5112,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 392, "literal": "^1.3.0", @@ -5125,7 +5125,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 393, "literal": "1", @@ -5138,7 +5138,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 394, "literal": "3.0.1", @@ -5151,7 +5151,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 395, "literal": "^6.12.4", @@ -5164,7 +5164,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 396, "literal": "^4.3.2", @@ -5177,7 +5177,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 397, "literal": "^9.6.0", @@ -5190,7 +5190,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 398, "literal": "^13.19.0", @@ -5203,7 +5203,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 399, "literal": "^5.2.0", @@ -5216,7 +5216,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 400, "literal": "^3.2.1", @@ -5229,7 +5229,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 401, "literal": "^4.1.0", @@ -5242,7 +5242,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 402, "literal": "^3.1.2", @@ -5255,7 +5255,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 403, "literal": "^3.1.1", @@ -5268,7 +5268,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 404, "literal": "^0.20.2", @@ -5281,7 +5281,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 405, "literal": "^8.9.0", @@ -5294,7 +5294,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 406, "literal": "^5.3.2", @@ -5307,7 +5307,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 407, "literal": "^3.4.1", @@ -5333,7 +5333,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 409, "literal": "^3.1.1", @@ -5346,7 +5346,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 410, "literal": "^2.0.0", @@ -5359,7 +5359,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 411, "literal": "^0.4.1", @@ -5372,7 +5372,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 412, "literal": "^4.2.2", @@ -5385,7 +5385,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 413, "literal": "^2.1.0", @@ -5398,7 +5398,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 414, "literal": "^4.3.0", @@ -5411,7 +5411,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 415, "literal": "^5.2.0", @@ -5424,7 +5424,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 416, "literal": "^5.2.0", @@ -5437,7 +5437,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 417, "literal": "^1.2.1", @@ -5450,7 +5450,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 418, "literal": "^0.1.3", @@ -5463,7 +5463,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 419, "literal": "^1.2.5", @@ -5476,7 +5476,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 420, "literal": "^0.4.0", @@ -5489,7 +5489,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 421, "literal": "^0.4.1", @@ -5502,7 +5502,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 422, "literal": "^2.0.6", @@ -5515,7 +5515,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 423, "literal": "^1.2.1", @@ -5528,7 +5528,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 424, "literal": "~0.4.0", @@ -5541,7 +5541,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 425, "literal": "^1.2.1", @@ -5554,7 +5554,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 426, "literal": "^2.0.2", @@ -5567,7 +5567,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 427, "literal": "^6.0.0", @@ -5580,7 +5580,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 428, "literal": "^4.0.0", @@ -5593,7 +5593,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 429, "literal": "^5.0.0", @@ -5606,7 +5606,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 430, "literal": "^3.0.2", @@ -5619,7 +5619,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 431, "literal": "^0.1.0", @@ -5632,7 +5632,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 432, "literal": "^5.1.0", @@ -5645,7 +5645,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 433, "literal": "^4.1.0", @@ -5658,7 +5658,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 434, "literal": "^7.1.0", @@ -5671,7 +5671,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 435, "literal": "^4.0.0", @@ -5684,7 +5684,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 436, "literal": "^4.3.4", @@ -5697,7 +5697,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 437, "literal": "^5.12.0", @@ -5710,7 +5710,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 438, "literal": "^2.7.4", @@ -5723,7 +5723,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 439, "literal": "^3.3.1", @@ -5736,7 +5736,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 440, "literal": "^4.5.0", @@ -5749,7 +5749,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 441, "literal": "^2.11.0", @@ -5762,7 +5762,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 442, "literal": "^4.0.3", @@ -5801,7 +5801,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 445, "literal": "^3.1.7", @@ -5814,7 +5814,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 446, "literal": "^1.2.3", @@ -5827,7 +5827,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 447, "literal": "^1.3.2", @@ -5840,7 +5840,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 448, "literal": "^1.3.2", @@ -5853,7 +5853,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 449, "literal": "^3.2.7", @@ -5866,7 +5866,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 450, "literal": "^2.1.0", @@ -5879,7 +5879,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 451, "literal": "^0.3.9", @@ -5892,7 +5892,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 452, "literal": "^2.8.0", @@ -5905,7 +5905,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 453, "literal": "^2.0.0", @@ -5918,7 +5918,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 454, "literal": "^2.13.1", @@ -5931,7 +5931,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 455, "literal": "^4.0.3", @@ -5944,7 +5944,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 456, "literal": "^3.1.2", @@ -5957,7 +5957,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 457, "literal": "^2.0.7", @@ -5970,7 +5970,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 458, "literal": "^1.0.1", @@ -5983,7 +5983,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 459, "literal": "^1.1.7", @@ -5996,7 +5996,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 460, "literal": "^6.3.1", @@ -6009,7 +6009,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 461, "literal": "^3.15.0", @@ -6035,7 +6035,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 463, "literal": "^0.0.29", @@ -6048,7 +6048,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 464, "literal": "^1.0.2", @@ -6061,7 +6061,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 465, "literal": "^1.2.6", @@ -6074,7 +6074,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 466, "literal": "^3.0.0", @@ -6087,7 +6087,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 467, "literal": "^1.2.0", @@ -6100,7 +6100,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 468, "literal": "^1.0.7", @@ -6113,7 +6113,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 469, "literal": "^1.2.1", @@ -6126,7 +6126,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 470, "literal": "^1.0.0", @@ -6139,7 +6139,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 471, "literal": "^1.3.0", @@ -6152,7 +6152,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 472, "literal": "^1.0.1", @@ -6165,7 +6165,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 473, "literal": "^1.0.0", @@ -6178,7 +6178,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 474, "literal": "^1.1.1", @@ -6191,7 +6191,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 475, "literal": "^1.0.0", @@ -6204,7 +6204,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 476, "literal": "^1.2.4", @@ -6217,7 +6217,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 477, "literal": "^1.3.0", @@ -6230,7 +6230,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 478, "literal": "^1.1.2", @@ -6243,7 +6243,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 479, "literal": "^1.0.1", @@ -6256,7 +6256,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 480, "literal": "^1.0.3", @@ -6269,7 +6269,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 481, "literal": "^2.0.0", @@ -6282,7 +6282,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 482, "literal": "^1.0.0", @@ -6295,7 +6295,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 483, "literal": "^1.3.0", @@ -6308,7 +6308,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 484, "literal": "^1.0.1", @@ -6321,7 +6321,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 485, "literal": "^1.1.3", @@ -6334,7 +6334,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 486, "literal": "^1.0.0", @@ -6347,7 +6347,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 487, "literal": "^1.3.0", @@ -6360,7 +6360,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 488, "literal": "^1.1.2", @@ -6373,7 +6373,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 489, "literal": "^1.2.4", @@ -6386,7 +6386,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 490, "literal": "^1.2.1", @@ -6399,7 +6399,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 491, "literal": "^1.1.4", @@ -6412,7 +6412,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 492, "literal": "^1.3.0", @@ -6425,7 +6425,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 493, "literal": "^1.1.2", @@ -6438,7 +6438,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 494, "literal": "^1.2.4", @@ -6451,7 +6451,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 495, "literal": "^1.0.1", @@ -6464,7 +6464,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 496, "literal": "^1.0.2", @@ -6477,7 +6477,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 497, "literal": "^1.0.7", @@ -6490,7 +6490,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 498, "literal": "^1.2.1", @@ -6503,7 +6503,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 499, "literal": "^1.23.2", @@ -6516,7 +6516,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 500, "literal": "^1.0.1", @@ -6529,7 +6529,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 501, "literal": "^1.0.3", @@ -6542,7 +6542,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 502, "literal": "^1.0.7", @@ -6555,7 +6555,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 503, "literal": "^1.0.7", @@ -6568,7 +6568,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 504, "literal": "^1.0.1", @@ -6581,7 +6581,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 505, "literal": "^1.0.1", @@ -6594,7 +6594,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 506, "literal": "^1.0.0", @@ -6607,7 +6607,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 507, "literal": "^1.0.0", @@ -6620,7 +6620,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 508, "literal": "^1.3.0", @@ -6633,7 +6633,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 509, "literal": "^1.0.0", @@ -6646,7 +6646,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 510, "literal": "^2.0.3", @@ -6659,7 +6659,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 511, "literal": "^1.2.1", @@ -6672,7 +6672,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 512, "literal": "^1.1.6", @@ -6685,7 +6685,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 513, "literal": "^1.2.4", @@ -6698,7 +6698,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 514, "literal": "^1.0.2", @@ -6711,7 +6711,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 515, "literal": "^1.0.3", @@ -6724,7 +6724,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 516, "literal": "^1.0.1", @@ -6737,7 +6737,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 517, "literal": "^1.0.2", @@ -6750,7 +6750,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 518, "literal": "^1.0.3", @@ -6763,7 +6763,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 519, "literal": "^1.0.3", @@ -6776,7 +6776,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 520, "literal": "^2.0.2", @@ -6789,7 +6789,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 521, "literal": "^1.0.7", @@ -6802,7 +6802,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 522, "literal": "^3.0.4", @@ -6815,7 +6815,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 523, "literal": "^1.2.7", @@ -6828,7 +6828,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 524, "literal": "^1.0.1", @@ -6841,7 +6841,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 525, "literal": "^2.0.3", @@ -6854,7 +6854,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 526, "literal": "^1.1.4", @@ -6867,7 +6867,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 527, "literal": "^1.0.3", @@ -6880,7 +6880,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 528, "literal": "^1.0.7", @@ -6893,7 +6893,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 529, "literal": "^1.1.13", @@ -6906,7 +6906,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 530, "literal": "^1.0.2", @@ -6919,7 +6919,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 531, "literal": "^1.13.1", @@ -6932,7 +6932,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 532, "literal": "^1.1.1", @@ -6945,7 +6945,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 533, "literal": "^4.1.5", @@ -6958,7 +6958,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 534, "literal": "^1.5.2", @@ -6971,7 +6971,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 535, "literal": "^1.1.2", @@ -6984,7 +6984,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 536, "literal": "^1.0.3", @@ -6997,7 +6997,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 537, "literal": "^1.2.9", @@ -7010,7 +7010,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 538, "literal": "^1.0.8", @@ -7023,7 +7023,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 539, "literal": "^1.0.8", @@ -7036,7 +7036,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 540, "literal": "^1.0.2", @@ -7049,7 +7049,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 541, "literal": "^1.0.1", @@ -7062,7 +7062,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 542, "literal": "^1.0.2", @@ -7075,7 +7075,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 543, "literal": "^1.0.6", @@ -7088,7 +7088,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 544, "literal": "^1.0.2", @@ -7101,7 +7101,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 545, "literal": "^1.1.15", @@ -7114,7 +7114,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 546, "literal": "^1.0.7", @@ -7127,7 +7127,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 547, "literal": "^1.0.7", @@ -7140,7 +7140,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 548, "literal": "^0.3.3", @@ -7153,7 +7153,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 549, "literal": "^1.0.1", @@ -7166,7 +7166,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 550, "literal": "^1.0.2", @@ -7179,7 +7179,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 551, "literal": "^1.0.3", @@ -7192,7 +7192,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 552, "literal": "^1.1.3", @@ -7205,7 +7205,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 553, "literal": "^1.0.0", @@ -7218,7 +7218,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 554, "literal": "^1.0.2", @@ -7231,7 +7231,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 555, "literal": "^1.0.2", @@ -7244,7 +7244,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 556, "literal": "^1.0.3", @@ -7257,7 +7257,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 557, "literal": "^1.0.2", @@ -7270,7 +7270,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 558, "literal": "^1.0.1", @@ -7283,7 +7283,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 559, "literal": "^1.1.0", @@ -7296,7 +7296,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 560, "literal": "^1.0.4", @@ -7309,7 +7309,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 561, "literal": "^1.0.5", @@ -7322,7 +7322,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 562, "literal": "^1.0.3", @@ -7335,7 +7335,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 563, "literal": "^1.0.2", @@ -7348,7 +7348,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 564, "literal": "^1.0.0", @@ -7361,7 +7361,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 565, "literal": "^1.0.0", @@ -7374,7 +7374,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 566, "literal": "^1.0.2", @@ -7387,7 +7387,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 567, "literal": "^1.0.0", @@ -7400,7 +7400,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 568, "literal": "^1.0.1", @@ -7413,7 +7413,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 569, "literal": "^1.0.7", @@ -7426,7 +7426,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 570, "literal": "^0.3.3", @@ -7439,7 +7439,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 571, "literal": "^1.0.1", @@ -7452,7 +7452,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 572, "literal": "^1.0.3", @@ -7465,7 +7465,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 573, "literal": "^1.1.13", @@ -7478,7 +7478,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 574, "literal": "^1.0.0", @@ -7491,7 +7491,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 575, "literal": "^1.1.14", @@ -7504,7 +7504,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 576, "literal": "^1.0.7", @@ -7517,7 +7517,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 577, "literal": "^1.0.7", @@ -7530,7 +7530,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 578, "literal": "^0.3.3", @@ -7543,7 +7543,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 579, "literal": "^1.0.1", @@ -7556,7 +7556,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 580, "literal": "^1.0.3", @@ -7569,7 +7569,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 581, "literal": "^1.1.13", @@ -7582,7 +7582,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 582, "literal": "^1.0.7", @@ -7595,7 +7595,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 583, "literal": "^0.3.3", @@ -7608,7 +7608,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 584, "literal": "^1.0.1", @@ -7621,7 +7621,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 585, "literal": "^1.0.3", @@ -7634,7 +7634,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 586, "literal": "^1.1.13", @@ -7647,7 +7647,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 587, "literal": "^1.0.7", @@ -7660,7 +7660,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 588, "literal": "^1.3.0", @@ -7673,7 +7673,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 589, "literal": "^1.1.13", @@ -7686,7 +7686,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 590, "literal": "^1.0.7", @@ -7699,7 +7699,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 591, "literal": "^1.2.1", @@ -7712,7 +7712,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 592, "literal": "^1.0.0", @@ -7725,7 +7725,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 593, "literal": "^1.0.7", @@ -7738,7 +7738,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 594, "literal": "^1.2.1", @@ -7751,7 +7751,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 595, "literal": "^1.0.0", @@ -7764,7 +7764,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 596, "literal": "^1.0.7", @@ -7777,7 +7777,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 597, "literal": "^1.2.1", @@ -7790,7 +7790,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 598, "literal": "^1.23.0", @@ -7803,7 +7803,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 599, "literal": "^1.0.0", @@ -7816,7 +7816,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 600, "literal": "^1.0.6", @@ -7829,7 +7829,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 601, "literal": "^1.3.0", @@ -7842,7 +7842,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 602, "literal": "^1.1.4", @@ -7855,7 +7855,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 603, "literal": "^1.0.2", @@ -7868,7 +7868,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 604, "literal": "^1.0.0", @@ -7881,7 +7881,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 605, "literal": "^1.0.7", @@ -7894,7 +7894,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 606, "literal": "^1.2.4", @@ -7907,7 +7907,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 607, "literal": "^1.0.3", @@ -7920,7 +7920,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 608, "literal": "^2.0.5", @@ -7933,7 +7933,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 609, "literal": "^1.0.6", @@ -7946,7 +7946,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 610, "literal": "^1.2.1", @@ -7959,7 +7959,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 611, "literal": "^1.3.0", @@ -7972,7 +7972,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 612, "literal": "^2.0.1", @@ -7985,7 +7985,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 613, "literal": "^1.1.4", @@ -7998,7 +7998,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 614, "literal": "^1.3.0", @@ -8011,7 +8011,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 615, "literal": "^1.2.3", @@ -8024,7 +8024,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 616, "literal": "^1.0.2", @@ -8037,7 +8037,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 617, "literal": "^1.0.5", @@ -8050,7 +8050,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 618, "literal": "^1.2.1", @@ -8063,7 +8063,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 619, "literal": "^1.0.3", @@ -8076,7 +8076,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 620, "literal": "^1.1.1", @@ -8089,7 +8089,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 621, "literal": "^1.0.2", @@ -8102,7 +8102,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 622, "literal": "^1.0.7", @@ -8115,7 +8115,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 623, "literal": "^1.1.13", @@ -8128,7 +8128,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 624, "literal": "^1.0.2", @@ -8141,7 +8141,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 625, "literal": "^1.2.1", @@ -8154,7 +8154,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 626, "literal": "^1.3.0", @@ -8167,7 +8167,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 627, "literal": "^2.0.0", @@ -8180,7 +8180,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 628, "literal": "^1.0.4", @@ -8193,7 +8193,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 629, "literal": "^1.0.7", @@ -8206,7 +8206,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 630, "literal": "^1.3.0", @@ -8219,7 +8219,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 631, "literal": "^1.2.4", @@ -8232,7 +8232,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 632, "literal": "^1.13.1", @@ -8245,7 +8245,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 633, "literal": "^1.2.1", @@ -8258,7 +8258,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 634, "literal": "^1.0.1", @@ -8271,7 +8271,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 635, "literal": "^1.0.5", @@ -8284,7 +8284,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 636, "literal": "^1.3.0", @@ -8297,7 +8297,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 637, "literal": "^1.2.4", @@ -8310,7 +8310,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 638, "literal": "^1.0.2", @@ -8323,7 +8323,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 639, "literal": "^1.2.0", @@ -8336,7 +8336,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 640, "literal": "^1.22.1", @@ -8349,7 +8349,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 641, "literal": "^1.2.3", @@ -8362,7 +8362,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 642, "literal": "^1.1.4", @@ -8375,7 +8375,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 643, "literal": "^1.0.1", @@ -8388,7 +8388,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 644, "literal": "^1.0.2", @@ -8401,7 +8401,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 645, "literal": "^1.0.0", @@ -8414,7 +8414,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 646, "literal": "^1.2.4", @@ -8427,7 +8427,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 647, "literal": "^1.0.2", @@ -8440,7 +8440,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 648, "literal": "^2.0.1", @@ -8453,7 +8453,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 649, "literal": "^1.0.6", @@ -8466,7 +8466,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 650, "literal": "^1.3.0", @@ -8479,7 +8479,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 651, "literal": "^1.0.1", @@ -8492,7 +8492,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 652, "literal": "^1.0.7", @@ -8505,7 +8505,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 653, "literal": "^1.3.0", @@ -8518,7 +8518,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 654, "literal": "^1.0.1", @@ -8531,7 +8531,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 655, "literal": "^1.0.6", @@ -8544,7 +8544,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 656, "literal": "^1.3.0", @@ -8557,7 +8557,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 657, "literal": "^1.0.1", @@ -8570,7 +8570,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 658, "literal": "^1.0.1", @@ -8583,7 +8583,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 659, "literal": "^1.0.5", @@ -8596,7 +8596,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 660, "literal": "^1.2.1", @@ -8609,7 +8609,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 661, "literal": "^1.22.3", @@ -8622,7 +8622,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 662, "literal": "^1.2.1", @@ -8635,7 +8635,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 663, "literal": "^1.2.3", @@ -8648,7 +8648,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 664, "literal": "^3.0.4", @@ -8661,7 +8661,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 665, "literal": "^1.0.2", @@ -8674,7 +8674,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 666, "literal": "^1.0.5", @@ -8687,7 +8687,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 667, "literal": "^3.0.4", @@ -8700,7 +8700,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 668, "literal": "^1.0.7", @@ -8713,7 +8713,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 669, "literal": "^1.2.1", @@ -8726,7 +8726,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 670, "literal": "^1.23.2", @@ -8739,7 +8739,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 671, "literal": "^1.0.0", @@ -8752,7 +8752,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 672, "literal": "^3.2.7", @@ -8765,7 +8765,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 673, "literal": "^2.1.1", @@ -8778,7 +8778,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 674, "literal": "^3.2.7", @@ -8791,7 +8791,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 675, "literal": "^2.13.0", @@ -8804,7 +8804,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 676, "literal": "^1.22.4", @@ -8817,7 +8817,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 677, "literal": "^2.0.2", @@ -8830,7 +8830,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 678, "literal": "^1.0.2", @@ -8843,7 +8843,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 679, "literal": "^1.2.0", @@ -8856,7 +8856,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 680, "literal": "^1.22.1", @@ -8869,7 +8869,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 681, "literal": "^1.0.0", @@ -8882,7 +8882,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 682, "literal": "^2.0.0", @@ -8895,7 +8895,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 683, "literal": "^1.0.2", @@ -8908,7 +8908,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 684, "literal": "^1.2.0", @@ -8921,7 +8921,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 685, "literal": "^1.22.1", @@ -8934,7 +8934,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 686, "literal": "^1.0.0", @@ -8947,7 +8947,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 687, "literal": "^1.0.7", @@ -8960,7 +8960,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 688, "literal": "^1.2.1", @@ -8973,7 +8973,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 689, "literal": "^1.23.2", @@ -8986,7 +8986,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 690, "literal": "^1.3.0", @@ -8999,7 +8999,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 691, "literal": "^1.0.0", @@ -9012,7 +9012,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 692, "literal": "^1.0.2", @@ -9025,7 +9025,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 693, "literal": "^1.0.7", @@ -9038,7 +9038,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 694, "literal": "^1.2.1", @@ -9051,7 +9051,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 695, "literal": "^1.23.2", @@ -9064,7 +9064,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 696, "literal": "^1.0.0", @@ -9077,7 +9077,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 697, "literal": "^1.2.4", @@ -9090,7 +9090,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 698, "literal": "^1.0.7", @@ -9103,7 +9103,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 699, "literal": "^1.0.0", @@ -9116,7 +9116,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 700, "literal": "^4.2.4", @@ -9129,7 +9129,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 701, "literal": "^2.2.0", @@ -9155,7 +9155,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 703, "literal": "^4.3.4", @@ -9168,7 +9168,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 704, "literal": "6.21.0", @@ -9181,7 +9181,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 705, "literal": "6.21.0", @@ -9194,7 +9194,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 706, "literal": "6.21.0", @@ -9207,7 +9207,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 707, "literal": "6.21.0", @@ -9233,7 +9233,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 709, "literal": "^4.3.4", @@ -9246,7 +9246,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 710, "literal": "^11.1.0", @@ -9259,7 +9259,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 711, "literal": "^7.5.4", @@ -9272,7 +9272,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 712, "literal": "^4.0.3", @@ -9285,7 +9285,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 713, "literal": "9.0.3", @@ -9298,7 +9298,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 714, "literal": "^1.0.1", @@ -9311,7 +9311,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 715, "literal": "6.21.0", @@ -9324,7 +9324,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 716, "literal": "6.21.0", @@ -9337,7 +9337,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 717, "literal": "^3.4.1", @@ -9350,7 +9350,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 718, "literal": "6.21.0", @@ -9376,7 +9376,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 720, "literal": "^2.0.1", @@ -9389,7 +9389,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 721, "literal": "^2.1.0", @@ -9402,7 +9402,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 722, "literal": "^3.0.1", @@ -9415,7 +9415,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 723, "literal": "^3.2.9", @@ -9428,7 +9428,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 724, "literal": "^5.2.0", @@ -9441,7 +9441,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 725, "literal": "^1.4.1", @@ -9454,7 +9454,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 726, "literal": "^3.0.0", @@ -9467,7 +9467,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 727, "literal": "^4.0.0", @@ -9480,7 +9480,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 728, "literal": "6.21.0", @@ -9493,7 +9493,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 729, "literal": "6.21.0", @@ -9506,7 +9506,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 730, "literal": "10.3.10", @@ -9519,7 +9519,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 731, "literal": "^7.23.2", @@ -9532,7 +9532,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 732, "literal": "^5.3.0", @@ -9545,7 +9545,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 733, "literal": "^3.1.7", @@ -9558,7 +9558,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 734, "literal": "^1.3.2", @@ -9571,7 +9571,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 735, "literal": "^0.0.8", @@ -9584,7 +9584,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 736, "literal": "=4.7.0", @@ -9597,7 +9597,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 737, "literal": "^3.2.1", @@ -9610,7 +9610,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 738, "literal": "^1.0.8", @@ -9623,7 +9623,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 739, "literal": "^9.2.2", @@ -9636,7 +9636,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 740, "literal": "^1.0.15", @@ -9649,7 +9649,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 741, "literal": "^2.0.0", @@ -9662,7 +9662,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 742, "literal": "^3.3.5", @@ -9675,7 +9675,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 743, "literal": "^1.0.9", @@ -9688,7 +9688,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 744, "literal": "^3.1.2", @@ -9701,7 +9701,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 745, "literal": "^1.1.7", @@ -9714,7 +9714,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 746, "literal": "^2.0.7", @@ -9740,7 +9740,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 748, "literal": "^1.0.7", @@ -9753,7 +9753,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 749, "literal": "^1.2.1", @@ -9766,7 +9766,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 750, "literal": "^1.0.0", @@ -9779,7 +9779,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 751, "literal": "^0.3.20", @@ -9792,7 +9792,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 752, "literal": "^3.1.6", @@ -9805,7 +9805,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 753, "literal": "^1.3.1", @@ -9818,7 +9818,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 754, "literal": "^4.1.4", @@ -9831,7 +9831,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 755, "literal": "^1.1.6", @@ -9844,7 +9844,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 756, "literal": "^1.0.7", @@ -9857,7 +9857,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 757, "literal": "^1.2.1", @@ -9870,7 +9870,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 758, "literal": "^1.23.3", @@ -9883,7 +9883,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 759, "literal": "^1.3.0", @@ -9896,7 +9896,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 760, "literal": "^2.0.3", @@ -9909,7 +9909,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 761, "literal": "^1.1.2", @@ -9922,7 +9922,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 762, "literal": "^1.2.4", @@ -9935,7 +9935,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 763, "literal": "^1.0.3", @@ -9948,7 +9948,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 764, "literal": "^1.0.2", @@ -9961,7 +9961,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 765, "literal": "^1.0.3", @@ -9974,7 +9974,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 766, "literal": "^1.0.3", @@ -9987,7 +9987,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 767, "literal": "^1.0.7", @@ -10000,7 +10000,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 768, "literal": "^1.1.2", @@ -10013,7 +10013,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 769, "literal": "^1.1.2", @@ -10026,7 +10026,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 770, "literal": "^1.2.1", @@ -10039,7 +10039,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 771, "literal": "^1.2.1", @@ -10052,7 +10052,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 772, "literal": "^1.0.3", @@ -10065,7 +10065,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 773, "literal": "^1.0.4", @@ -10078,7 +10078,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 774, "literal": "^2.0.1", @@ -10091,7 +10091,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 775, "literal": "^1.0.7", @@ -10104,7 +10104,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 776, "literal": "^1.2.1", @@ -10117,7 +10117,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 777, "literal": "^1.23.1", @@ -10130,7 +10130,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 778, "literal": "^1.3.0", @@ -10143,7 +10143,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 779, "literal": "^1.2.4", @@ -10156,7 +10156,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 780, "literal": "^1.0.3", @@ -10169,7 +10169,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 781, "literal": "^1.1.3", @@ -10182,7 +10182,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 782, "literal": "^1.1.5", @@ -10195,7 +10195,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 783, "literal": "^1.0.0", @@ -10208,7 +10208,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 784, "literal": "^2.0.0", @@ -10221,7 +10221,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 785, "literal": "^1.0.5", @@ -10234,7 +10234,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 786, "literal": "^1.0.2", @@ -10247,7 +10247,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 787, "literal": "^1.0.10", @@ -10260,7 +10260,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 788, "literal": "^1.1.4", @@ -10273,7 +10273,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 789, "literal": "^1.0.2", @@ -10286,7 +10286,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 790, "literal": "^2.0.5", @@ -10299,7 +10299,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 791, "literal": "^1.0.2", @@ -10312,7 +10312,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 792, "literal": "^1.0.1", @@ -10325,7 +10325,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 793, "literal": "^1.1.9", @@ -10338,7 +10338,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 794, "literal": "^2.0.3", @@ -10351,7 +10351,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 795, "literal": "^2.0.3", @@ -10364,7 +10364,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 796, "literal": "^2.0.2", @@ -10377,7 +10377,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 797, "literal": "^2.0.3", @@ -10390,7 +10390,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 798, "literal": "^1.0.7", @@ -10403,7 +10403,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 799, "literal": "^1.2.4", @@ -10416,7 +10416,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 800, "literal": "^1.0.0", @@ -10429,7 +10429,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 801, "literal": "^1.0.2", @@ -10442,7 +10442,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 802, "literal": "^1.0.0", @@ -10455,7 +10455,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 803, "literal": "^2.0.3", @@ -10468,7 +10468,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 804, "literal": "^2.0.3", @@ -10481,7 +10481,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 805, "literal": "^0.14.0", @@ -10494,7 +10494,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 806, "literal": "^3.1.8", @@ -10507,7 +10507,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 807, "literal": "^1.2.5", @@ -10520,7 +10520,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 808, "literal": "^1.3.2", @@ -10533,7 +10533,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 809, "literal": "^1.1.2", @@ -10546,7 +10546,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 810, "literal": "^1.1.3", @@ -10559,7 +10559,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 811, "literal": "^2.1.0", @@ -10572,7 +10572,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 812, "literal": "^1.0.19", @@ -10585,7 +10585,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 813, "literal": "^5.3.0", @@ -10598,7 +10598,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 814, "literal": "^2.4.1 || ^3.0.0", @@ -10611,7 +10611,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 815, "literal": "^3.1.2", @@ -10624,7 +10624,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 816, "literal": "^1.1.8", @@ -10637,7 +10637,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 817, "literal": "^2.0.8", @@ -10650,7 +10650,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 818, "literal": "^1.1.4", @@ -10663,7 +10663,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 819, "literal": "^1.2.0", @@ -10676,7 +10676,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 820, "literal": "^15.8.1", @@ -10689,7 +10689,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 821, "literal": "^2.0.0-next.5", @@ -10702,7 +10702,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 822, "literal": "^6.3.1", @@ -10715,7 +10715,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 823, "literal": "^4.0.11", @@ -10741,7 +10741,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 825, "literal": "^1.0.7", @@ -10754,7 +10754,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 826, "literal": "^1.2.1", @@ -10767,7 +10767,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 827, "literal": "^1.23.2", @@ -10780,7 +10780,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 828, "literal": "^1.3.0", @@ -10793,7 +10793,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 829, "literal": "^1.0.0", @@ -10806,7 +10806,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 830, "literal": "^1.2.4", @@ -10819,7 +10819,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 831, "literal": "^1.0.1", @@ -10832,7 +10832,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 832, "literal": "^1.0.3", @@ -10845,7 +10845,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 833, "literal": "^1.0.7", @@ -10858,7 +10858,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 834, "literal": "^1.5.2", @@ -10871,7 +10871,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 835, "literal": "^2.0.2", @@ -10884,7 +10884,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 836, "literal": "^1.0.6", @@ -10897,7 +10897,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 837, "literal": "^2.13.0", @@ -10910,7 +10910,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 838, "literal": "^1.0.7", @@ -10923,7 +10923,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 839, "literal": "^1.0.0", @@ -10936,7 +10936,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 840, "literal": "^1.4.0", @@ -10949,7 +10949,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 841, "literal": "^4.1.1", @@ -10962,7 +10962,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 842, "literal": "^16.13.1", @@ -10975,7 +10975,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 843, "literal": "^1.2.1", @@ -10988,7 +10988,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 844, "literal": "^1.23.2", @@ -11001,7 +11001,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 845, "literal": "^1.0.0", @@ -11014,7 +11014,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 846, "literal": "^1.0.7", @@ -11027,7 +11027,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 847, "literal": "^1.2.1", @@ -11040,7 +11040,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 848, "literal": "^1.23.3", @@ -11053,7 +11053,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 849, "literal": "^1.3.0", @@ -11066,7 +11066,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 850, "literal": "^1.0.2", @@ -11079,7 +11079,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 851, "literal": "^1.0.2", @@ -11092,7 +11092,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 852, "literal": "^1.2.0", @@ -11105,7 +11105,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 853, "literal": "^1.22.1", @@ -11118,7 +11118,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 854, "literal": "^1.0.0", @@ -11131,7 +11131,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 855, "literal": "^1.0.7", @@ -11144,7 +11144,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 856, "literal": "^1.2.1", @@ -11157,7 +11157,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 857, "literal": "^1.23.2", @@ -11170,7 +11170,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 858, "literal": "^1.3.0", @@ -11183,7 +11183,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 859, "literal": "^1.0.0", @@ -11196,7 +11196,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 860, "literal": "^1.0.2", @@ -11209,7 +11209,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 861, "literal": "~8.5.10", @@ -11222,7 +11222,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 862, "literal": "~20.12.8", @@ -11235,7 +11235,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 863, "literal": "*", @@ -11248,7 +11248,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 864, "literal": "^4.21.10", @@ -11261,7 +11261,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 865, "literal": "^1.0.30001538", @@ -11274,7 +11274,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 866, "literal": "^4.3.6", @@ -11287,7 +11287,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 867, "literal": "^0.1.2", @@ -11300,7 +11300,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 868, "literal": "^1.0.0", @@ -11313,7 +11313,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 869, "literal": "^4.2.0", @@ -11339,7 +11339,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 871, "literal": "^1.0.30001587", @@ -11352,7 +11352,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 872, "literal": "^1.4.668", @@ -11365,7 +11365,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 873, "literal": "^2.0.14", @@ -11378,7 +11378,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 874, "literal": "^1.0.13", @@ -11391,7 +11391,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 875, "literal": "^3.1.2", @@ -11404,7 +11404,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 876, "literal": "^1.0.1", @@ -11430,7 +11430,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 878, "literal": "*", @@ -11443,7 +11443,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 879, "literal": "*", @@ -11456,7 +11456,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 880, "literal": "*", @@ -11469,7 +11469,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 881, "literal": "^3.0.2", diff --git a/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap b/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap index 536715c42b..6bacb22ab5 100644 --- a/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap @@ -5,7 +5,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "dependencies": [ { "behavior": { - "normal": true, + "prod": true, }, "id": 0, "literal": "20.7.0", @@ -18,7 +18,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 1, "literal": "18.2.22", @@ -31,7 +31,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 2, "literal": "18.2.7", @@ -44,7 +44,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 3, "literal": "10.4.16", @@ -57,7 +57,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 4, "literal": "^1.0.3", @@ -70,7 +70,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 5, "literal": "8.50.0", @@ -83,7 +83,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 6, "literal": "14.1.3", @@ -96,7 +96,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 7, "literal": "14.1.3", @@ -109,7 +109,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 8, "literal": "8.4.30", @@ -122,7 +122,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 9, "literal": "22.12.0", @@ -135,7 +135,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 10, "literal": "18.2.0", @@ -148,7 +148,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 11, "literal": "18.2.0", @@ -161,7 +161,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 12, "literal": "3.3.3", @@ -174,7 +174,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 13, "literal": "5.2.2", @@ -187,7 +187,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 14, "literal": "^5.0.2", @@ -200,7 +200,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 15, "literal": "^1.1.3", @@ -213,7 +213,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 16, "literal": "^1.18.2", @@ -226,7 +226,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 17, "literal": "^4.0.3", @@ -239,7 +239,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 18, "literal": "^8.4.23", @@ -252,7 +252,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 19, "literal": "^1.22.2", @@ -265,7 +265,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 20, "literal": "^3.32.0", @@ -278,7 +278,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 21, "literal": "^3.5.3", @@ -291,7 +291,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 22, "literal": "^3.2.12", @@ -304,7 +304,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 23, "literal": "^2.1.0", @@ -317,7 +317,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 24, "literal": "^1.2.2", @@ -330,7 +330,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 25, "literal": "^4.0.5", @@ -343,7 +343,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 26, "literal": "^1.0.0", @@ -356,7 +356,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 27, "literal": "^4.0.1", @@ -369,7 +369,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 28, "literal": "^6.0.2", @@ -382,7 +382,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 29, "literal": "^3.0.0", @@ -395,7 +395,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 30, "literal": "^3.0.0", @@ -408,7 +408,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 31, "literal": "^15.1.0", @@ -421,7 +421,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 32, "literal": "^6.0.1", @@ -434,7 +434,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 33, "literal": "^5.2.0", @@ -447,7 +447,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 34, "literal": "^4.0.1", @@ -460,7 +460,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 35, "literal": "^6.0.11", @@ -473,7 +473,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 36, "literal": "^3.0.0", @@ -486,7 +486,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 37, "literal": "^1.0.2", @@ -499,7 +499,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 38, "literal": "^2.3.4", @@ -512,7 +512,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 39, "literal": "^3.0.0", @@ -553,7 +553,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 42, "literal": "^3.3.6", @@ -566,7 +566,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 43, "literal": "^1.0.0", @@ -579,7 +579,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 44, "literal": "^1.0.2", @@ -592,7 +592,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 45, "literal": "^6.0.11", @@ -618,7 +618,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 47, "literal": "^4.0.0", @@ -631,7 +631,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 48, "literal": "^1.0.0", @@ -644,7 +644,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 49, "literal": "^1.1.7", @@ -670,7 +670,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 51, "literal": "^2.13.0", @@ -683,7 +683,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 52, "literal": "^1.0.7", @@ -696,7 +696,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 53, "literal": "^1.0.0", @@ -709,7 +709,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 54, "literal": "^2.0.0", @@ -722,7 +722,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 55, "literal": "^1.1.2", @@ -735,7 +735,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 56, "literal": "^2.3.0", @@ -748,7 +748,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 57, "literal": "^4.0.3", @@ -761,7 +761,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 58, "literal": "^2.1.1", @@ -774,7 +774,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 59, "literal": "^2.0.1", @@ -800,7 +800,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 61, "literal": "^3.0.3", @@ -813,7 +813,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 62, "literal": "^2.3.1", @@ -826,7 +826,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 63, "literal": "^7.1.1", @@ -839,7 +839,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 64, "literal": "^5.0.1", @@ -852,7 +852,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 65, "literal": "^7.0.0", @@ -865,7 +865,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 66, "literal": "^2.0.2", @@ -878,7 +878,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 67, "literal": "^1.2.3", @@ -891,7 +891,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 68, "literal": "^5.1.2", @@ -904,7 +904,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 69, "literal": "^1.3.0", @@ -917,7 +917,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 70, "literal": "^4.0.4", @@ -930,7 +930,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 71, "literal": "^4.0.1", @@ -943,7 +943,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 72, "literal": "2.1.5", @@ -956,7 +956,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 73, "literal": "^1.6.0", @@ -969,7 +969,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 74, "literal": "^1.0.4", @@ -982,7 +982,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 75, "literal": "2.0.5", @@ -995,7 +995,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 76, "literal": "^1.1.9", @@ -1008,7 +1008,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 77, "literal": "^1.2.2", @@ -1021,7 +1021,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 78, "literal": "~3.1.2", @@ -1034,7 +1034,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 79, "literal": "~3.0.2", @@ -1047,7 +1047,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 80, "literal": "~5.1.2", @@ -1060,7 +1060,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 81, "literal": "~2.1.0", @@ -1073,7 +1073,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 82, "literal": "~4.0.1", @@ -1086,7 +1086,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 83, "literal": "~3.0.0", @@ -1099,7 +1099,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 84, "literal": "~3.6.0", @@ -1125,7 +1125,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 86, "literal": "^2.2.1", @@ -1138,7 +1138,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 87, "literal": "^2.0.0", @@ -1151,7 +1151,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 88, "literal": "^3.0.0", @@ -1164,7 +1164,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 89, "literal": "^2.0.4", @@ -1177,7 +1177,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 90, "literal": "^0.3.2", @@ -1190,7 +1190,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 91, "literal": "^4.0.0", @@ -1203,7 +1203,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 92, "literal": "^10.3.10", @@ -1216,7 +1216,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 93, "literal": "^1.1.6", @@ -1229,7 +1229,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 94, "literal": "^2.7.0", @@ -1242,7 +1242,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 95, "literal": "^4.0.1", @@ -1255,7 +1255,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 96, "literal": "^0.1.9", @@ -1268,7 +1268,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 97, "literal": "^1.0.0", @@ -1281,7 +1281,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 98, "literal": "^4.0.1", @@ -1294,7 +1294,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 99, "literal": "^1.0.0", @@ -1307,7 +1307,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 100, "literal": ">= 3.1.0 < 4", @@ -1320,7 +1320,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 101, "literal": "^1.0.0", @@ -1333,7 +1333,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 102, "literal": "^3.1.0", @@ -1346,7 +1346,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 103, "literal": "^2.3.5", @@ -1359,7 +1359,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 104, "literal": "^9.0.1", @@ -1372,7 +1372,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 105, "literal": "^5.0.0 || ^6.0.2 || ^7.0.0", @@ -1385,7 +1385,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 106, "literal": "^1.10.1", @@ -1398,7 +1398,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 107, "literal": "^10.2.0", @@ -1411,7 +1411,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 108, "literal": "^5.0.0 || ^6.0.2 || ^7.0.0", @@ -1424,7 +1424,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 109, "literal": "^2.0.1", @@ -1437,7 +1437,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 110, "literal": "^1.0.0", @@ -1450,7 +1450,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 111, "literal": "^8.0.2", @@ -1476,7 +1476,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 113, "literal": "^5.1.2", @@ -1489,7 +1489,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 114, "is_alias": true, @@ -1503,7 +1503,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 115, "literal": "^7.0.1", @@ -1516,7 +1516,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 116, "is_alias": true, @@ -1530,7 +1530,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 117, "literal": "^8.1.0", @@ -1543,7 +1543,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 118, "is_alias": true, @@ -1557,7 +1557,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 119, "literal": "^4.0.0", @@ -1570,7 +1570,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 120, "literal": "^4.1.0", @@ -1583,7 +1583,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 121, "literal": "^6.0.0", @@ -1596,7 +1596,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 122, "literal": "^5.0.1", @@ -1609,7 +1609,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 123, "literal": "^8.0.0", @@ -1622,7 +1622,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 124, "literal": "^3.0.0", @@ -1635,7 +1635,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 125, "literal": "^6.0.1", @@ -1648,7 +1648,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 126, "literal": "^2.0.1", @@ -1661,7 +1661,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 127, "literal": "~1.1.4", @@ -1674,7 +1674,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 128, "literal": "^6.1.0", @@ -1687,7 +1687,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 129, "literal": "^5.0.1", @@ -1700,7 +1700,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 130, "literal": "^7.0.1", @@ -1713,7 +1713,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 131, "literal": "^6.0.1", @@ -1726,7 +1726,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 132, "literal": "^0.2.0", @@ -1739,7 +1739,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 133, "literal": "^9.2.2", @@ -1752,7 +1752,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 134, "literal": "^7.0.1", @@ -1765,7 +1765,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 135, "literal": "^7.0.0", @@ -1778,7 +1778,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 136, "literal": "^4.0.1", @@ -1791,7 +1791,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 137, "literal": "^3.1.0", @@ -1804,7 +1804,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 138, "literal": "^2.0.0", @@ -1817,7 +1817,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 139, "literal": "^2.0.1", @@ -1830,7 +1830,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 140, "literal": "^2.0.0", @@ -1843,7 +1843,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 141, "literal": "^3.0.0", @@ -1856,7 +1856,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 142, "literal": "^1.2.1", @@ -1869,7 +1869,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 143, "literal": "^1.4.10", @@ -1882,7 +1882,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 144, "literal": "^0.3.24", @@ -1895,7 +1895,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 145, "literal": "^3.1.0", @@ -1908,7 +1908,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 146, "literal": "^1.4.14", @@ -1921,7 +1921,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 147, "literal": "^0.23.0", @@ -1934,7 +1934,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 148, "literal": "^1.1.0", @@ -1960,7 +1960,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 150, "literal": "^1.1.0", @@ -1973,7 +1973,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 151, "literal": "^3.0.0 || ^4.0.0", @@ -1986,7 +1986,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 152, "literal": "^1.1.0", @@ -1999,7 +1999,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 153, "literal": "9.0.0", @@ -2012,7 +2012,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 154, "literal": "22.12.0", @@ -2025,7 +2025,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 155, "literal": "2.2.3", @@ -2038,7 +2038,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 156, "literal": "0.0.1299070", @@ -2051,7 +2051,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 157, "literal": "4.3.4", @@ -2064,7 +2064,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 158, "literal": "2.0.1", @@ -2077,7 +2077,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 159, "literal": "2.0.3", @@ -2090,7 +2090,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 160, "literal": "6.4.0", @@ -2103,7 +2103,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 161, "literal": "3.0.5", @@ -2116,7 +2116,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 162, "literal": "1.4.3", @@ -2129,7 +2129,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 163, "literal": "17.7.2", @@ -2142,7 +2142,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 164, "literal": "7.6.0", @@ -2155,7 +2155,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 165, "literal": "^6.0.0", @@ -2168,7 +2168,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 166, "literal": "^4.0.0", @@ -2181,7 +2181,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 167, "literal": "^8.0.1", @@ -2194,7 +2194,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 168, "literal": "^3.1.1", @@ -2207,7 +2207,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 169, "literal": "^2.0.5", @@ -2220,7 +2220,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 170, "literal": "^2.1.1", @@ -2233,7 +2233,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 171, "literal": "^4.2.3", @@ -2246,7 +2246,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 172, "literal": "^5.0.5", @@ -2259,7 +2259,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 173, "literal": "^21.1.1", @@ -2272,7 +2272,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 174, "literal": "^4.2.0", @@ -2285,7 +2285,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 175, "literal": "^6.0.1", @@ -2298,7 +2298,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 176, "literal": "^7.0.0", @@ -2311,7 +2311,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 177, "literal": "^5.2.1", @@ -2324,7 +2324,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 178, "literal": "^2.3.8", @@ -2337,7 +2337,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 179, "literal": "^1.3.1", @@ -2350,7 +2350,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 180, "literal": "^1.1.13", @@ -2363,7 +2363,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 181, "literal": "^3.0.0", @@ -2376,7 +2376,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 182, "literal": "^3.1.5", @@ -2415,7 +2415,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 185, "literal": "^2.1.0", @@ -2428,7 +2428,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 186, "literal": "^2.0.0", @@ -2441,7 +2441,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 187, "literal": "^2.0.0", @@ -2454,7 +2454,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 188, "literal": "^2.0.0", @@ -2467,7 +2467,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 189, "literal": "^2.18.0", @@ -2480,7 +2480,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 190, "literal": "^1.3.2", @@ -2493,7 +2493,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 191, "literal": "^1.0.1", @@ -2506,7 +2506,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 192, "literal": "^1.1.0", @@ -2532,7 +2532,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 194, "literal": "^1.6.4", @@ -2545,7 +2545,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 195, "literal": "^1.6.4", @@ -2558,7 +2558,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 196, "literal": "^1.2.0", @@ -2571,7 +2571,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 197, "literal": "^2.15.0", @@ -2584,7 +2584,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 198, "literal": "^1.1.0", @@ -2597,7 +2597,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 199, "literal": "^1.3.1", @@ -2610,7 +2610,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 200, "literal": "1", @@ -2623,7 +2623,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 201, "literal": "^1.4.0", @@ -2636,7 +2636,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 202, "literal": "^7.0.2", @@ -2649,7 +2649,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 203, "literal": "^4.3.4", @@ -2662,7 +2662,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 204, "literal": "^7.0.1", @@ -2675,7 +2675,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 205, "literal": "^7.0.3", @@ -2688,7 +2688,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 206, "literal": "^7.14.1", @@ -2701,7 +2701,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 207, "literal": "^7.0.1", @@ -2714,7 +2714,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 208, "literal": "^1.1.0", @@ -2727,7 +2727,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 209, "literal": "^8.0.2", @@ -2740,7 +2740,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 210, "literal": "^7.1.1", @@ -2753,7 +2753,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 211, "literal": "^4.3.4", @@ -2766,7 +2766,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 212, "literal": "^2.7.1", @@ -2779,7 +2779,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 213, "literal": "^9.0.5", @@ -2792,7 +2792,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 214, "literal": "^4.2.0", @@ -2805,7 +2805,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 215, "literal": "1.1.0", @@ -2818,7 +2818,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 216, "literal": "^1.1.3", @@ -2831,7 +2831,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 217, "literal": "2.1.2", @@ -2844,7 +2844,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 218, "literal": "^4.3.4", @@ -2857,7 +2857,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 219, "literal": "^0.23.0", @@ -2870,7 +2870,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 220, "literal": "^7.0.2", @@ -2883,7 +2883,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 221, "literal": "^4.3.4", @@ -2896,7 +2896,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 222, "literal": "^6.0.1", @@ -2909,7 +2909,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 223, "literal": "^7.0.0", @@ -2922,7 +2922,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 224, "literal": "^7.0.2", @@ -2935,7 +2935,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 225, "literal": "^7.0.0", @@ -2948,7 +2948,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 226, "literal": "^8.0.2", @@ -2961,7 +2961,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 227, "literal": "^5.0.0", @@ -2974,7 +2974,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 228, "literal": "^2.0.2", @@ -2987,7 +2987,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 229, "literal": "^0.13.4", @@ -3000,7 +3000,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 230, "literal": "^2.1.0", @@ -3013,7 +3013,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 231, "literal": "^4.0.1", @@ -3026,7 +3026,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 232, "literal": "^5.2.0", @@ -3039,7 +3039,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 233, "literal": "^2.0.2", @@ -3052,7 +3052,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 234, "literal": "^4.0.1", @@ -3078,7 +3078,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 236, "literal": "^2.0.1", @@ -3091,7 +3091,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 237, "literal": "^7.0.2", @@ -3104,7 +3104,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 238, "literal": "4", @@ -3117,7 +3117,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 239, "literal": "^7.1.0", @@ -3130,7 +3130,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 240, "literal": "^4.3.4", @@ -3143,7 +3143,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 241, "literal": "^5.0.2", @@ -3156,7 +3156,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 242, "literal": "^6.0.2", @@ -3169,7 +3169,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 243, "literal": "^4.3.4", @@ -3182,7 +3182,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 244, "literal": "^11.2.0", @@ -3195,7 +3195,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 245, "literal": "^4.2.0", @@ -3208,7 +3208,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 246, "literal": "^6.0.1", @@ -3221,7 +3221,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 247, "literal": "^2.0.0", @@ -3234,7 +3234,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 248, "literal": "^2.0.0", @@ -3260,7 +3260,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 250, "literal": "^4.1.1", @@ -3273,7 +3273,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 251, "literal": "^5.1.0", @@ -3286,7 +3286,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 252, "literal": "^2.10.0", @@ -3312,7 +3312,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 254, "literal": "*", @@ -3325,7 +3325,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 255, "literal": "~5.26.4", @@ -3338,7 +3338,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 256, "literal": "~1.1.0", @@ -3351,7 +3351,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 257, "literal": "~0.2.3", @@ -3364,7 +3364,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 258, "literal": "~1.2.0", @@ -3377,7 +3377,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 259, "literal": "^3.0.0", @@ -3390,7 +3390,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 260, "literal": "2.1.2", @@ -3403,7 +3403,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 261, "literal": "2.2.3", @@ -3416,7 +3416,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 262, "literal": "0.5.24", @@ -3429,7 +3429,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 263, "literal": "4.3.5", @@ -3442,7 +3442,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 264, "literal": "0.0.1299070", @@ -3455,7 +3455,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 265, "literal": "8.17.1", @@ -3496,7 +3496,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 268, "literal": "3.0.1", @@ -3509,7 +3509,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 269, "literal": "10.0.0", @@ -3522,7 +3522,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 270, "literal": "3.23.8", @@ -3548,7 +3548,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 272, "literal": "^2.2.1", @@ -3561,7 +3561,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 273, "literal": "^3.3.0", @@ -3574,7 +3574,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 274, "literal": "^4.1.0", @@ -3587,7 +3587,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 275, "literal": "^5.2.0", @@ -3614,7 +3614,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 277, "literal": "^7.0.0", @@ -3627,7 +3627,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 278, "literal": "^1.3.1", @@ -3640,7 +3640,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 279, "literal": "^2.3.0", @@ -3653,7 +3653,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 280, "literal": "^1.1.6", @@ -3666,7 +3666,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 281, "literal": "^0.2.1", @@ -3679,7 +3679,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 282, "literal": "^7.24.7", @@ -3692,7 +3692,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 283, "literal": "^1.0.0", @@ -3705,7 +3705,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 284, "literal": "^7.24.7", @@ -3718,7 +3718,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 285, "literal": "^2.4.2", @@ -3731,7 +3731,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 286, "literal": "^4.0.0", @@ -3744,7 +3744,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 287, "literal": "^1.0.0", @@ -3757,7 +3757,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 288, "literal": "^3.2.1", @@ -3770,7 +3770,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 289, "literal": "^1.0.5", @@ -3783,7 +3783,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 290, "literal": "^5.3.0", @@ -3796,7 +3796,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 291, "literal": "^3.0.0", @@ -3809,7 +3809,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 292, "literal": "^1.9.0", @@ -3822,7 +3822,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 293, "literal": "1.1.3", @@ -3835,7 +3835,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 294, "literal": "^2.0.1", @@ -3848,7 +3848,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 295, "literal": "^1.0.0", @@ -3861,7 +3861,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 296, "literal": "^4.0.0", @@ -3874,7 +3874,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 297, "literal": "^3.0.0", @@ -3887,7 +3887,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 298, "literal": "1.6.0", @@ -3900,7 +3900,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 299, "literal": "8.4.31", @@ -3913,7 +3913,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 300, "literal": "14.1.3", @@ -3926,7 +3926,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 301, "literal": "5.1.1", @@ -3939,7 +3939,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 302, "literal": "^4.2.11", @@ -3952,7 +3952,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 303, "literal": "0.5.2", @@ -3965,7 +3965,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 304, "literal": "^1.0.30001579", @@ -4149,7 +4149,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 318, "literal": "^2.4.0", @@ -4162,7 +4162,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 319, "literal": "0.0.1", @@ -4188,7 +4188,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 321, "literal": "^3.3.6", @@ -4201,7 +4201,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 322, "literal": "^1.0.0", @@ -4214,7 +4214,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 323, "literal": "^1.0.2", @@ -4227,7 +4227,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 324, "literal": "^1.1.0", @@ -4240,7 +4240,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 325, "literal": "^7.33.2", @@ -4253,7 +4253,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 326, "literal": "^2.28.1", @@ -4266,7 +4266,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 327, "literal": "^6.7.1", @@ -4279,7 +4279,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 328, "literal": "^1.3.3", @@ -4292,7 +4292,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 329, "literal": "14.1.3", @@ -4305,7 +4305,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 330, "literal": "^5.4.2 || ^6.0.0", @@ -4318,7 +4318,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 331, "literal": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705", @@ -4331,7 +4331,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 332, "literal": "^0.3.6", @@ -4344,7 +4344,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 333, "literal": "^3.5.2", @@ -4384,7 +4384,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 336, "literal": "^6.12.4", @@ -4397,7 +4397,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 337, "literal": "^0.4.1", @@ -4410,7 +4410,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 338, "literal": "^4.0.0", @@ -4423,7 +4423,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 339, "literal": "^4.3.2", @@ -4436,7 +4436,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 340, "literal": "^9.6.1", @@ -4449,7 +4449,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 341, "literal": "^5.2.0", @@ -4462,7 +4462,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 342, "literal": "^1.4.2", @@ -4475,7 +4475,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 343, "literal": "^2.0.2", @@ -4488,7 +4488,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 344, "literal": "^5.0.0", @@ -4501,7 +4501,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 345, "literal": "^13.19.0", @@ -4514,7 +4514,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 346, "literal": "^4.0.0", @@ -4527,7 +4527,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 347, "literal": "^4.1.0", @@ -4540,7 +4540,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 348, "literal": "^3.0.0", @@ -4553,7 +4553,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 349, "literal": "^1.4.0", @@ -4566,7 +4566,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 350, "literal": "^3.1.2", @@ -4579,7 +4579,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 351, "literal": "8.50.0", @@ -4592,7 +4592,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 352, "literal": "^0.9.3", @@ -4605,7 +4605,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 353, "literal": "^6.0.1", @@ -4618,7 +4618,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 354, "literal": "^0.2.0", @@ -4631,7 +4631,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 355, "literal": "^7.0.2", @@ -4644,7 +4644,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 356, "literal": "^6.0.2", @@ -4657,7 +4657,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 357, "literal": "^0.1.4", @@ -4670,7 +4670,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 358, "literal": "^7.2.2", @@ -4683,7 +4683,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 359, "literal": "^4.6.2", @@ -4696,7 +4696,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 360, "literal": "^3.0.3", @@ -4709,7 +4709,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 361, "literal": "^3.1.3", @@ -4722,7 +4722,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 362, "literal": "^1.4.0", @@ -4735,7 +4735,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 363, "literal": "^2.1.2", @@ -4748,7 +4748,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 364, "literal": "^1.2.8", @@ -4761,7 +4761,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 365, "literal": "^6.0.1", @@ -4774,7 +4774,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 366, "literal": "^3.4.3", @@ -4787,7 +4787,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 367, "literal": "^4.0.0", @@ -4800,7 +4800,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 368, "literal": "^4.6.1", @@ -4813,7 +4813,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 369, "literal": "^0.11.11", @@ -4826,7 +4826,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 370, "literal": "^4.2.0", @@ -4839,7 +4839,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 371, "literal": "^1.0.1", @@ -4852,7 +4852,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 372, "literal": "^1.0.1", @@ -4865,7 +4865,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 373, "literal": "^3.3.0", @@ -4891,7 +4891,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 375, "literal": "^2.0.2", @@ -4904,7 +4904,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 376, "literal": "^4.3.1", @@ -4917,7 +4917,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 377, "literal": "^3.0.5", @@ -4930,7 +4930,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 378, "literal": "^1.1.7", @@ -4943,7 +4943,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 379, "literal": "^1.0.0", @@ -4956,7 +4956,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 380, "literal": "0.0.1", @@ -4969,7 +4969,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 381, "literal": "^3.0.4", @@ -4982,7 +4982,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 382, "literal": "^3.2.9", @@ -4995,7 +4995,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 383, "literal": "^4.5.3", @@ -5008,7 +5008,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 384, "literal": "^3.0.2", @@ -5021,7 +5021,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 385, "literal": "^7.1.3", @@ -5034,7 +5034,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 386, "literal": "^1.0.0", @@ -5047,7 +5047,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 387, "literal": "^1.0.4", @@ -5060,7 +5060,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 388, "literal": "2", @@ -5073,7 +5073,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 389, "literal": "^3.1.1", @@ -5086,7 +5086,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 390, "literal": "^1.3.0", @@ -5099,7 +5099,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 391, "literal": "^1.0.0", @@ -5112,7 +5112,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 392, "literal": "^1.3.0", @@ -5125,7 +5125,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 393, "literal": "1", @@ -5138,7 +5138,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 394, "literal": "3.0.1", @@ -5151,7 +5151,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 395, "literal": "^6.12.4", @@ -5164,7 +5164,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 396, "literal": "^4.3.2", @@ -5177,7 +5177,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 397, "literal": "^9.6.0", @@ -5190,7 +5190,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 398, "literal": "^13.19.0", @@ -5203,7 +5203,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 399, "literal": "^5.2.0", @@ -5216,7 +5216,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 400, "literal": "^3.2.1", @@ -5229,7 +5229,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 401, "literal": "^4.1.0", @@ -5242,7 +5242,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 402, "literal": "^3.1.2", @@ -5255,7 +5255,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 403, "literal": "^3.1.1", @@ -5268,7 +5268,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 404, "literal": "^0.20.2", @@ -5281,7 +5281,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 405, "literal": "^8.9.0", @@ -5294,7 +5294,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 406, "literal": "^5.3.2", @@ -5307,7 +5307,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 407, "literal": "^3.4.1", @@ -5333,7 +5333,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 409, "literal": "^3.1.1", @@ -5346,7 +5346,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 410, "literal": "^2.0.0", @@ -5359,7 +5359,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 411, "literal": "^0.4.1", @@ -5372,7 +5372,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 412, "literal": "^4.2.2", @@ -5385,7 +5385,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 413, "literal": "^2.1.0", @@ -5398,7 +5398,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 414, "literal": "^4.3.0", @@ -5411,7 +5411,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 415, "literal": "^5.2.0", @@ -5424,7 +5424,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 416, "literal": "^5.2.0", @@ -5437,7 +5437,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 417, "literal": "^1.2.1", @@ -5450,7 +5450,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 418, "literal": "^0.1.3", @@ -5463,7 +5463,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 419, "literal": "^1.2.5", @@ -5476,7 +5476,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 420, "literal": "^0.4.0", @@ -5489,7 +5489,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 421, "literal": "^0.4.1", @@ -5502,7 +5502,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 422, "literal": "^2.0.6", @@ -5515,7 +5515,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 423, "literal": "^1.2.1", @@ -5528,7 +5528,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 424, "literal": "~0.4.0", @@ -5541,7 +5541,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 425, "literal": "^1.2.1", @@ -5554,7 +5554,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 426, "literal": "^2.0.2", @@ -5567,7 +5567,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 427, "literal": "^6.0.0", @@ -5580,7 +5580,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 428, "literal": "^4.0.0", @@ -5593,7 +5593,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 429, "literal": "^5.0.0", @@ -5606,7 +5606,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 430, "literal": "^3.0.2", @@ -5619,7 +5619,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 431, "literal": "^0.1.0", @@ -5632,7 +5632,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 432, "literal": "^5.1.0", @@ -5645,7 +5645,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 433, "literal": "^4.1.0", @@ -5658,7 +5658,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 434, "literal": "^7.1.0", @@ -5671,7 +5671,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 435, "literal": "^4.0.0", @@ -5684,7 +5684,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 436, "literal": "^4.3.4", @@ -5697,7 +5697,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 437, "literal": "^5.12.0", @@ -5710,7 +5710,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 438, "literal": "^2.7.4", @@ -5723,7 +5723,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 439, "literal": "^3.3.1", @@ -5736,7 +5736,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 440, "literal": "^4.5.0", @@ -5749,7 +5749,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 441, "literal": "^2.11.0", @@ -5762,7 +5762,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 442, "literal": "^4.0.3", @@ -5801,7 +5801,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 445, "literal": "^3.1.7", @@ -5814,7 +5814,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 446, "literal": "^1.2.3", @@ -5827,7 +5827,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 447, "literal": "^1.3.2", @@ -5840,7 +5840,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 448, "literal": "^1.3.2", @@ -5853,7 +5853,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 449, "literal": "^3.2.7", @@ -5866,7 +5866,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 450, "literal": "^2.1.0", @@ -5879,7 +5879,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 451, "literal": "^0.3.9", @@ -5892,7 +5892,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 452, "literal": "^2.8.0", @@ -5905,7 +5905,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 453, "literal": "^2.0.0", @@ -5918,7 +5918,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 454, "literal": "^2.13.1", @@ -5931,7 +5931,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 455, "literal": "^4.0.3", @@ -5944,7 +5944,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 456, "literal": "^3.1.2", @@ -5957,7 +5957,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 457, "literal": "^2.0.7", @@ -5970,7 +5970,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 458, "literal": "^1.0.1", @@ -5983,7 +5983,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 459, "literal": "^1.1.7", @@ -5996,7 +5996,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 460, "literal": "^6.3.1", @@ -6009,7 +6009,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 461, "literal": "^3.15.0", @@ -6035,7 +6035,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 463, "literal": "^0.0.29", @@ -6048,7 +6048,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 464, "literal": "^1.0.2", @@ -6061,7 +6061,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 465, "literal": "^1.2.6", @@ -6074,7 +6074,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 466, "literal": "^3.0.0", @@ -6087,7 +6087,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 467, "literal": "^1.2.0", @@ -6100,7 +6100,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 468, "literal": "^1.0.7", @@ -6113,7 +6113,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 469, "literal": "^1.2.1", @@ -6126,7 +6126,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 470, "literal": "^1.0.0", @@ -6139,7 +6139,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 471, "literal": "^1.3.0", @@ -6152,7 +6152,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 472, "literal": "^1.0.1", @@ -6165,7 +6165,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 473, "literal": "^1.0.0", @@ -6178,7 +6178,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 474, "literal": "^1.1.1", @@ -6191,7 +6191,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 475, "literal": "^1.0.0", @@ -6204,7 +6204,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 476, "literal": "^1.2.4", @@ -6217,7 +6217,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 477, "literal": "^1.3.0", @@ -6230,7 +6230,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 478, "literal": "^1.1.2", @@ -6243,7 +6243,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 479, "literal": "^1.0.1", @@ -6256,7 +6256,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 480, "literal": "^1.0.3", @@ -6269,7 +6269,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 481, "literal": "^2.0.0", @@ -6282,7 +6282,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 482, "literal": "^1.0.0", @@ -6295,7 +6295,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 483, "literal": "^1.3.0", @@ -6308,7 +6308,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 484, "literal": "^1.0.1", @@ -6321,7 +6321,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 485, "literal": "^1.1.3", @@ -6334,7 +6334,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 486, "literal": "^1.0.0", @@ -6347,7 +6347,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 487, "literal": "^1.3.0", @@ -6360,7 +6360,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 488, "literal": "^1.1.2", @@ -6373,7 +6373,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 489, "literal": "^1.2.4", @@ -6386,7 +6386,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 490, "literal": "^1.2.1", @@ -6399,7 +6399,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 491, "literal": "^1.1.4", @@ -6412,7 +6412,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 492, "literal": "^1.3.0", @@ -6425,7 +6425,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 493, "literal": "^1.1.2", @@ -6438,7 +6438,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 494, "literal": "^1.2.4", @@ -6451,7 +6451,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 495, "literal": "^1.0.1", @@ -6464,7 +6464,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 496, "literal": "^1.0.2", @@ -6477,7 +6477,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 497, "literal": "^1.0.7", @@ -6490,7 +6490,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 498, "literal": "^1.2.1", @@ -6503,7 +6503,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 499, "literal": "^1.23.2", @@ -6516,7 +6516,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 500, "literal": "^1.0.1", @@ -6529,7 +6529,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 501, "literal": "^1.0.3", @@ -6542,7 +6542,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 502, "literal": "^1.0.7", @@ -6555,7 +6555,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 503, "literal": "^1.0.7", @@ -6568,7 +6568,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 504, "literal": "^1.0.1", @@ -6581,7 +6581,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 505, "literal": "^1.0.1", @@ -6594,7 +6594,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 506, "literal": "^1.0.0", @@ -6607,7 +6607,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 507, "literal": "^1.0.0", @@ -6620,7 +6620,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 508, "literal": "^1.3.0", @@ -6633,7 +6633,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 509, "literal": "^1.0.0", @@ -6646,7 +6646,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 510, "literal": "^2.0.3", @@ -6659,7 +6659,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 511, "literal": "^1.2.1", @@ -6672,7 +6672,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 512, "literal": "^1.1.6", @@ -6685,7 +6685,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 513, "literal": "^1.2.4", @@ -6698,7 +6698,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 514, "literal": "^1.0.2", @@ -6711,7 +6711,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 515, "literal": "^1.0.3", @@ -6724,7 +6724,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 516, "literal": "^1.0.1", @@ -6737,7 +6737,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 517, "literal": "^1.0.2", @@ -6750,7 +6750,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 518, "literal": "^1.0.3", @@ -6763,7 +6763,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 519, "literal": "^1.0.3", @@ -6776,7 +6776,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 520, "literal": "^2.0.2", @@ -6789,7 +6789,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 521, "literal": "^1.0.7", @@ -6802,7 +6802,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 522, "literal": "^3.0.4", @@ -6815,7 +6815,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 523, "literal": "^1.2.7", @@ -6828,7 +6828,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 524, "literal": "^1.0.1", @@ -6841,7 +6841,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 525, "literal": "^2.0.3", @@ -6854,7 +6854,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 526, "literal": "^1.1.4", @@ -6867,7 +6867,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 527, "literal": "^1.0.3", @@ -6880,7 +6880,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 528, "literal": "^1.0.7", @@ -6893,7 +6893,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 529, "literal": "^1.1.13", @@ -6906,7 +6906,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 530, "literal": "^1.0.2", @@ -6919,7 +6919,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 531, "literal": "^1.13.1", @@ -6932,7 +6932,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 532, "literal": "^1.1.1", @@ -6945,7 +6945,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 533, "literal": "^4.1.5", @@ -6958,7 +6958,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 534, "literal": "^1.5.2", @@ -6971,7 +6971,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 535, "literal": "^1.1.2", @@ -6984,7 +6984,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 536, "literal": "^1.0.3", @@ -6997,7 +6997,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 537, "literal": "^1.2.9", @@ -7010,7 +7010,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 538, "literal": "^1.0.8", @@ -7023,7 +7023,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 539, "literal": "^1.0.8", @@ -7036,7 +7036,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 540, "literal": "^1.0.2", @@ -7049,7 +7049,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 541, "literal": "^1.0.1", @@ -7062,7 +7062,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 542, "literal": "^1.0.2", @@ -7075,7 +7075,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 543, "literal": "^1.0.6", @@ -7088,7 +7088,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 544, "literal": "^1.0.2", @@ -7101,7 +7101,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 545, "literal": "^1.1.15", @@ -7114,7 +7114,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 546, "literal": "^1.0.7", @@ -7127,7 +7127,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 547, "literal": "^1.0.7", @@ -7140,7 +7140,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 548, "literal": "^0.3.3", @@ -7153,7 +7153,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 549, "literal": "^1.0.1", @@ -7166,7 +7166,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 550, "literal": "^1.0.2", @@ -7179,7 +7179,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 551, "literal": "^1.0.3", @@ -7192,7 +7192,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 552, "literal": "^1.1.3", @@ -7205,7 +7205,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 553, "literal": "^1.0.0", @@ -7218,7 +7218,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 554, "literal": "^1.0.2", @@ -7231,7 +7231,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 555, "literal": "^1.0.2", @@ -7244,7 +7244,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 556, "literal": "^1.0.3", @@ -7257,7 +7257,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 557, "literal": "^1.0.2", @@ -7270,7 +7270,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 558, "literal": "^1.0.1", @@ -7283,7 +7283,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 559, "literal": "^1.1.0", @@ -7296,7 +7296,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 560, "literal": "^1.0.4", @@ -7309,7 +7309,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 561, "literal": "^1.0.5", @@ -7322,7 +7322,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 562, "literal": "^1.0.3", @@ -7335,7 +7335,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 563, "literal": "^1.0.2", @@ -7348,7 +7348,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 564, "literal": "^1.0.0", @@ -7361,7 +7361,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 565, "literal": "^1.0.0", @@ -7374,7 +7374,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 566, "literal": "^1.0.2", @@ -7387,7 +7387,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 567, "literal": "^1.0.0", @@ -7400,7 +7400,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 568, "literal": "^1.0.1", @@ -7413,7 +7413,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 569, "literal": "^1.0.7", @@ -7426,7 +7426,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 570, "literal": "^0.3.3", @@ -7439,7 +7439,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 571, "literal": "^1.0.1", @@ -7452,7 +7452,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 572, "literal": "^1.0.3", @@ -7465,7 +7465,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 573, "literal": "^1.1.13", @@ -7478,7 +7478,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 574, "literal": "^1.0.0", @@ -7491,7 +7491,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 575, "literal": "^1.1.14", @@ -7504,7 +7504,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 576, "literal": "^1.0.7", @@ -7517,7 +7517,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 577, "literal": "^1.0.7", @@ -7530,7 +7530,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 578, "literal": "^0.3.3", @@ -7543,7 +7543,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 579, "literal": "^1.0.1", @@ -7556,7 +7556,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 580, "literal": "^1.0.3", @@ -7569,7 +7569,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 581, "literal": "^1.1.13", @@ -7582,7 +7582,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 582, "literal": "^1.0.7", @@ -7595,7 +7595,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 583, "literal": "^0.3.3", @@ -7608,7 +7608,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 584, "literal": "^1.0.1", @@ -7621,7 +7621,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 585, "literal": "^1.0.3", @@ -7634,7 +7634,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 586, "literal": "^1.1.13", @@ -7647,7 +7647,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 587, "literal": "^1.0.7", @@ -7660,7 +7660,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 588, "literal": "^1.3.0", @@ -7673,7 +7673,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 589, "literal": "^1.1.13", @@ -7686,7 +7686,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 590, "literal": "^1.0.7", @@ -7699,7 +7699,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 591, "literal": "^1.2.1", @@ -7712,7 +7712,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 592, "literal": "^1.0.0", @@ -7725,7 +7725,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 593, "literal": "^1.0.7", @@ -7738,7 +7738,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 594, "literal": "^1.2.1", @@ -7751,7 +7751,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 595, "literal": "^1.0.0", @@ -7764,7 +7764,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 596, "literal": "^1.0.7", @@ -7777,7 +7777,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 597, "literal": "^1.2.1", @@ -7790,7 +7790,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 598, "literal": "^1.23.0", @@ -7803,7 +7803,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 599, "literal": "^1.0.0", @@ -7816,7 +7816,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 600, "literal": "^1.0.6", @@ -7829,7 +7829,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 601, "literal": "^1.3.0", @@ -7842,7 +7842,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 602, "literal": "^1.1.4", @@ -7855,7 +7855,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 603, "literal": "^1.0.2", @@ -7868,7 +7868,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 604, "literal": "^1.0.0", @@ -7881,7 +7881,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 605, "literal": "^1.0.7", @@ -7894,7 +7894,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 606, "literal": "^1.2.4", @@ -7907,7 +7907,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 607, "literal": "^1.0.3", @@ -7920,7 +7920,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 608, "literal": "^2.0.5", @@ -7933,7 +7933,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 609, "literal": "^1.0.6", @@ -7946,7 +7946,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 610, "literal": "^1.2.1", @@ -7959,7 +7959,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 611, "literal": "^1.3.0", @@ -7972,7 +7972,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 612, "literal": "^2.0.1", @@ -7985,7 +7985,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 613, "literal": "^1.1.4", @@ -7998,7 +7998,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 614, "literal": "^1.3.0", @@ -8011,7 +8011,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 615, "literal": "^1.2.3", @@ -8024,7 +8024,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 616, "literal": "^1.0.2", @@ -8037,7 +8037,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 617, "literal": "^1.0.5", @@ -8050,7 +8050,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 618, "literal": "^1.2.1", @@ -8063,7 +8063,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 619, "literal": "^1.0.3", @@ -8076,7 +8076,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 620, "literal": "^1.1.1", @@ -8089,7 +8089,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 621, "literal": "^1.0.2", @@ -8102,7 +8102,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 622, "literal": "^1.0.7", @@ -8115,7 +8115,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 623, "literal": "^1.1.13", @@ -8128,7 +8128,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 624, "literal": "^1.0.2", @@ -8141,7 +8141,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 625, "literal": "^1.2.1", @@ -8154,7 +8154,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 626, "literal": "^1.3.0", @@ -8167,7 +8167,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 627, "literal": "^2.0.0", @@ -8180,7 +8180,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 628, "literal": "^1.0.4", @@ -8193,7 +8193,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 629, "literal": "^1.0.7", @@ -8206,7 +8206,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 630, "literal": "^1.3.0", @@ -8219,7 +8219,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 631, "literal": "^1.2.4", @@ -8232,7 +8232,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 632, "literal": "^1.13.1", @@ -8245,7 +8245,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 633, "literal": "^1.2.1", @@ -8258,7 +8258,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 634, "literal": "^1.0.1", @@ -8271,7 +8271,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 635, "literal": "^1.0.5", @@ -8284,7 +8284,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 636, "literal": "^1.3.0", @@ -8297,7 +8297,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 637, "literal": "^1.2.4", @@ -8310,7 +8310,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 638, "literal": "^1.0.2", @@ -8323,7 +8323,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 639, "literal": "^1.2.0", @@ -8336,7 +8336,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 640, "literal": "^1.22.1", @@ -8349,7 +8349,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 641, "literal": "^1.2.3", @@ -8362,7 +8362,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 642, "literal": "^1.1.4", @@ -8375,7 +8375,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 643, "literal": "^1.0.1", @@ -8388,7 +8388,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 644, "literal": "^1.0.2", @@ -8401,7 +8401,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 645, "literal": "^1.0.0", @@ -8414,7 +8414,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 646, "literal": "^1.2.4", @@ -8427,7 +8427,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 647, "literal": "^1.0.2", @@ -8440,7 +8440,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 648, "literal": "^2.0.1", @@ -8453,7 +8453,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 649, "literal": "^1.0.6", @@ -8466,7 +8466,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 650, "literal": "^1.3.0", @@ -8479,7 +8479,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 651, "literal": "^1.0.1", @@ -8492,7 +8492,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 652, "literal": "^1.0.7", @@ -8505,7 +8505,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 653, "literal": "^1.3.0", @@ -8518,7 +8518,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 654, "literal": "^1.0.1", @@ -8531,7 +8531,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 655, "literal": "^1.0.6", @@ -8544,7 +8544,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 656, "literal": "^1.3.0", @@ -8557,7 +8557,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 657, "literal": "^1.0.1", @@ -8570,7 +8570,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 658, "literal": "^1.0.1", @@ -8583,7 +8583,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 659, "literal": "^1.0.5", @@ -8596,7 +8596,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 660, "literal": "^1.2.1", @@ -8609,7 +8609,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 661, "literal": "^1.22.3", @@ -8622,7 +8622,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 662, "literal": "^1.2.1", @@ -8635,7 +8635,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 663, "literal": "^1.2.3", @@ -8648,7 +8648,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 664, "literal": "^3.0.4", @@ -8661,7 +8661,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 665, "literal": "^1.0.2", @@ -8674,7 +8674,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 666, "literal": "^1.0.5", @@ -8687,7 +8687,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 667, "literal": "^3.0.4", @@ -8700,7 +8700,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 668, "literal": "^1.0.7", @@ -8713,7 +8713,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 669, "literal": "^1.2.1", @@ -8726,7 +8726,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 670, "literal": "^1.23.2", @@ -8739,7 +8739,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 671, "literal": "^1.0.0", @@ -8752,7 +8752,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 672, "literal": "^3.2.7", @@ -8765,7 +8765,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 673, "literal": "^2.1.1", @@ -8778,7 +8778,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 674, "literal": "^3.2.7", @@ -8791,7 +8791,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 675, "literal": "^2.13.0", @@ -8804,7 +8804,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 676, "literal": "^1.22.4", @@ -8817,7 +8817,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 677, "literal": "^2.0.2", @@ -8830,7 +8830,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 678, "literal": "^1.0.2", @@ -8843,7 +8843,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 679, "literal": "^1.2.0", @@ -8856,7 +8856,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 680, "literal": "^1.22.1", @@ -8869,7 +8869,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 681, "literal": "^1.0.0", @@ -8882,7 +8882,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 682, "literal": "^2.0.0", @@ -8895,7 +8895,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 683, "literal": "^1.0.2", @@ -8908,7 +8908,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 684, "literal": "^1.2.0", @@ -8921,7 +8921,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 685, "literal": "^1.22.1", @@ -8934,7 +8934,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 686, "literal": "^1.0.0", @@ -8947,7 +8947,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 687, "literal": "^1.0.7", @@ -8960,7 +8960,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 688, "literal": "^1.2.1", @@ -8973,7 +8973,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 689, "literal": "^1.23.2", @@ -8986,7 +8986,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 690, "literal": "^1.3.0", @@ -8999,7 +8999,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 691, "literal": "^1.0.0", @@ -9012,7 +9012,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 692, "literal": "^1.0.2", @@ -9025,7 +9025,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 693, "literal": "^1.0.7", @@ -9038,7 +9038,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 694, "literal": "^1.2.1", @@ -9051,7 +9051,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 695, "literal": "^1.23.2", @@ -9064,7 +9064,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 696, "literal": "^1.0.0", @@ -9077,7 +9077,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 697, "literal": "^1.2.4", @@ -9090,7 +9090,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 698, "literal": "^1.0.7", @@ -9103,7 +9103,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 699, "literal": "^1.0.0", @@ -9116,7 +9116,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 700, "literal": "^4.2.4", @@ -9129,7 +9129,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 701, "literal": "^2.2.0", @@ -9155,7 +9155,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 703, "literal": "^4.3.4", @@ -9168,7 +9168,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 704, "literal": "6.21.0", @@ -9181,7 +9181,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 705, "literal": "6.21.0", @@ -9194,7 +9194,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 706, "literal": "6.21.0", @@ -9207,7 +9207,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 707, "literal": "6.21.0", @@ -9233,7 +9233,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 709, "literal": "^4.3.4", @@ -9246,7 +9246,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 710, "literal": "^11.1.0", @@ -9259,7 +9259,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 711, "literal": "^7.5.4", @@ -9272,7 +9272,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 712, "literal": "^4.0.3", @@ -9285,7 +9285,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 713, "literal": "9.0.3", @@ -9298,7 +9298,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 714, "literal": "^1.0.1", @@ -9311,7 +9311,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 715, "literal": "6.21.0", @@ -9324,7 +9324,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 716, "literal": "6.21.0", @@ -9337,7 +9337,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 717, "literal": "^3.4.1", @@ -9350,7 +9350,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 718, "literal": "6.21.0", @@ -9376,7 +9376,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 720, "literal": "^2.0.1", @@ -9389,7 +9389,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 721, "literal": "^2.1.0", @@ -9402,7 +9402,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 722, "literal": "^3.0.1", @@ -9415,7 +9415,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 723, "literal": "^3.2.9", @@ -9428,7 +9428,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 724, "literal": "^5.2.0", @@ -9441,7 +9441,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 725, "literal": "^1.4.1", @@ -9454,7 +9454,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 726, "literal": "^3.0.0", @@ -9467,7 +9467,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 727, "literal": "^4.0.0", @@ -9480,7 +9480,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 728, "literal": "6.21.0", @@ -9493,7 +9493,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 729, "literal": "6.21.0", @@ -9506,7 +9506,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 730, "literal": "10.3.10", @@ -9519,7 +9519,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 731, "literal": "^7.23.2", @@ -9532,7 +9532,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 732, "literal": "^5.3.0", @@ -9545,7 +9545,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 733, "literal": "^3.1.7", @@ -9558,7 +9558,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 734, "literal": "^1.3.2", @@ -9571,7 +9571,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 735, "literal": "^0.0.8", @@ -9584,7 +9584,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 736, "literal": "=4.7.0", @@ -9597,7 +9597,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 737, "literal": "^3.2.1", @@ -9610,7 +9610,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 738, "literal": "^1.0.8", @@ -9623,7 +9623,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 739, "literal": "^9.2.2", @@ -9636,7 +9636,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 740, "literal": "^1.0.15", @@ -9649,7 +9649,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 741, "literal": "^2.0.0", @@ -9662,7 +9662,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 742, "literal": "^3.3.5", @@ -9675,7 +9675,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 743, "literal": "^1.0.9", @@ -9688,7 +9688,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 744, "literal": "^3.1.2", @@ -9701,7 +9701,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 745, "literal": "^1.1.7", @@ -9714,7 +9714,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 746, "literal": "^2.0.7", @@ -9740,7 +9740,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 748, "literal": "^1.0.7", @@ -9753,7 +9753,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 749, "literal": "^1.2.1", @@ -9766,7 +9766,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 750, "literal": "^1.0.0", @@ -9779,7 +9779,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 751, "literal": "^0.3.20", @@ -9792,7 +9792,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 752, "literal": "^3.1.6", @@ -9805,7 +9805,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 753, "literal": "^1.3.1", @@ -9818,7 +9818,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 754, "literal": "^4.1.4", @@ -9831,7 +9831,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 755, "literal": "^1.1.6", @@ -9844,7 +9844,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 756, "literal": "^1.0.7", @@ -9857,7 +9857,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 757, "literal": "^1.2.1", @@ -9870,7 +9870,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 758, "literal": "^1.23.3", @@ -9883,7 +9883,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 759, "literal": "^1.3.0", @@ -9896,7 +9896,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 760, "literal": "^2.0.3", @@ -9909,7 +9909,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 761, "literal": "^1.1.2", @@ -9922,7 +9922,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 762, "literal": "^1.2.4", @@ -9935,7 +9935,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 763, "literal": "^1.0.3", @@ -9948,7 +9948,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 764, "literal": "^1.0.2", @@ -9961,7 +9961,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 765, "literal": "^1.0.3", @@ -9974,7 +9974,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 766, "literal": "^1.0.3", @@ -9987,7 +9987,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 767, "literal": "^1.0.7", @@ -10000,7 +10000,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 768, "literal": "^1.1.2", @@ -10013,7 +10013,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 769, "literal": "^1.1.2", @@ -10026,7 +10026,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 770, "literal": "^1.2.1", @@ -10039,7 +10039,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 771, "literal": "^1.2.1", @@ -10052,7 +10052,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 772, "literal": "^1.0.3", @@ -10065,7 +10065,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 773, "literal": "^1.0.4", @@ -10078,7 +10078,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 774, "literal": "^2.0.1", @@ -10091,7 +10091,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 775, "literal": "^1.0.7", @@ -10104,7 +10104,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 776, "literal": "^1.2.1", @@ -10117,7 +10117,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 777, "literal": "^1.23.1", @@ -10130,7 +10130,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 778, "literal": "^1.3.0", @@ -10143,7 +10143,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 779, "literal": "^1.2.4", @@ -10156,7 +10156,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 780, "literal": "^1.0.3", @@ -10169,7 +10169,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 781, "literal": "^1.1.3", @@ -10182,7 +10182,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 782, "literal": "^1.1.5", @@ -10195,7 +10195,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 783, "literal": "^1.0.0", @@ -10208,7 +10208,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 784, "literal": "^2.0.0", @@ -10221,7 +10221,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 785, "literal": "^1.0.5", @@ -10234,7 +10234,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 786, "literal": "^1.0.2", @@ -10247,7 +10247,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 787, "literal": "^1.0.10", @@ -10260,7 +10260,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 788, "literal": "^1.1.4", @@ -10273,7 +10273,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 789, "literal": "^1.0.2", @@ -10286,7 +10286,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 790, "literal": "^2.0.5", @@ -10299,7 +10299,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 791, "literal": "^1.0.2", @@ -10312,7 +10312,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 792, "literal": "^1.0.1", @@ -10325,7 +10325,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 793, "literal": "^1.1.9", @@ -10338,7 +10338,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 794, "literal": "^2.0.3", @@ -10351,7 +10351,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 795, "literal": "^2.0.3", @@ -10364,7 +10364,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 796, "literal": "^2.0.2", @@ -10377,7 +10377,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 797, "literal": "^2.0.3", @@ -10390,7 +10390,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 798, "literal": "^1.0.7", @@ -10403,7 +10403,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 799, "literal": "^1.2.4", @@ -10416,7 +10416,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 800, "literal": "^1.0.0", @@ -10429,7 +10429,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 801, "literal": "^1.0.2", @@ -10442,7 +10442,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 802, "literal": "^1.0.0", @@ -10455,7 +10455,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 803, "literal": "^2.0.3", @@ -10468,7 +10468,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 804, "literal": "^2.0.3", @@ -10481,7 +10481,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 805, "literal": "^0.14.0", @@ -10494,7 +10494,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 806, "literal": "^3.1.8", @@ -10507,7 +10507,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 807, "literal": "^1.2.5", @@ -10520,7 +10520,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 808, "literal": "^1.3.2", @@ -10533,7 +10533,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 809, "literal": "^1.1.2", @@ -10546,7 +10546,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 810, "literal": "^1.1.3", @@ -10559,7 +10559,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 811, "literal": "^2.1.0", @@ -10572,7 +10572,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 812, "literal": "^1.0.19", @@ -10585,7 +10585,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 813, "literal": "^5.3.0", @@ -10598,7 +10598,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 814, "literal": "^2.4.1 || ^3.0.0", @@ -10611,7 +10611,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 815, "literal": "^3.1.2", @@ -10624,7 +10624,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 816, "literal": "^1.1.8", @@ -10637,7 +10637,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 817, "literal": "^2.0.8", @@ -10650,7 +10650,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 818, "literal": "^1.1.4", @@ -10663,7 +10663,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 819, "literal": "^1.2.0", @@ -10676,7 +10676,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 820, "literal": "^15.8.1", @@ -10689,7 +10689,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 821, "literal": "^2.0.0-next.5", @@ -10702,7 +10702,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 822, "literal": "^6.3.1", @@ -10715,7 +10715,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 823, "literal": "^4.0.11", @@ -10741,7 +10741,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 825, "literal": "^1.0.7", @@ -10754,7 +10754,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 826, "literal": "^1.2.1", @@ -10767,7 +10767,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 827, "literal": "^1.23.2", @@ -10780,7 +10780,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 828, "literal": "^1.3.0", @@ -10793,7 +10793,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 829, "literal": "^1.0.0", @@ -10806,7 +10806,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 830, "literal": "^1.2.4", @@ -10819,7 +10819,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 831, "literal": "^1.0.1", @@ -10832,7 +10832,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 832, "literal": "^1.0.3", @@ -10845,7 +10845,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 833, "literal": "^1.0.7", @@ -10858,7 +10858,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 834, "literal": "^1.5.2", @@ -10871,7 +10871,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 835, "literal": "^2.0.2", @@ -10884,7 +10884,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 836, "literal": "^1.0.6", @@ -10897,7 +10897,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 837, "literal": "^2.13.0", @@ -10910,7 +10910,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 838, "literal": "^1.0.7", @@ -10923,7 +10923,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 839, "literal": "^1.0.0", @@ -10936,7 +10936,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 840, "literal": "^1.4.0", @@ -10949,7 +10949,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 841, "literal": "^4.1.1", @@ -10962,7 +10962,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 842, "literal": "^16.13.1", @@ -10975,7 +10975,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 843, "literal": "^1.2.1", @@ -10988,7 +10988,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 844, "literal": "^1.23.2", @@ -11001,7 +11001,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 845, "literal": "^1.0.0", @@ -11014,7 +11014,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 846, "literal": "^1.0.7", @@ -11027,7 +11027,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 847, "literal": "^1.2.1", @@ -11040,7 +11040,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 848, "literal": "^1.23.3", @@ -11053,7 +11053,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 849, "literal": "^1.3.0", @@ -11066,7 +11066,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 850, "literal": "^1.0.2", @@ -11079,7 +11079,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 851, "literal": "^1.0.2", @@ -11092,7 +11092,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 852, "literal": "^1.2.0", @@ -11105,7 +11105,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 853, "literal": "^1.22.1", @@ -11118,7 +11118,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 854, "literal": "^1.0.0", @@ -11131,7 +11131,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 855, "literal": "^1.0.7", @@ -11144,7 +11144,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 856, "literal": "^1.2.1", @@ -11157,7 +11157,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 857, "literal": "^1.23.2", @@ -11170,7 +11170,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 858, "literal": "^1.3.0", @@ -11183,7 +11183,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 859, "literal": "^1.0.0", @@ -11196,7 +11196,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 860, "literal": "^1.0.2", @@ -11209,7 +11209,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 861, "literal": "~8.5.10", @@ -11222,7 +11222,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 862, "literal": "~20.12.8", @@ -11235,7 +11235,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 863, "literal": "*", @@ -11248,7 +11248,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 864, "literal": "^4.21.10", @@ -11261,7 +11261,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 865, "literal": "^1.0.30001538", @@ -11274,7 +11274,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 866, "literal": "^4.3.6", @@ -11287,7 +11287,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 867, "literal": "^0.1.2", @@ -11300,7 +11300,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 868, "literal": "^1.0.0", @@ -11313,7 +11313,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 869, "literal": "^4.2.0", @@ -11339,7 +11339,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 871, "literal": "^1.0.30001587", @@ -11352,7 +11352,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 872, "literal": "^1.4.668", @@ -11365,7 +11365,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 873, "literal": "^2.0.14", @@ -11378,7 +11378,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 874, "literal": "^1.0.13", @@ -11391,7 +11391,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 875, "literal": "^3.1.2", @@ -11404,7 +11404,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 876, "literal": "^1.0.1", @@ -11430,7 +11430,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 878, "literal": "*", @@ -11443,7 +11443,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 879, "literal": "*", @@ -11456,7 +11456,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 880, "literal": "*", @@ -11469,7 +11469,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 881, "literal": "^3.0.2", diff --git a/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap b/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap index a7e9af8b95..fe8eb9c7d8 100644 --- a/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap @@ -5,7 +5,7 @@ exports[`next build works: bun 1`] = ` "dependencies": [ { "behavior": { - "normal": true, + "prod": true, }, "id": 0, "literal": "20.7.0", @@ -18,7 +18,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 1, "literal": "18.2.22", @@ -31,7 +31,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 2, "literal": "18.2.7", @@ -44,7 +44,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 3, "literal": "10.4.16", @@ -57,7 +57,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 4, "literal": "^1.0.3", @@ -70,7 +70,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 5, "literal": "8.50.0", @@ -83,7 +83,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 6, "literal": "14.1.3", @@ -96,7 +96,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 7, "literal": "14.1.3", @@ -109,7 +109,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 8, "literal": "8.4.30", @@ -122,7 +122,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 9, "literal": "22.12.0", @@ -135,7 +135,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 10, "literal": "18.2.0", @@ -148,7 +148,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 11, "literal": "18.2.0", @@ -161,7 +161,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 12, "literal": "3.3.3", @@ -174,7 +174,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 13, "literal": "5.2.2", @@ -187,7 +187,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 14, "literal": "^5.0.2", @@ -200,7 +200,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 15, "literal": "^1.1.3", @@ -213,7 +213,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 16, "literal": "^1.18.2", @@ -226,7 +226,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 17, "literal": "^4.0.3", @@ -239,7 +239,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 18, "literal": "^8.4.23", @@ -252,7 +252,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 19, "literal": "^1.22.2", @@ -265,7 +265,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 20, "literal": "^3.32.0", @@ -278,7 +278,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 21, "literal": "^3.5.3", @@ -291,7 +291,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 22, "literal": "^3.2.12", @@ -304,7 +304,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 23, "literal": "^2.1.0", @@ -317,7 +317,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 24, "literal": "^1.2.2", @@ -330,7 +330,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 25, "literal": "^4.0.5", @@ -343,7 +343,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 26, "literal": "^1.0.0", @@ -356,7 +356,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 27, "literal": "^4.0.1", @@ -369,7 +369,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 28, "literal": "^6.0.2", @@ -382,7 +382,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 29, "literal": "^3.0.0", @@ -395,7 +395,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 30, "literal": "^3.0.0", @@ -408,7 +408,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 31, "literal": "^15.1.0", @@ -421,7 +421,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 32, "literal": "^6.0.1", @@ -434,7 +434,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 33, "literal": "^5.2.0", @@ -447,7 +447,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 34, "literal": "^4.0.1", @@ -460,7 +460,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 35, "literal": "^6.0.11", @@ -473,7 +473,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 36, "literal": "^3.0.0", @@ -486,7 +486,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 37, "literal": "^1.0.2", @@ -499,7 +499,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 38, "literal": "^2.3.4", @@ -512,7 +512,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 39, "literal": "^3.0.0", @@ -553,7 +553,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 42, "literal": "^3.3.6", @@ -566,7 +566,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 43, "literal": "^1.0.0", @@ -579,7 +579,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 44, "literal": "^1.0.2", @@ -592,7 +592,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 45, "literal": "^6.0.11", @@ -618,7 +618,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 47, "literal": "^4.0.0", @@ -631,7 +631,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 48, "literal": "^1.0.0", @@ -644,7 +644,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 49, "literal": "^1.1.7", @@ -670,7 +670,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 51, "literal": "^2.13.0", @@ -683,7 +683,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 52, "literal": "^1.0.7", @@ -696,7 +696,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 53, "literal": "^1.0.0", @@ -709,7 +709,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 54, "literal": "^2.0.0", @@ -722,7 +722,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 55, "literal": "^1.1.2", @@ -735,7 +735,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 56, "literal": "^2.3.0", @@ -748,7 +748,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 57, "literal": "^4.0.3", @@ -761,7 +761,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 58, "literal": "^2.1.1", @@ -774,7 +774,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 59, "literal": "^2.0.1", @@ -800,7 +800,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 61, "literal": "^3.0.3", @@ -813,7 +813,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 62, "literal": "^2.3.1", @@ -826,7 +826,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 63, "literal": "^7.1.1", @@ -839,7 +839,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 64, "literal": "^5.0.1", @@ -852,7 +852,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 65, "literal": "^7.0.0", @@ -865,7 +865,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 66, "literal": "^2.0.2", @@ -878,7 +878,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 67, "literal": "^1.2.3", @@ -891,7 +891,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 68, "literal": "^5.1.2", @@ -904,7 +904,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 69, "literal": "^1.3.0", @@ -917,7 +917,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 70, "literal": "^4.0.4", @@ -930,7 +930,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 71, "literal": "^4.0.1", @@ -943,7 +943,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 72, "literal": "2.1.5", @@ -956,7 +956,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 73, "literal": "^1.6.0", @@ -969,7 +969,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 74, "literal": "^1.0.4", @@ -982,7 +982,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 75, "literal": "2.0.5", @@ -995,7 +995,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 76, "literal": "^1.1.9", @@ -1008,7 +1008,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 77, "literal": "^1.2.2", @@ -1021,7 +1021,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 78, "literal": "~3.1.2", @@ -1034,7 +1034,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 79, "literal": "~3.0.2", @@ -1047,7 +1047,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 80, "literal": "~5.1.2", @@ -1060,7 +1060,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 81, "literal": "~2.1.0", @@ -1073,7 +1073,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 82, "literal": "~4.0.1", @@ -1086,7 +1086,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 83, "literal": "~3.0.0", @@ -1099,7 +1099,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 84, "literal": "~3.6.0", @@ -1125,7 +1125,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 86, "literal": "^2.2.1", @@ -1138,7 +1138,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 87, "literal": "^2.0.0", @@ -1151,7 +1151,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 88, "literal": "^3.0.0", @@ -1164,7 +1164,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 89, "literal": "^2.0.4", @@ -1177,7 +1177,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 90, "literal": "^0.3.2", @@ -1190,7 +1190,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 91, "literal": "^4.0.0", @@ -1203,7 +1203,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 92, "literal": "^10.3.10", @@ -1216,7 +1216,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 93, "literal": "^1.1.6", @@ -1229,7 +1229,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 94, "literal": "^2.7.0", @@ -1242,7 +1242,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 95, "literal": "^4.0.1", @@ -1255,7 +1255,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 96, "literal": "^0.1.9", @@ -1268,7 +1268,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 97, "literal": "^1.0.0", @@ -1281,7 +1281,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 98, "literal": "^4.0.1", @@ -1294,7 +1294,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 99, "literal": "^1.0.0", @@ -1307,7 +1307,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 100, "literal": ">= 3.1.0 < 4", @@ -1320,7 +1320,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 101, "literal": "^1.0.0", @@ -1333,7 +1333,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 102, "literal": "^3.1.0", @@ -1346,7 +1346,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 103, "literal": "^2.3.5", @@ -1359,7 +1359,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 104, "literal": "^9.0.1", @@ -1372,7 +1372,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 105, "literal": "^5.0.0 || ^6.0.2 || ^7.0.0", @@ -1385,7 +1385,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 106, "literal": "^1.10.1", @@ -1398,7 +1398,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 107, "literal": "^10.2.0", @@ -1411,7 +1411,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 108, "literal": "^5.0.0 || ^6.0.2 || ^7.0.0", @@ -1424,7 +1424,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 109, "literal": "^2.0.1", @@ -1437,7 +1437,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 110, "literal": "^1.0.0", @@ -1450,7 +1450,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 111, "literal": "^8.0.2", @@ -1476,7 +1476,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 113, "literal": "^5.1.2", @@ -1489,7 +1489,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 114, "is_alias": true, @@ -1503,7 +1503,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 115, "literal": "^7.0.1", @@ -1516,7 +1516,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 116, "is_alias": true, @@ -1530,7 +1530,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 117, "literal": "^8.1.0", @@ -1543,7 +1543,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 118, "is_alias": true, @@ -1557,7 +1557,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 119, "literal": "^4.0.0", @@ -1570,7 +1570,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 120, "literal": "^4.1.0", @@ -1583,7 +1583,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 121, "literal": "^6.0.0", @@ -1596,7 +1596,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 122, "literal": "^5.0.1", @@ -1609,7 +1609,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 123, "literal": "^8.0.0", @@ -1622,7 +1622,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 124, "literal": "^3.0.0", @@ -1635,7 +1635,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 125, "literal": "^6.0.1", @@ -1648,7 +1648,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 126, "literal": "^2.0.1", @@ -1661,7 +1661,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 127, "literal": "~1.1.4", @@ -1674,7 +1674,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 128, "literal": "^6.1.0", @@ -1687,7 +1687,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 129, "literal": "^5.0.1", @@ -1700,7 +1700,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 130, "literal": "^7.0.1", @@ -1713,7 +1713,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 131, "literal": "^6.0.1", @@ -1726,7 +1726,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 132, "literal": "^0.2.0", @@ -1739,7 +1739,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 133, "literal": "^9.2.2", @@ -1752,7 +1752,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 134, "literal": "^7.0.1", @@ -1765,7 +1765,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 135, "literal": "^7.0.0", @@ -1778,7 +1778,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 136, "literal": "^4.0.1", @@ -1791,7 +1791,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 137, "literal": "^3.1.0", @@ -1804,7 +1804,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 138, "literal": "^2.0.0", @@ -1817,7 +1817,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 139, "literal": "^2.0.1", @@ -1830,7 +1830,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 140, "literal": "^2.0.0", @@ -1843,7 +1843,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 141, "literal": "^3.0.0", @@ -1856,7 +1856,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 142, "literal": "^1.2.1", @@ -1869,7 +1869,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 143, "literal": "^1.4.10", @@ -1882,7 +1882,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 144, "literal": "^0.3.24", @@ -1895,7 +1895,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 145, "literal": "^3.1.0", @@ -1908,7 +1908,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 146, "literal": "^1.4.14", @@ -1921,7 +1921,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 147, "literal": "^0.23.0", @@ -1934,7 +1934,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 148, "literal": "^1.1.0", @@ -1960,7 +1960,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 150, "literal": "^1.1.0", @@ -1973,7 +1973,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 151, "literal": "^3.0.0 || ^4.0.0", @@ -1986,7 +1986,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 152, "literal": "^1.1.0", @@ -1999,7 +1999,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 153, "literal": "9.0.0", @@ -2012,7 +2012,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 154, "literal": "22.12.0", @@ -2025,7 +2025,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 155, "literal": "2.2.3", @@ -2038,7 +2038,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 156, "literal": "0.0.1299070", @@ -2051,7 +2051,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 157, "literal": "4.3.4", @@ -2064,7 +2064,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 158, "literal": "2.0.1", @@ -2077,7 +2077,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 159, "literal": "2.0.3", @@ -2090,7 +2090,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 160, "literal": "6.4.0", @@ -2103,7 +2103,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 161, "literal": "3.0.5", @@ -2116,7 +2116,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 162, "literal": "1.4.3", @@ -2129,7 +2129,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 163, "literal": "17.7.2", @@ -2142,7 +2142,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 164, "literal": "7.6.0", @@ -2155,7 +2155,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 165, "literal": "^6.0.0", @@ -2168,7 +2168,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 166, "literal": "^4.0.0", @@ -2181,7 +2181,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 167, "literal": "^8.0.1", @@ -2194,7 +2194,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 168, "literal": "^3.1.1", @@ -2207,7 +2207,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 169, "literal": "^2.0.5", @@ -2220,7 +2220,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 170, "literal": "^2.1.1", @@ -2233,7 +2233,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 171, "literal": "^4.2.3", @@ -2246,7 +2246,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 172, "literal": "^5.0.5", @@ -2259,7 +2259,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 173, "literal": "^21.1.1", @@ -2272,7 +2272,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 174, "literal": "^4.2.0", @@ -2285,7 +2285,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 175, "literal": "^6.0.1", @@ -2298,7 +2298,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 176, "literal": "^7.0.0", @@ -2311,7 +2311,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 177, "literal": "^5.2.1", @@ -2324,7 +2324,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 178, "literal": "^2.3.8", @@ -2337,7 +2337,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 179, "literal": "^1.3.1", @@ -2350,7 +2350,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 180, "literal": "^1.1.13", @@ -2363,7 +2363,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 181, "literal": "^3.0.0", @@ -2376,7 +2376,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 182, "literal": "^3.1.5", @@ -2415,7 +2415,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 185, "literal": "^2.1.0", @@ -2428,7 +2428,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 186, "literal": "^2.0.0", @@ -2441,7 +2441,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 187, "literal": "^2.0.0", @@ -2454,7 +2454,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 188, "literal": "^2.0.0", @@ -2467,7 +2467,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 189, "literal": "^2.18.0", @@ -2480,7 +2480,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 190, "literal": "^1.3.2", @@ -2493,7 +2493,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 191, "literal": "^1.0.1", @@ -2506,7 +2506,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 192, "literal": "^1.1.0", @@ -2532,7 +2532,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 194, "literal": "^1.6.4", @@ -2545,7 +2545,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 195, "literal": "^1.6.4", @@ -2558,7 +2558,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 196, "literal": "^1.2.0", @@ -2571,7 +2571,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 197, "literal": "^2.15.0", @@ -2584,7 +2584,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 198, "literal": "^1.1.0", @@ -2597,7 +2597,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 199, "literal": "^1.3.1", @@ -2610,7 +2610,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 200, "literal": "1", @@ -2623,7 +2623,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 201, "literal": "^1.4.0", @@ -2636,7 +2636,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 202, "literal": "^7.0.2", @@ -2649,7 +2649,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 203, "literal": "^4.3.4", @@ -2662,7 +2662,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 204, "literal": "^7.0.1", @@ -2675,7 +2675,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 205, "literal": "^7.0.3", @@ -2688,7 +2688,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 206, "literal": "^7.14.1", @@ -2701,7 +2701,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 207, "literal": "^7.0.1", @@ -2714,7 +2714,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 208, "literal": "^1.1.0", @@ -2727,7 +2727,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 209, "literal": "^8.0.2", @@ -2740,7 +2740,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 210, "literal": "^7.1.1", @@ -2753,7 +2753,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 211, "literal": "^4.3.4", @@ -2766,7 +2766,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 212, "literal": "^2.7.1", @@ -2779,7 +2779,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 213, "literal": "^9.0.5", @@ -2792,7 +2792,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 214, "literal": "^4.2.0", @@ -2805,7 +2805,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 215, "literal": "1.1.0", @@ -2818,7 +2818,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 216, "literal": "^1.1.3", @@ -2831,7 +2831,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 217, "literal": "2.1.2", @@ -2844,7 +2844,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 218, "literal": "^4.3.4", @@ -2857,7 +2857,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 219, "literal": "^0.23.0", @@ -2870,7 +2870,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 220, "literal": "^7.0.2", @@ -2883,7 +2883,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 221, "literal": "^4.3.4", @@ -2896,7 +2896,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 222, "literal": "^6.0.1", @@ -2909,7 +2909,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 223, "literal": "^7.0.0", @@ -2922,7 +2922,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 224, "literal": "^7.0.2", @@ -2935,7 +2935,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 225, "literal": "^7.0.0", @@ -2948,7 +2948,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 226, "literal": "^8.0.2", @@ -2961,7 +2961,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 227, "literal": "^5.0.0", @@ -2974,7 +2974,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 228, "literal": "^2.0.2", @@ -2987,7 +2987,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 229, "literal": "^0.13.4", @@ -3000,7 +3000,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 230, "literal": "^2.1.0", @@ -3013,7 +3013,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 231, "literal": "^4.0.1", @@ -3026,7 +3026,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 232, "literal": "^5.2.0", @@ -3039,7 +3039,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 233, "literal": "^2.0.2", @@ -3052,7 +3052,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 234, "literal": "^4.0.1", @@ -3078,7 +3078,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 236, "literal": "^2.0.1", @@ -3091,7 +3091,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 237, "literal": "^7.0.2", @@ -3104,7 +3104,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 238, "literal": "4", @@ -3117,7 +3117,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 239, "literal": "^7.1.0", @@ -3130,7 +3130,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 240, "literal": "^4.3.4", @@ -3143,7 +3143,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 241, "literal": "^5.0.2", @@ -3156,7 +3156,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 242, "literal": "^6.0.2", @@ -3169,7 +3169,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 243, "literal": "^4.3.4", @@ -3182,7 +3182,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 244, "literal": "^11.2.0", @@ -3195,7 +3195,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 245, "literal": "^4.2.0", @@ -3208,7 +3208,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 246, "literal": "^6.0.1", @@ -3221,7 +3221,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 247, "literal": "^2.0.0", @@ -3234,7 +3234,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 248, "literal": "^2.0.0", @@ -3260,7 +3260,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 250, "literal": "^4.1.1", @@ -3273,7 +3273,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 251, "literal": "^5.1.0", @@ -3286,7 +3286,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 252, "literal": "^2.10.0", @@ -3312,7 +3312,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 254, "literal": "*", @@ -3325,7 +3325,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 255, "literal": "~5.26.4", @@ -3338,7 +3338,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 256, "literal": "~1.1.0", @@ -3351,7 +3351,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 257, "literal": "~0.2.3", @@ -3364,7 +3364,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 258, "literal": "~1.2.0", @@ -3377,7 +3377,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 259, "literal": "^3.0.0", @@ -3390,7 +3390,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 260, "literal": "2.1.2", @@ -3403,7 +3403,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 261, "literal": "2.2.3", @@ -3416,7 +3416,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 262, "literal": "0.5.24", @@ -3429,7 +3429,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 263, "literal": "4.3.5", @@ -3442,7 +3442,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 264, "literal": "0.0.1299070", @@ -3455,7 +3455,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 265, "literal": "8.17.1", @@ -3496,7 +3496,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 268, "literal": "3.0.1", @@ -3509,7 +3509,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 269, "literal": "10.0.0", @@ -3522,7 +3522,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 270, "literal": "3.23.8", @@ -3548,7 +3548,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 272, "literal": "^2.2.1", @@ -3561,7 +3561,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 273, "literal": "^3.3.0", @@ -3574,7 +3574,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 274, "literal": "^4.1.0", @@ -3587,7 +3587,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 275, "literal": "^5.2.0", @@ -3614,7 +3614,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 277, "literal": "^7.0.0", @@ -3627,7 +3627,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 278, "literal": "^1.3.1", @@ -3640,7 +3640,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 279, "literal": "^2.3.0", @@ -3653,7 +3653,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 280, "literal": "^1.1.6", @@ -3666,7 +3666,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 281, "literal": "^0.2.1", @@ -3679,7 +3679,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 282, "literal": "^7.24.7", @@ -3692,7 +3692,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 283, "literal": "^1.0.0", @@ -3705,7 +3705,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 284, "literal": "^7.24.7", @@ -3718,7 +3718,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 285, "literal": "^2.4.2", @@ -3731,7 +3731,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 286, "literal": "^4.0.0", @@ -3744,7 +3744,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 287, "literal": "^1.0.0", @@ -3757,7 +3757,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 288, "literal": "^3.2.1", @@ -3770,7 +3770,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 289, "literal": "^1.0.5", @@ -3783,7 +3783,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 290, "literal": "^5.3.0", @@ -3796,7 +3796,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 291, "literal": "^3.0.0", @@ -3809,7 +3809,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 292, "literal": "^1.9.0", @@ -3822,7 +3822,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 293, "literal": "1.1.3", @@ -3835,7 +3835,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 294, "literal": "^2.0.1", @@ -3848,7 +3848,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 295, "literal": "^1.0.0", @@ -3861,7 +3861,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 296, "literal": "^4.0.0", @@ -3874,7 +3874,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 297, "literal": "^3.0.0", @@ -3887,7 +3887,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 298, "literal": "1.6.0", @@ -3900,7 +3900,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 299, "literal": "8.4.31", @@ -3913,7 +3913,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 300, "literal": "14.1.3", @@ -3926,7 +3926,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 301, "literal": "5.1.1", @@ -3939,7 +3939,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 302, "literal": "^4.2.11", @@ -3952,7 +3952,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 303, "literal": "0.5.2", @@ -3965,7 +3965,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 304, "literal": "^1.0.30001579", @@ -4149,7 +4149,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 318, "literal": "^2.4.0", @@ -4162,7 +4162,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 319, "literal": "0.0.1", @@ -4188,7 +4188,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 321, "literal": "^3.3.6", @@ -4201,7 +4201,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 322, "literal": "^1.0.0", @@ -4214,7 +4214,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 323, "literal": "^1.0.2", @@ -4227,7 +4227,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 324, "literal": "^1.1.0", @@ -4240,7 +4240,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 325, "literal": "^7.33.2", @@ -4253,7 +4253,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 326, "literal": "^2.28.1", @@ -4266,7 +4266,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 327, "literal": "^6.7.1", @@ -4279,7 +4279,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 328, "literal": "^1.3.3", @@ -4292,7 +4292,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 329, "literal": "14.1.3", @@ -4305,7 +4305,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 330, "literal": "^5.4.2 || ^6.0.0", @@ -4318,7 +4318,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 331, "literal": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705", @@ -4331,7 +4331,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 332, "literal": "^0.3.6", @@ -4344,7 +4344,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 333, "literal": "^3.5.2", @@ -4384,7 +4384,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 336, "literal": "^6.12.4", @@ -4397,7 +4397,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 337, "literal": "^0.4.1", @@ -4410,7 +4410,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 338, "literal": "^4.0.0", @@ -4423,7 +4423,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 339, "literal": "^4.3.2", @@ -4436,7 +4436,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 340, "literal": "^9.6.1", @@ -4449,7 +4449,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 341, "literal": "^5.2.0", @@ -4462,7 +4462,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 342, "literal": "^1.4.2", @@ -4475,7 +4475,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 343, "literal": "^2.0.2", @@ -4488,7 +4488,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 344, "literal": "^5.0.0", @@ -4501,7 +4501,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 345, "literal": "^13.19.0", @@ -4514,7 +4514,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 346, "literal": "^4.0.0", @@ -4527,7 +4527,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 347, "literal": "^4.1.0", @@ -4540,7 +4540,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 348, "literal": "^3.0.0", @@ -4553,7 +4553,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 349, "literal": "^1.4.0", @@ -4566,7 +4566,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 350, "literal": "^3.1.2", @@ -4579,7 +4579,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 351, "literal": "8.50.0", @@ -4592,7 +4592,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 352, "literal": "^0.9.3", @@ -4605,7 +4605,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 353, "literal": "^6.0.1", @@ -4618,7 +4618,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 354, "literal": "^0.2.0", @@ -4631,7 +4631,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 355, "literal": "^7.0.2", @@ -4644,7 +4644,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 356, "literal": "^6.0.2", @@ -4657,7 +4657,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 357, "literal": "^0.1.4", @@ -4670,7 +4670,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 358, "literal": "^7.2.2", @@ -4683,7 +4683,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 359, "literal": "^4.6.2", @@ -4696,7 +4696,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 360, "literal": "^3.0.3", @@ -4709,7 +4709,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 361, "literal": "^3.1.3", @@ -4722,7 +4722,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 362, "literal": "^1.4.0", @@ -4735,7 +4735,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 363, "literal": "^2.1.2", @@ -4748,7 +4748,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 364, "literal": "^1.2.8", @@ -4761,7 +4761,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 365, "literal": "^6.0.1", @@ -4774,7 +4774,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 366, "literal": "^3.4.3", @@ -4787,7 +4787,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 367, "literal": "^4.0.0", @@ -4800,7 +4800,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 368, "literal": "^4.6.1", @@ -4813,7 +4813,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 369, "literal": "^0.11.11", @@ -4826,7 +4826,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 370, "literal": "^4.2.0", @@ -4839,7 +4839,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 371, "literal": "^1.0.1", @@ -4852,7 +4852,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 372, "literal": "^1.0.1", @@ -4865,7 +4865,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 373, "literal": "^3.3.0", @@ -4891,7 +4891,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 375, "literal": "^2.0.2", @@ -4904,7 +4904,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 376, "literal": "^4.3.1", @@ -4917,7 +4917,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 377, "literal": "^3.0.5", @@ -4930,7 +4930,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 378, "literal": "^1.1.7", @@ -4943,7 +4943,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 379, "literal": "^1.0.0", @@ -4956,7 +4956,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 380, "literal": "0.0.1", @@ -4969,7 +4969,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 381, "literal": "^3.0.4", @@ -4982,7 +4982,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 382, "literal": "^3.2.9", @@ -4995,7 +4995,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 383, "literal": "^4.5.3", @@ -5008,7 +5008,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 384, "literal": "^3.0.2", @@ -5021,7 +5021,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 385, "literal": "^7.1.3", @@ -5034,7 +5034,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 386, "literal": "^1.0.0", @@ -5047,7 +5047,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 387, "literal": "^1.0.4", @@ -5060,7 +5060,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 388, "literal": "2", @@ -5073,7 +5073,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 389, "literal": "^3.1.1", @@ -5086,7 +5086,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 390, "literal": "^1.3.0", @@ -5099,7 +5099,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 391, "literal": "^1.0.0", @@ -5112,7 +5112,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 392, "literal": "^1.3.0", @@ -5125,7 +5125,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 393, "literal": "1", @@ -5138,7 +5138,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 394, "literal": "3.0.1", @@ -5151,7 +5151,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 395, "literal": "^6.12.4", @@ -5164,7 +5164,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 396, "literal": "^4.3.2", @@ -5177,7 +5177,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 397, "literal": "^9.6.0", @@ -5190,7 +5190,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 398, "literal": "^13.19.0", @@ -5203,7 +5203,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 399, "literal": "^5.2.0", @@ -5216,7 +5216,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 400, "literal": "^3.2.1", @@ -5229,7 +5229,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 401, "literal": "^4.1.0", @@ -5242,7 +5242,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 402, "literal": "^3.1.2", @@ -5255,7 +5255,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 403, "literal": "^3.1.1", @@ -5268,7 +5268,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 404, "literal": "^0.20.2", @@ -5281,7 +5281,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 405, "literal": "^8.9.0", @@ -5294,7 +5294,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 406, "literal": "^5.3.2", @@ -5307,7 +5307,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 407, "literal": "^3.4.1", @@ -5333,7 +5333,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 409, "literal": "^3.1.1", @@ -5346,7 +5346,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 410, "literal": "^2.0.0", @@ -5359,7 +5359,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 411, "literal": "^0.4.1", @@ -5372,7 +5372,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 412, "literal": "^4.2.2", @@ -5385,7 +5385,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 413, "literal": "^2.1.0", @@ -5398,7 +5398,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 414, "literal": "^4.3.0", @@ -5411,7 +5411,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 415, "literal": "^5.2.0", @@ -5424,7 +5424,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 416, "literal": "^5.2.0", @@ -5437,7 +5437,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 417, "literal": "^1.2.1", @@ -5450,7 +5450,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 418, "literal": "^0.1.3", @@ -5463,7 +5463,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 419, "literal": "^1.2.5", @@ -5476,7 +5476,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 420, "literal": "^0.4.0", @@ -5489,7 +5489,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 421, "literal": "^0.4.1", @@ -5502,7 +5502,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 422, "literal": "^2.0.6", @@ -5515,7 +5515,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 423, "literal": "^1.2.1", @@ -5528,7 +5528,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 424, "literal": "~0.4.0", @@ -5541,7 +5541,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 425, "literal": "^1.2.1", @@ -5554,7 +5554,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 426, "literal": "^2.0.2", @@ -5567,7 +5567,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 427, "literal": "^6.0.0", @@ -5580,7 +5580,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 428, "literal": "^4.0.0", @@ -5593,7 +5593,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 429, "literal": "^5.0.0", @@ -5606,7 +5606,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 430, "literal": "^3.0.2", @@ -5619,7 +5619,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 431, "literal": "^0.1.0", @@ -5632,7 +5632,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 432, "literal": "^5.1.0", @@ -5645,7 +5645,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 433, "literal": "^4.1.0", @@ -5658,7 +5658,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 434, "literal": "^7.1.0", @@ -5671,7 +5671,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 435, "literal": "^4.0.0", @@ -5684,7 +5684,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 436, "literal": "^4.3.4", @@ -5697,7 +5697,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 437, "literal": "^5.12.0", @@ -5710,7 +5710,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 438, "literal": "^2.7.4", @@ -5723,7 +5723,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 439, "literal": "^3.3.1", @@ -5736,7 +5736,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 440, "literal": "^4.5.0", @@ -5749,7 +5749,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 441, "literal": "^2.11.0", @@ -5762,7 +5762,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 442, "literal": "^4.0.3", @@ -5801,7 +5801,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 445, "literal": "^3.1.7", @@ -5814,7 +5814,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 446, "literal": "^1.2.3", @@ -5827,7 +5827,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 447, "literal": "^1.3.2", @@ -5840,7 +5840,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 448, "literal": "^1.3.2", @@ -5853,7 +5853,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 449, "literal": "^3.2.7", @@ -5866,7 +5866,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 450, "literal": "^2.1.0", @@ -5879,7 +5879,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 451, "literal": "^0.3.9", @@ -5892,7 +5892,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 452, "literal": "^2.8.0", @@ -5905,7 +5905,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 453, "literal": "^2.0.0", @@ -5918,7 +5918,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 454, "literal": "^2.13.1", @@ -5931,7 +5931,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 455, "literal": "^4.0.3", @@ -5944,7 +5944,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 456, "literal": "^3.1.2", @@ -5957,7 +5957,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 457, "literal": "^2.0.7", @@ -5970,7 +5970,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 458, "literal": "^1.0.1", @@ -5983,7 +5983,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 459, "literal": "^1.1.7", @@ -5996,7 +5996,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 460, "literal": "^6.3.1", @@ -6009,7 +6009,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 461, "literal": "^3.15.0", @@ -6035,7 +6035,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 463, "literal": "^0.0.29", @@ -6048,7 +6048,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 464, "literal": "^1.0.2", @@ -6061,7 +6061,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 465, "literal": "^1.2.6", @@ -6074,7 +6074,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 466, "literal": "^3.0.0", @@ -6087,7 +6087,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 467, "literal": "^1.2.0", @@ -6100,7 +6100,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 468, "literal": "^1.0.7", @@ -6113,7 +6113,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 469, "literal": "^1.2.1", @@ -6126,7 +6126,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 470, "literal": "^1.0.0", @@ -6139,7 +6139,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 471, "literal": "^1.3.0", @@ -6152,7 +6152,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 472, "literal": "^1.0.1", @@ -6165,7 +6165,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 473, "literal": "^1.0.0", @@ -6178,7 +6178,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 474, "literal": "^1.1.1", @@ -6191,7 +6191,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 475, "literal": "^1.0.0", @@ -6204,7 +6204,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 476, "literal": "^1.2.4", @@ -6217,7 +6217,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 477, "literal": "^1.3.0", @@ -6230,7 +6230,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 478, "literal": "^1.1.2", @@ -6243,7 +6243,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 479, "literal": "^1.0.1", @@ -6256,7 +6256,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 480, "literal": "^1.0.3", @@ -6269,7 +6269,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 481, "literal": "^2.0.0", @@ -6282,7 +6282,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 482, "literal": "^1.0.0", @@ -6295,7 +6295,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 483, "literal": "^1.3.0", @@ -6308,7 +6308,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 484, "literal": "^1.0.1", @@ -6321,7 +6321,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 485, "literal": "^1.1.3", @@ -6334,7 +6334,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 486, "literal": "^1.0.0", @@ -6347,7 +6347,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 487, "literal": "^1.3.0", @@ -6360,7 +6360,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 488, "literal": "^1.1.2", @@ -6373,7 +6373,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 489, "literal": "^1.2.4", @@ -6386,7 +6386,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 490, "literal": "^1.2.1", @@ -6399,7 +6399,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 491, "literal": "^1.1.4", @@ -6412,7 +6412,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 492, "literal": "^1.3.0", @@ -6425,7 +6425,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 493, "literal": "^1.1.2", @@ -6438,7 +6438,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 494, "literal": "^1.2.4", @@ -6451,7 +6451,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 495, "literal": "^1.0.1", @@ -6464,7 +6464,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 496, "literal": "^1.0.2", @@ -6477,7 +6477,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 497, "literal": "^1.0.7", @@ -6490,7 +6490,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 498, "literal": "^1.2.1", @@ -6503,7 +6503,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 499, "literal": "^1.23.2", @@ -6516,7 +6516,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 500, "literal": "^1.0.1", @@ -6529,7 +6529,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 501, "literal": "^1.0.3", @@ -6542,7 +6542,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 502, "literal": "^1.0.7", @@ -6555,7 +6555,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 503, "literal": "^1.0.7", @@ -6568,7 +6568,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 504, "literal": "^1.0.1", @@ -6581,7 +6581,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 505, "literal": "^1.0.1", @@ -6594,7 +6594,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 506, "literal": "^1.0.0", @@ -6607,7 +6607,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 507, "literal": "^1.0.0", @@ -6620,7 +6620,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 508, "literal": "^1.3.0", @@ -6633,7 +6633,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 509, "literal": "^1.0.0", @@ -6646,7 +6646,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 510, "literal": "^2.0.3", @@ -6659,7 +6659,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 511, "literal": "^1.2.1", @@ -6672,7 +6672,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 512, "literal": "^1.1.6", @@ -6685,7 +6685,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 513, "literal": "^1.2.4", @@ -6698,7 +6698,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 514, "literal": "^1.0.2", @@ -6711,7 +6711,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 515, "literal": "^1.0.3", @@ -6724,7 +6724,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 516, "literal": "^1.0.1", @@ -6737,7 +6737,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 517, "literal": "^1.0.2", @@ -6750,7 +6750,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 518, "literal": "^1.0.3", @@ -6763,7 +6763,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 519, "literal": "^1.0.3", @@ -6776,7 +6776,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 520, "literal": "^2.0.2", @@ -6789,7 +6789,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 521, "literal": "^1.0.7", @@ -6802,7 +6802,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 522, "literal": "^3.0.4", @@ -6815,7 +6815,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 523, "literal": "^1.2.7", @@ -6828,7 +6828,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 524, "literal": "^1.0.1", @@ -6841,7 +6841,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 525, "literal": "^2.0.3", @@ -6854,7 +6854,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 526, "literal": "^1.1.4", @@ -6867,7 +6867,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 527, "literal": "^1.0.3", @@ -6880,7 +6880,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 528, "literal": "^1.0.7", @@ -6893,7 +6893,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 529, "literal": "^1.1.13", @@ -6906,7 +6906,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 530, "literal": "^1.0.2", @@ -6919,7 +6919,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 531, "literal": "^1.13.1", @@ -6932,7 +6932,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 532, "literal": "^1.1.1", @@ -6945,7 +6945,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 533, "literal": "^4.1.5", @@ -6958,7 +6958,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 534, "literal": "^1.5.2", @@ -6971,7 +6971,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 535, "literal": "^1.1.2", @@ -6984,7 +6984,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 536, "literal": "^1.0.3", @@ -6997,7 +6997,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 537, "literal": "^1.2.9", @@ -7010,7 +7010,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 538, "literal": "^1.0.8", @@ -7023,7 +7023,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 539, "literal": "^1.0.8", @@ -7036,7 +7036,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 540, "literal": "^1.0.2", @@ -7049,7 +7049,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 541, "literal": "^1.0.1", @@ -7062,7 +7062,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 542, "literal": "^1.0.2", @@ -7075,7 +7075,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 543, "literal": "^1.0.6", @@ -7088,7 +7088,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 544, "literal": "^1.0.2", @@ -7101,7 +7101,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 545, "literal": "^1.1.15", @@ -7114,7 +7114,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 546, "literal": "^1.0.7", @@ -7127,7 +7127,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 547, "literal": "^1.0.7", @@ -7140,7 +7140,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 548, "literal": "^0.3.3", @@ -7153,7 +7153,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 549, "literal": "^1.0.1", @@ -7166,7 +7166,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 550, "literal": "^1.0.2", @@ -7179,7 +7179,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 551, "literal": "^1.0.3", @@ -7192,7 +7192,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 552, "literal": "^1.1.3", @@ -7205,7 +7205,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 553, "literal": "^1.0.0", @@ -7218,7 +7218,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 554, "literal": "^1.0.2", @@ -7231,7 +7231,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 555, "literal": "^1.0.2", @@ -7244,7 +7244,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 556, "literal": "^1.0.3", @@ -7257,7 +7257,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 557, "literal": "^1.0.2", @@ -7270,7 +7270,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 558, "literal": "^1.0.1", @@ -7283,7 +7283,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 559, "literal": "^1.1.0", @@ -7296,7 +7296,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 560, "literal": "^1.0.4", @@ -7309,7 +7309,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 561, "literal": "^1.0.5", @@ -7322,7 +7322,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 562, "literal": "^1.0.3", @@ -7335,7 +7335,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 563, "literal": "^1.0.2", @@ -7348,7 +7348,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 564, "literal": "^1.0.0", @@ -7361,7 +7361,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 565, "literal": "^1.0.0", @@ -7374,7 +7374,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 566, "literal": "^1.0.2", @@ -7387,7 +7387,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 567, "literal": "^1.0.0", @@ -7400,7 +7400,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 568, "literal": "^1.0.1", @@ -7413,7 +7413,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 569, "literal": "^1.0.7", @@ -7426,7 +7426,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 570, "literal": "^0.3.3", @@ -7439,7 +7439,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 571, "literal": "^1.0.1", @@ -7452,7 +7452,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 572, "literal": "^1.0.3", @@ -7465,7 +7465,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 573, "literal": "^1.1.13", @@ -7478,7 +7478,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 574, "literal": "^1.0.0", @@ -7491,7 +7491,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 575, "literal": "^1.1.14", @@ -7504,7 +7504,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 576, "literal": "^1.0.7", @@ -7517,7 +7517,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 577, "literal": "^1.0.7", @@ -7530,7 +7530,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 578, "literal": "^0.3.3", @@ -7543,7 +7543,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 579, "literal": "^1.0.1", @@ -7556,7 +7556,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 580, "literal": "^1.0.3", @@ -7569,7 +7569,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 581, "literal": "^1.1.13", @@ -7582,7 +7582,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 582, "literal": "^1.0.7", @@ -7595,7 +7595,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 583, "literal": "^0.3.3", @@ -7608,7 +7608,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 584, "literal": "^1.0.1", @@ -7621,7 +7621,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 585, "literal": "^1.0.3", @@ -7634,7 +7634,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 586, "literal": "^1.1.13", @@ -7647,7 +7647,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 587, "literal": "^1.0.7", @@ -7660,7 +7660,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 588, "literal": "^1.3.0", @@ -7673,7 +7673,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 589, "literal": "^1.1.13", @@ -7686,7 +7686,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 590, "literal": "^1.0.7", @@ -7699,7 +7699,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 591, "literal": "^1.2.1", @@ -7712,7 +7712,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 592, "literal": "^1.0.0", @@ -7725,7 +7725,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 593, "literal": "^1.0.7", @@ -7738,7 +7738,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 594, "literal": "^1.2.1", @@ -7751,7 +7751,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 595, "literal": "^1.0.0", @@ -7764,7 +7764,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 596, "literal": "^1.0.7", @@ -7777,7 +7777,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 597, "literal": "^1.2.1", @@ -7790,7 +7790,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 598, "literal": "^1.23.0", @@ -7803,7 +7803,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 599, "literal": "^1.0.0", @@ -7816,7 +7816,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 600, "literal": "^1.0.6", @@ -7829,7 +7829,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 601, "literal": "^1.3.0", @@ -7842,7 +7842,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 602, "literal": "^1.1.4", @@ -7855,7 +7855,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 603, "literal": "^1.0.2", @@ -7868,7 +7868,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 604, "literal": "^1.0.0", @@ -7881,7 +7881,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 605, "literal": "^1.0.7", @@ -7894,7 +7894,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 606, "literal": "^1.2.4", @@ -7907,7 +7907,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 607, "literal": "^1.0.3", @@ -7920,7 +7920,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 608, "literal": "^2.0.5", @@ -7933,7 +7933,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 609, "literal": "^1.0.6", @@ -7946,7 +7946,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 610, "literal": "^1.2.1", @@ -7959,7 +7959,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 611, "literal": "^1.3.0", @@ -7972,7 +7972,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 612, "literal": "^2.0.1", @@ -7985,7 +7985,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 613, "literal": "^1.1.4", @@ -7998,7 +7998,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 614, "literal": "^1.3.0", @@ -8011,7 +8011,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 615, "literal": "^1.2.3", @@ -8024,7 +8024,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 616, "literal": "^1.0.2", @@ -8037,7 +8037,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 617, "literal": "^1.0.5", @@ -8050,7 +8050,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 618, "literal": "^1.2.1", @@ -8063,7 +8063,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 619, "literal": "^1.0.3", @@ -8076,7 +8076,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 620, "literal": "^1.1.1", @@ -8089,7 +8089,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 621, "literal": "^1.0.2", @@ -8102,7 +8102,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 622, "literal": "^1.0.7", @@ -8115,7 +8115,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 623, "literal": "^1.1.13", @@ -8128,7 +8128,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 624, "literal": "^1.0.2", @@ -8141,7 +8141,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 625, "literal": "^1.2.1", @@ -8154,7 +8154,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 626, "literal": "^1.3.0", @@ -8167,7 +8167,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 627, "literal": "^2.0.0", @@ -8180,7 +8180,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 628, "literal": "^1.0.4", @@ -8193,7 +8193,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 629, "literal": "^1.0.7", @@ -8206,7 +8206,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 630, "literal": "^1.3.0", @@ -8219,7 +8219,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 631, "literal": "^1.2.4", @@ -8232,7 +8232,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 632, "literal": "^1.13.1", @@ -8245,7 +8245,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 633, "literal": "^1.2.1", @@ -8258,7 +8258,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 634, "literal": "^1.0.1", @@ -8271,7 +8271,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 635, "literal": "^1.0.5", @@ -8284,7 +8284,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 636, "literal": "^1.3.0", @@ -8297,7 +8297,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 637, "literal": "^1.2.4", @@ -8310,7 +8310,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 638, "literal": "^1.0.2", @@ -8323,7 +8323,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 639, "literal": "^1.2.0", @@ -8336,7 +8336,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 640, "literal": "^1.22.1", @@ -8349,7 +8349,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 641, "literal": "^1.2.3", @@ -8362,7 +8362,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 642, "literal": "^1.1.4", @@ -8375,7 +8375,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 643, "literal": "^1.0.1", @@ -8388,7 +8388,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 644, "literal": "^1.0.2", @@ -8401,7 +8401,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 645, "literal": "^1.0.0", @@ -8414,7 +8414,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 646, "literal": "^1.2.4", @@ -8427,7 +8427,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 647, "literal": "^1.0.2", @@ -8440,7 +8440,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 648, "literal": "^2.0.1", @@ -8453,7 +8453,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 649, "literal": "^1.0.6", @@ -8466,7 +8466,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 650, "literal": "^1.3.0", @@ -8479,7 +8479,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 651, "literal": "^1.0.1", @@ -8492,7 +8492,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 652, "literal": "^1.0.7", @@ -8505,7 +8505,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 653, "literal": "^1.3.0", @@ -8518,7 +8518,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 654, "literal": "^1.0.1", @@ -8531,7 +8531,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 655, "literal": "^1.0.6", @@ -8544,7 +8544,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 656, "literal": "^1.3.0", @@ -8557,7 +8557,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 657, "literal": "^1.0.1", @@ -8570,7 +8570,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 658, "literal": "^1.0.1", @@ -8583,7 +8583,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 659, "literal": "^1.0.5", @@ -8596,7 +8596,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 660, "literal": "^1.2.1", @@ -8609,7 +8609,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 661, "literal": "^1.22.3", @@ -8622,7 +8622,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 662, "literal": "^1.2.1", @@ -8635,7 +8635,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 663, "literal": "^1.2.3", @@ -8648,7 +8648,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 664, "literal": "^3.0.4", @@ -8661,7 +8661,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 665, "literal": "^1.0.2", @@ -8674,7 +8674,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 666, "literal": "^1.0.5", @@ -8687,7 +8687,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 667, "literal": "^3.0.4", @@ -8700,7 +8700,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 668, "literal": "^1.0.7", @@ -8713,7 +8713,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 669, "literal": "^1.2.1", @@ -8726,7 +8726,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 670, "literal": "^1.23.2", @@ -8739,7 +8739,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 671, "literal": "^1.0.0", @@ -8752,7 +8752,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 672, "literal": "^3.2.7", @@ -8765,7 +8765,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 673, "literal": "^2.1.1", @@ -8778,7 +8778,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 674, "literal": "^3.2.7", @@ -8791,7 +8791,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 675, "literal": "^2.13.0", @@ -8804,7 +8804,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 676, "literal": "^1.22.4", @@ -8817,7 +8817,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 677, "literal": "^2.0.2", @@ -8830,7 +8830,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 678, "literal": "^1.0.2", @@ -8843,7 +8843,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 679, "literal": "^1.2.0", @@ -8856,7 +8856,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 680, "literal": "^1.22.1", @@ -8869,7 +8869,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 681, "literal": "^1.0.0", @@ -8882,7 +8882,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 682, "literal": "^2.0.0", @@ -8895,7 +8895,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 683, "literal": "^1.0.2", @@ -8908,7 +8908,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 684, "literal": "^1.2.0", @@ -8921,7 +8921,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 685, "literal": "^1.22.1", @@ -8934,7 +8934,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 686, "literal": "^1.0.0", @@ -8947,7 +8947,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 687, "literal": "^1.0.7", @@ -8960,7 +8960,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 688, "literal": "^1.2.1", @@ -8973,7 +8973,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 689, "literal": "^1.23.2", @@ -8986,7 +8986,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 690, "literal": "^1.3.0", @@ -8999,7 +8999,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 691, "literal": "^1.0.0", @@ -9012,7 +9012,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 692, "literal": "^1.0.2", @@ -9025,7 +9025,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 693, "literal": "^1.0.7", @@ -9038,7 +9038,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 694, "literal": "^1.2.1", @@ -9051,7 +9051,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 695, "literal": "^1.23.2", @@ -9064,7 +9064,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 696, "literal": "^1.0.0", @@ -9077,7 +9077,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 697, "literal": "^1.2.4", @@ -9090,7 +9090,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 698, "literal": "^1.0.7", @@ -9103,7 +9103,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 699, "literal": "^1.0.0", @@ -9116,7 +9116,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 700, "literal": "^4.2.4", @@ -9129,7 +9129,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 701, "literal": "^2.2.0", @@ -9155,7 +9155,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 703, "literal": "^4.3.4", @@ -9168,7 +9168,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 704, "literal": "6.21.0", @@ -9181,7 +9181,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 705, "literal": "6.21.0", @@ -9194,7 +9194,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 706, "literal": "6.21.0", @@ -9207,7 +9207,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 707, "literal": "6.21.0", @@ -9233,7 +9233,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 709, "literal": "^4.3.4", @@ -9246,7 +9246,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 710, "literal": "^11.1.0", @@ -9259,7 +9259,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 711, "literal": "^7.5.4", @@ -9272,7 +9272,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 712, "literal": "^4.0.3", @@ -9285,7 +9285,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 713, "literal": "9.0.3", @@ -9298,7 +9298,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 714, "literal": "^1.0.1", @@ -9311,7 +9311,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 715, "literal": "6.21.0", @@ -9324,7 +9324,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 716, "literal": "6.21.0", @@ -9337,7 +9337,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 717, "literal": "^3.4.1", @@ -9350,7 +9350,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 718, "literal": "6.21.0", @@ -9376,7 +9376,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 720, "literal": "^2.0.1", @@ -9389,7 +9389,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 721, "literal": "^2.1.0", @@ -9402,7 +9402,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 722, "literal": "^3.0.1", @@ -9415,7 +9415,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 723, "literal": "^3.2.9", @@ -9428,7 +9428,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 724, "literal": "^5.2.0", @@ -9441,7 +9441,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 725, "literal": "^1.4.1", @@ -9454,7 +9454,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 726, "literal": "^3.0.0", @@ -9467,7 +9467,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 727, "literal": "^4.0.0", @@ -9480,7 +9480,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 728, "literal": "6.21.0", @@ -9493,7 +9493,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 729, "literal": "6.21.0", @@ -9506,7 +9506,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 730, "literal": "10.3.10", @@ -9519,7 +9519,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 731, "literal": "^7.23.2", @@ -9532,7 +9532,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 732, "literal": "^5.3.0", @@ -9545,7 +9545,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 733, "literal": "^3.1.7", @@ -9558,7 +9558,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 734, "literal": "^1.3.2", @@ -9571,7 +9571,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 735, "literal": "^0.0.8", @@ -9584,7 +9584,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 736, "literal": "=4.7.0", @@ -9597,7 +9597,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 737, "literal": "^3.2.1", @@ -9610,7 +9610,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 738, "literal": "^1.0.8", @@ -9623,7 +9623,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 739, "literal": "^9.2.2", @@ -9636,7 +9636,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 740, "literal": "^1.0.15", @@ -9649,7 +9649,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 741, "literal": "^2.0.0", @@ -9662,7 +9662,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 742, "literal": "^3.3.5", @@ -9675,7 +9675,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 743, "literal": "^1.0.9", @@ -9688,7 +9688,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 744, "literal": "^3.1.2", @@ -9701,7 +9701,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 745, "literal": "^1.1.7", @@ -9714,7 +9714,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 746, "literal": "^2.0.7", @@ -9740,7 +9740,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 748, "literal": "^1.0.7", @@ -9753,7 +9753,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 749, "literal": "^1.2.1", @@ -9766,7 +9766,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 750, "literal": "^1.0.0", @@ -9779,7 +9779,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 751, "literal": "^0.3.20", @@ -9792,7 +9792,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 752, "literal": "^3.1.6", @@ -9805,7 +9805,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 753, "literal": "^1.3.1", @@ -9818,7 +9818,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 754, "literal": "^4.1.4", @@ -9831,7 +9831,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 755, "literal": "^1.1.6", @@ -9844,7 +9844,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 756, "literal": "^1.0.7", @@ -9857,7 +9857,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 757, "literal": "^1.2.1", @@ -9870,7 +9870,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 758, "literal": "^1.23.3", @@ -9883,7 +9883,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 759, "literal": "^1.3.0", @@ -9896,7 +9896,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 760, "literal": "^2.0.3", @@ -9909,7 +9909,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 761, "literal": "^1.1.2", @@ -9922,7 +9922,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 762, "literal": "^1.2.4", @@ -9935,7 +9935,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 763, "literal": "^1.0.3", @@ -9948,7 +9948,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 764, "literal": "^1.0.2", @@ -9961,7 +9961,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 765, "literal": "^1.0.3", @@ -9974,7 +9974,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 766, "literal": "^1.0.3", @@ -9987,7 +9987,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 767, "literal": "^1.0.7", @@ -10000,7 +10000,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 768, "literal": "^1.1.2", @@ -10013,7 +10013,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 769, "literal": "^1.1.2", @@ -10026,7 +10026,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 770, "literal": "^1.2.1", @@ -10039,7 +10039,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 771, "literal": "^1.2.1", @@ -10052,7 +10052,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 772, "literal": "^1.0.3", @@ -10065,7 +10065,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 773, "literal": "^1.0.4", @@ -10078,7 +10078,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 774, "literal": "^2.0.1", @@ -10091,7 +10091,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 775, "literal": "^1.0.7", @@ -10104,7 +10104,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 776, "literal": "^1.2.1", @@ -10117,7 +10117,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 777, "literal": "^1.23.1", @@ -10130,7 +10130,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 778, "literal": "^1.3.0", @@ -10143,7 +10143,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 779, "literal": "^1.2.4", @@ -10156,7 +10156,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 780, "literal": "^1.0.3", @@ -10169,7 +10169,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 781, "literal": "^1.1.3", @@ -10182,7 +10182,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 782, "literal": "^1.1.5", @@ -10195,7 +10195,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 783, "literal": "^1.0.0", @@ -10208,7 +10208,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 784, "literal": "^2.0.0", @@ -10221,7 +10221,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 785, "literal": "^1.0.5", @@ -10234,7 +10234,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 786, "literal": "^1.0.2", @@ -10247,7 +10247,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 787, "literal": "^1.0.10", @@ -10260,7 +10260,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 788, "literal": "^1.1.4", @@ -10273,7 +10273,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 789, "literal": "^1.0.2", @@ -10286,7 +10286,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 790, "literal": "^2.0.5", @@ -10299,7 +10299,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 791, "literal": "^1.0.2", @@ -10312,7 +10312,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 792, "literal": "^1.0.1", @@ -10325,7 +10325,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 793, "literal": "^1.1.9", @@ -10338,7 +10338,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 794, "literal": "^2.0.3", @@ -10351,7 +10351,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 795, "literal": "^2.0.3", @@ -10364,7 +10364,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 796, "literal": "^2.0.2", @@ -10377,7 +10377,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 797, "literal": "^2.0.3", @@ -10390,7 +10390,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 798, "literal": "^1.0.7", @@ -10403,7 +10403,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 799, "literal": "^1.2.4", @@ -10416,7 +10416,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 800, "literal": "^1.0.0", @@ -10429,7 +10429,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 801, "literal": "^1.0.2", @@ -10442,7 +10442,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 802, "literal": "^1.0.0", @@ -10455,7 +10455,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 803, "literal": "^2.0.3", @@ -10468,7 +10468,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 804, "literal": "^2.0.3", @@ -10481,7 +10481,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 805, "literal": "^0.14.0", @@ -10494,7 +10494,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 806, "literal": "^3.1.8", @@ -10507,7 +10507,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 807, "literal": "^1.2.5", @@ -10520,7 +10520,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 808, "literal": "^1.3.2", @@ -10533,7 +10533,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 809, "literal": "^1.1.2", @@ -10546,7 +10546,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 810, "literal": "^1.1.3", @@ -10559,7 +10559,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 811, "literal": "^2.1.0", @@ -10572,7 +10572,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 812, "literal": "^1.0.19", @@ -10585,7 +10585,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 813, "literal": "^5.3.0", @@ -10598,7 +10598,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 814, "literal": "^2.4.1 || ^3.0.0", @@ -10611,7 +10611,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 815, "literal": "^3.1.2", @@ -10624,7 +10624,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 816, "literal": "^1.1.8", @@ -10637,7 +10637,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 817, "literal": "^2.0.8", @@ -10650,7 +10650,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 818, "literal": "^1.1.4", @@ -10663,7 +10663,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 819, "literal": "^1.2.0", @@ -10676,7 +10676,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 820, "literal": "^15.8.1", @@ -10689,7 +10689,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 821, "literal": "^2.0.0-next.5", @@ -10702,7 +10702,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 822, "literal": "^6.3.1", @@ -10715,7 +10715,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 823, "literal": "^4.0.11", @@ -10741,7 +10741,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 825, "literal": "^1.0.7", @@ -10754,7 +10754,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 826, "literal": "^1.2.1", @@ -10767,7 +10767,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 827, "literal": "^1.23.2", @@ -10780,7 +10780,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 828, "literal": "^1.3.0", @@ -10793,7 +10793,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 829, "literal": "^1.0.0", @@ -10806,7 +10806,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 830, "literal": "^1.2.4", @@ -10819,7 +10819,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 831, "literal": "^1.0.1", @@ -10832,7 +10832,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 832, "literal": "^1.0.3", @@ -10845,7 +10845,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 833, "literal": "^1.0.7", @@ -10858,7 +10858,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 834, "literal": "^1.5.2", @@ -10871,7 +10871,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 835, "literal": "^2.0.2", @@ -10884,7 +10884,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 836, "literal": "^1.0.6", @@ -10897,7 +10897,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 837, "literal": "^2.13.0", @@ -10910,7 +10910,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 838, "literal": "^1.0.7", @@ -10923,7 +10923,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 839, "literal": "^1.0.0", @@ -10936,7 +10936,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 840, "literal": "^1.4.0", @@ -10949,7 +10949,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 841, "literal": "^4.1.1", @@ -10962,7 +10962,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 842, "literal": "^16.13.1", @@ -10975,7 +10975,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 843, "literal": "^1.2.1", @@ -10988,7 +10988,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 844, "literal": "^1.23.2", @@ -11001,7 +11001,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 845, "literal": "^1.0.0", @@ -11014,7 +11014,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 846, "literal": "^1.0.7", @@ -11027,7 +11027,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 847, "literal": "^1.2.1", @@ -11040,7 +11040,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 848, "literal": "^1.23.3", @@ -11053,7 +11053,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 849, "literal": "^1.3.0", @@ -11066,7 +11066,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 850, "literal": "^1.0.2", @@ -11079,7 +11079,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 851, "literal": "^1.0.2", @@ -11092,7 +11092,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 852, "literal": "^1.2.0", @@ -11105,7 +11105,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 853, "literal": "^1.22.1", @@ -11118,7 +11118,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 854, "literal": "^1.0.0", @@ -11131,7 +11131,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 855, "literal": "^1.0.7", @@ -11144,7 +11144,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 856, "literal": "^1.2.1", @@ -11157,7 +11157,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 857, "literal": "^1.23.2", @@ -11170,7 +11170,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 858, "literal": "^1.3.0", @@ -11183,7 +11183,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 859, "literal": "^1.0.0", @@ -11196,7 +11196,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 860, "literal": "^1.0.2", @@ -11209,7 +11209,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 861, "literal": "~8.5.10", @@ -11222,7 +11222,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 862, "literal": "~20.12.8", @@ -11235,7 +11235,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 863, "literal": "*", @@ -11248,7 +11248,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 864, "literal": "^4.21.10", @@ -11261,7 +11261,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 865, "literal": "^1.0.30001538", @@ -11274,7 +11274,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 866, "literal": "^4.3.6", @@ -11287,7 +11287,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 867, "literal": "^0.1.2", @@ -11300,7 +11300,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 868, "literal": "^1.0.0", @@ -11313,7 +11313,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 869, "literal": "^4.2.0", @@ -11339,7 +11339,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 871, "literal": "^1.0.30001587", @@ -11352,7 +11352,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 872, "literal": "^1.4.668", @@ -11365,7 +11365,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 873, "literal": "^2.0.14", @@ -11378,7 +11378,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 874, "literal": "^1.0.13", @@ -11391,7 +11391,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 875, "literal": "^3.1.2", @@ -11404,7 +11404,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 876, "literal": "^1.0.1", @@ -11430,7 +11430,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 878, "literal": "*", @@ -11443,7 +11443,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 879, "literal": "*", @@ -11456,7 +11456,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 880, "literal": "*", @@ -11469,7 +11469,7 @@ exports[`next build works: bun 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 881, "literal": "^3.0.2", @@ -22609,7 +22609,7 @@ exports[`next build works: node 1`] = ` "dependencies": [ { "behavior": { - "normal": true, + "prod": true, }, "id": 0, "literal": "20.7.0", @@ -22622,7 +22622,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 1, "literal": "18.2.22", @@ -22635,7 +22635,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 2, "literal": "18.2.7", @@ -22648,7 +22648,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 3, "literal": "10.4.16", @@ -22661,7 +22661,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 4, "literal": "^1.0.3", @@ -22674,7 +22674,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 5, "literal": "8.50.0", @@ -22687,7 +22687,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 6, "literal": "14.1.3", @@ -22700,7 +22700,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 7, "literal": "14.1.3", @@ -22713,7 +22713,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 8, "literal": "8.4.30", @@ -22726,7 +22726,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 9, "literal": "22.12.0", @@ -22739,7 +22739,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 10, "literal": "18.2.0", @@ -22752,7 +22752,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 11, "literal": "18.2.0", @@ -22765,7 +22765,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 12, "literal": "3.3.3", @@ -22778,7 +22778,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 13, "literal": "5.2.2", @@ -22791,7 +22791,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 14, "literal": "^5.0.2", @@ -22804,7 +22804,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 15, "literal": "^1.1.3", @@ -22817,7 +22817,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 16, "literal": "^1.18.2", @@ -22830,7 +22830,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 17, "literal": "^4.0.3", @@ -22843,7 +22843,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 18, "literal": "^8.4.23", @@ -22856,7 +22856,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 19, "literal": "^1.22.2", @@ -22869,7 +22869,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 20, "literal": "^3.32.0", @@ -22882,7 +22882,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 21, "literal": "^3.5.3", @@ -22895,7 +22895,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 22, "literal": "^3.2.12", @@ -22908,7 +22908,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 23, "literal": "^2.1.0", @@ -22921,7 +22921,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 24, "literal": "^1.2.2", @@ -22934,7 +22934,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 25, "literal": "^4.0.5", @@ -22947,7 +22947,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 26, "literal": "^1.0.0", @@ -22960,7 +22960,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 27, "literal": "^4.0.1", @@ -22973,7 +22973,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 28, "literal": "^6.0.2", @@ -22986,7 +22986,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 29, "literal": "^3.0.0", @@ -22999,7 +22999,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 30, "literal": "^3.0.0", @@ -23012,7 +23012,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 31, "literal": "^15.1.0", @@ -23025,7 +23025,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 32, "literal": "^6.0.1", @@ -23038,7 +23038,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 33, "literal": "^5.2.0", @@ -23051,7 +23051,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 34, "literal": "^4.0.1", @@ -23064,7 +23064,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 35, "literal": "^6.0.11", @@ -23077,7 +23077,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 36, "literal": "^3.0.0", @@ -23090,7 +23090,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 37, "literal": "^1.0.2", @@ -23103,7 +23103,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 38, "literal": "^2.3.4", @@ -23116,7 +23116,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 39, "literal": "^3.0.0", @@ -23157,7 +23157,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 42, "literal": "^3.3.6", @@ -23170,7 +23170,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 43, "literal": "^1.0.0", @@ -23183,7 +23183,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 44, "literal": "^1.0.2", @@ -23196,7 +23196,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 45, "literal": "^6.0.11", @@ -23222,7 +23222,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 47, "literal": "^4.0.0", @@ -23235,7 +23235,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 48, "literal": "^1.0.0", @@ -23248,7 +23248,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 49, "literal": "^1.1.7", @@ -23274,7 +23274,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 51, "literal": "^2.13.0", @@ -23287,7 +23287,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 52, "literal": "^1.0.7", @@ -23300,7 +23300,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 53, "literal": "^1.0.0", @@ -23313,7 +23313,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 54, "literal": "^2.0.0", @@ -23326,7 +23326,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 55, "literal": "^1.1.2", @@ -23339,7 +23339,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 56, "literal": "^2.3.0", @@ -23352,7 +23352,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 57, "literal": "^4.0.3", @@ -23365,7 +23365,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 58, "literal": "^2.1.1", @@ -23378,7 +23378,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 59, "literal": "^2.0.1", @@ -23404,7 +23404,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 61, "literal": "^3.0.3", @@ -23417,7 +23417,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 62, "literal": "^2.3.1", @@ -23430,7 +23430,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 63, "literal": "^7.1.1", @@ -23443,7 +23443,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 64, "literal": "^5.0.1", @@ -23456,7 +23456,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 65, "literal": "^7.0.0", @@ -23469,7 +23469,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 66, "literal": "^2.0.2", @@ -23482,7 +23482,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 67, "literal": "^1.2.3", @@ -23495,7 +23495,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 68, "literal": "^5.1.2", @@ -23508,7 +23508,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 69, "literal": "^1.3.0", @@ -23521,7 +23521,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 70, "literal": "^4.0.4", @@ -23534,7 +23534,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 71, "literal": "^4.0.1", @@ -23547,7 +23547,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 72, "literal": "2.1.5", @@ -23560,7 +23560,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 73, "literal": "^1.6.0", @@ -23573,7 +23573,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 74, "literal": "^1.0.4", @@ -23586,7 +23586,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 75, "literal": "2.0.5", @@ -23599,7 +23599,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 76, "literal": "^1.1.9", @@ -23612,7 +23612,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 77, "literal": "^1.2.2", @@ -23625,7 +23625,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 78, "literal": "~3.1.2", @@ -23638,7 +23638,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 79, "literal": "~3.0.2", @@ -23651,7 +23651,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 80, "literal": "~5.1.2", @@ -23664,7 +23664,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 81, "literal": "~2.1.0", @@ -23677,7 +23677,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 82, "literal": "~4.0.1", @@ -23690,7 +23690,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 83, "literal": "~3.0.0", @@ -23703,7 +23703,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 84, "literal": "~3.6.0", @@ -23729,7 +23729,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 86, "literal": "^2.2.1", @@ -23742,7 +23742,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 87, "literal": "^2.0.0", @@ -23755,7 +23755,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 88, "literal": "^3.0.0", @@ -23768,7 +23768,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 89, "literal": "^2.0.4", @@ -23781,7 +23781,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 90, "literal": "^0.3.2", @@ -23794,7 +23794,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 91, "literal": "^4.0.0", @@ -23807,7 +23807,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 92, "literal": "^10.3.10", @@ -23820,7 +23820,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 93, "literal": "^1.1.6", @@ -23833,7 +23833,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 94, "literal": "^2.7.0", @@ -23846,7 +23846,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 95, "literal": "^4.0.1", @@ -23859,7 +23859,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 96, "literal": "^0.1.9", @@ -23872,7 +23872,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 97, "literal": "^1.0.0", @@ -23885,7 +23885,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 98, "literal": "^4.0.1", @@ -23898,7 +23898,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 99, "literal": "^1.0.0", @@ -23911,7 +23911,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 100, "literal": ">= 3.1.0 < 4", @@ -23924,7 +23924,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 101, "literal": "^1.0.0", @@ -23937,7 +23937,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 102, "literal": "^3.1.0", @@ -23950,7 +23950,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 103, "literal": "^2.3.5", @@ -23963,7 +23963,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 104, "literal": "^9.0.1", @@ -23976,7 +23976,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 105, "literal": "^5.0.0 || ^6.0.2 || ^7.0.0", @@ -23989,7 +23989,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 106, "literal": "^1.10.1", @@ -24002,7 +24002,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 107, "literal": "^10.2.0", @@ -24015,7 +24015,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 108, "literal": "^5.0.0 || ^6.0.2 || ^7.0.0", @@ -24028,7 +24028,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 109, "literal": "^2.0.1", @@ -24041,7 +24041,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 110, "literal": "^1.0.0", @@ -24054,7 +24054,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 111, "literal": "^8.0.2", @@ -24080,7 +24080,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 113, "literal": "^5.1.2", @@ -24093,7 +24093,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 114, "is_alias": true, @@ -24107,7 +24107,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 115, "literal": "^7.0.1", @@ -24120,7 +24120,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 116, "is_alias": true, @@ -24134,7 +24134,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 117, "literal": "^8.1.0", @@ -24147,7 +24147,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 118, "is_alias": true, @@ -24161,7 +24161,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 119, "literal": "^4.0.0", @@ -24174,7 +24174,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 120, "literal": "^4.1.0", @@ -24187,7 +24187,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 121, "literal": "^6.0.0", @@ -24200,7 +24200,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 122, "literal": "^5.0.1", @@ -24213,7 +24213,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 123, "literal": "^8.0.0", @@ -24226,7 +24226,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 124, "literal": "^3.0.0", @@ -24239,7 +24239,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 125, "literal": "^6.0.1", @@ -24252,7 +24252,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 126, "literal": "^2.0.1", @@ -24265,7 +24265,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 127, "literal": "~1.1.4", @@ -24278,7 +24278,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 128, "literal": "^6.1.0", @@ -24291,7 +24291,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 129, "literal": "^5.0.1", @@ -24304,7 +24304,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 130, "literal": "^7.0.1", @@ -24317,7 +24317,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 131, "literal": "^6.0.1", @@ -24330,7 +24330,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 132, "literal": "^0.2.0", @@ -24343,7 +24343,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 133, "literal": "^9.2.2", @@ -24356,7 +24356,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 134, "literal": "^7.0.1", @@ -24369,7 +24369,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 135, "literal": "^7.0.0", @@ -24382,7 +24382,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 136, "literal": "^4.0.1", @@ -24395,7 +24395,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 137, "literal": "^3.1.0", @@ -24408,7 +24408,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 138, "literal": "^2.0.0", @@ -24421,7 +24421,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 139, "literal": "^2.0.1", @@ -24434,7 +24434,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 140, "literal": "^2.0.0", @@ -24447,7 +24447,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 141, "literal": "^3.0.0", @@ -24460,7 +24460,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 142, "literal": "^1.2.1", @@ -24473,7 +24473,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 143, "literal": "^1.4.10", @@ -24486,7 +24486,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 144, "literal": "^0.3.24", @@ -24499,7 +24499,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 145, "literal": "^3.1.0", @@ -24512,7 +24512,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 146, "literal": "^1.4.14", @@ -24525,7 +24525,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 147, "literal": "^0.23.0", @@ -24538,7 +24538,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 148, "literal": "^1.1.0", @@ -24564,7 +24564,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 150, "literal": "^1.1.0", @@ -24577,7 +24577,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 151, "literal": "^3.0.0 || ^4.0.0", @@ -24590,7 +24590,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 152, "literal": "^1.1.0", @@ -24603,7 +24603,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 153, "literal": "9.0.0", @@ -24616,7 +24616,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 154, "literal": "22.12.0", @@ -24629,7 +24629,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 155, "literal": "2.2.3", @@ -24642,7 +24642,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 156, "literal": "0.0.1299070", @@ -24655,7 +24655,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 157, "literal": "4.3.4", @@ -24668,7 +24668,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 158, "literal": "2.0.1", @@ -24681,7 +24681,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 159, "literal": "2.0.3", @@ -24694,7 +24694,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 160, "literal": "6.4.0", @@ -24707,7 +24707,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 161, "literal": "3.0.5", @@ -24720,7 +24720,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 162, "literal": "1.4.3", @@ -24733,7 +24733,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 163, "literal": "17.7.2", @@ -24746,7 +24746,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 164, "literal": "7.6.0", @@ -24759,7 +24759,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 165, "literal": "^6.0.0", @@ -24772,7 +24772,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 166, "literal": "^4.0.0", @@ -24785,7 +24785,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 167, "literal": "^8.0.1", @@ -24798,7 +24798,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 168, "literal": "^3.1.1", @@ -24811,7 +24811,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 169, "literal": "^2.0.5", @@ -24824,7 +24824,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 170, "literal": "^2.1.1", @@ -24837,7 +24837,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 171, "literal": "^4.2.3", @@ -24850,7 +24850,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 172, "literal": "^5.0.5", @@ -24863,7 +24863,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 173, "literal": "^21.1.1", @@ -24876,7 +24876,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 174, "literal": "^4.2.0", @@ -24889,7 +24889,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 175, "literal": "^6.0.1", @@ -24902,7 +24902,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 176, "literal": "^7.0.0", @@ -24915,7 +24915,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 177, "literal": "^5.2.1", @@ -24928,7 +24928,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 178, "literal": "^2.3.8", @@ -24941,7 +24941,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 179, "literal": "^1.3.1", @@ -24954,7 +24954,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 180, "literal": "^1.1.13", @@ -24967,7 +24967,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 181, "literal": "^3.0.0", @@ -24980,7 +24980,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 182, "literal": "^3.1.5", @@ -25019,7 +25019,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 185, "literal": "^2.1.0", @@ -25032,7 +25032,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 186, "literal": "^2.0.0", @@ -25045,7 +25045,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 187, "literal": "^2.0.0", @@ -25058,7 +25058,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 188, "literal": "^2.0.0", @@ -25071,7 +25071,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 189, "literal": "^2.18.0", @@ -25084,7 +25084,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 190, "literal": "^1.3.2", @@ -25097,7 +25097,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 191, "literal": "^1.0.1", @@ -25110,7 +25110,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 192, "literal": "^1.1.0", @@ -25136,7 +25136,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 194, "literal": "^1.6.4", @@ -25149,7 +25149,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 195, "literal": "^1.6.4", @@ -25162,7 +25162,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 196, "literal": "^1.2.0", @@ -25175,7 +25175,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 197, "literal": "^2.15.0", @@ -25188,7 +25188,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 198, "literal": "^1.1.0", @@ -25201,7 +25201,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 199, "literal": "^1.3.1", @@ -25214,7 +25214,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 200, "literal": "1", @@ -25227,7 +25227,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 201, "literal": "^1.4.0", @@ -25240,7 +25240,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 202, "literal": "^7.0.2", @@ -25253,7 +25253,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 203, "literal": "^4.3.4", @@ -25266,7 +25266,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 204, "literal": "^7.0.1", @@ -25279,7 +25279,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 205, "literal": "^7.0.3", @@ -25292,7 +25292,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 206, "literal": "^7.14.1", @@ -25305,7 +25305,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 207, "literal": "^7.0.1", @@ -25318,7 +25318,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 208, "literal": "^1.1.0", @@ -25331,7 +25331,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 209, "literal": "^8.0.2", @@ -25344,7 +25344,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 210, "literal": "^7.1.1", @@ -25357,7 +25357,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 211, "literal": "^4.3.4", @@ -25370,7 +25370,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 212, "literal": "^2.7.1", @@ -25383,7 +25383,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 213, "literal": "^9.0.5", @@ -25396,7 +25396,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 214, "literal": "^4.2.0", @@ -25409,7 +25409,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 215, "literal": "1.1.0", @@ -25422,7 +25422,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 216, "literal": "^1.1.3", @@ -25435,7 +25435,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 217, "literal": "2.1.2", @@ -25448,7 +25448,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 218, "literal": "^4.3.4", @@ -25461,7 +25461,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 219, "literal": "^0.23.0", @@ -25474,7 +25474,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 220, "literal": "^7.0.2", @@ -25487,7 +25487,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 221, "literal": "^4.3.4", @@ -25500,7 +25500,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 222, "literal": "^6.0.1", @@ -25513,7 +25513,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 223, "literal": "^7.0.0", @@ -25526,7 +25526,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 224, "literal": "^7.0.2", @@ -25539,7 +25539,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 225, "literal": "^7.0.0", @@ -25552,7 +25552,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 226, "literal": "^8.0.2", @@ -25565,7 +25565,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 227, "literal": "^5.0.0", @@ -25578,7 +25578,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 228, "literal": "^2.0.2", @@ -25591,7 +25591,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 229, "literal": "^0.13.4", @@ -25604,7 +25604,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 230, "literal": "^2.1.0", @@ -25617,7 +25617,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 231, "literal": "^4.0.1", @@ -25630,7 +25630,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 232, "literal": "^5.2.0", @@ -25643,7 +25643,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 233, "literal": "^2.0.2", @@ -25656,7 +25656,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 234, "literal": "^4.0.1", @@ -25682,7 +25682,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 236, "literal": "^2.0.1", @@ -25695,7 +25695,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 237, "literal": "^7.0.2", @@ -25708,7 +25708,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 238, "literal": "4", @@ -25721,7 +25721,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 239, "literal": "^7.1.0", @@ -25734,7 +25734,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 240, "literal": "^4.3.4", @@ -25747,7 +25747,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 241, "literal": "^5.0.2", @@ -25760,7 +25760,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 242, "literal": "^6.0.2", @@ -25773,7 +25773,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 243, "literal": "^4.3.4", @@ -25786,7 +25786,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 244, "literal": "^11.2.0", @@ -25799,7 +25799,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 245, "literal": "^4.2.0", @@ -25812,7 +25812,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 246, "literal": "^6.0.1", @@ -25825,7 +25825,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 247, "literal": "^2.0.0", @@ -25838,7 +25838,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 248, "literal": "^2.0.0", @@ -25864,7 +25864,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 250, "literal": "^4.1.1", @@ -25877,7 +25877,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 251, "literal": "^5.1.0", @@ -25890,7 +25890,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 252, "literal": "^2.10.0", @@ -25916,7 +25916,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 254, "literal": "*", @@ -25929,7 +25929,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 255, "literal": "~5.26.4", @@ -25942,7 +25942,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 256, "literal": "~1.1.0", @@ -25955,7 +25955,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 257, "literal": "~0.2.3", @@ -25968,7 +25968,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 258, "literal": "~1.2.0", @@ -25981,7 +25981,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 259, "literal": "^3.0.0", @@ -25994,7 +25994,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 260, "literal": "2.1.2", @@ -26007,7 +26007,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 261, "literal": "2.2.3", @@ -26020,7 +26020,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 262, "literal": "0.5.24", @@ -26033,7 +26033,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 263, "literal": "4.3.5", @@ -26046,7 +26046,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 264, "literal": "0.0.1299070", @@ -26059,7 +26059,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 265, "literal": "8.17.1", @@ -26100,7 +26100,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 268, "literal": "3.0.1", @@ -26113,7 +26113,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 269, "literal": "10.0.0", @@ -26126,7 +26126,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 270, "literal": "3.23.8", @@ -26152,7 +26152,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 272, "literal": "^2.2.1", @@ -26165,7 +26165,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 273, "literal": "^3.3.0", @@ -26178,7 +26178,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 274, "literal": "^4.1.0", @@ -26191,7 +26191,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 275, "literal": "^5.2.0", @@ -26218,7 +26218,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 277, "literal": "^7.0.0", @@ -26231,7 +26231,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 278, "literal": "^1.3.1", @@ -26244,7 +26244,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 279, "literal": "^2.3.0", @@ -26257,7 +26257,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 280, "literal": "^1.1.6", @@ -26270,7 +26270,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 281, "literal": "^0.2.1", @@ -26283,7 +26283,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 282, "literal": "^7.24.7", @@ -26296,7 +26296,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 283, "literal": "^1.0.0", @@ -26309,7 +26309,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 284, "literal": "^7.24.7", @@ -26322,7 +26322,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 285, "literal": "^2.4.2", @@ -26335,7 +26335,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 286, "literal": "^4.0.0", @@ -26348,7 +26348,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 287, "literal": "^1.0.0", @@ -26361,7 +26361,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 288, "literal": "^3.2.1", @@ -26374,7 +26374,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 289, "literal": "^1.0.5", @@ -26387,7 +26387,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 290, "literal": "^5.3.0", @@ -26400,7 +26400,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 291, "literal": "^3.0.0", @@ -26413,7 +26413,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 292, "literal": "^1.9.0", @@ -26426,7 +26426,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 293, "literal": "1.1.3", @@ -26439,7 +26439,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 294, "literal": "^2.0.1", @@ -26452,7 +26452,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 295, "literal": "^1.0.0", @@ -26465,7 +26465,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 296, "literal": "^4.0.0", @@ -26478,7 +26478,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 297, "literal": "^3.0.0", @@ -26491,7 +26491,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 298, "literal": "1.6.0", @@ -26504,7 +26504,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 299, "literal": "8.4.31", @@ -26517,7 +26517,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 300, "literal": "14.1.3", @@ -26530,7 +26530,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 301, "literal": "5.1.1", @@ -26543,7 +26543,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 302, "literal": "^4.2.11", @@ -26556,7 +26556,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 303, "literal": "0.5.2", @@ -26569,7 +26569,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 304, "literal": "^1.0.30001579", @@ -26753,7 +26753,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 318, "literal": "^2.4.0", @@ -26766,7 +26766,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 319, "literal": "0.0.1", @@ -26792,7 +26792,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 321, "literal": "^3.3.6", @@ -26805,7 +26805,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 322, "literal": "^1.0.0", @@ -26818,7 +26818,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 323, "literal": "^1.0.2", @@ -26831,7 +26831,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 324, "literal": "^1.1.0", @@ -26844,7 +26844,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 325, "literal": "^7.33.2", @@ -26857,7 +26857,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 326, "literal": "^2.28.1", @@ -26870,7 +26870,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 327, "literal": "^6.7.1", @@ -26883,7 +26883,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 328, "literal": "^1.3.3", @@ -26896,7 +26896,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 329, "literal": "14.1.3", @@ -26909,7 +26909,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 330, "literal": "^5.4.2 || ^6.0.0", @@ -26922,7 +26922,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 331, "literal": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705", @@ -26935,7 +26935,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 332, "literal": "^0.3.6", @@ -26948,7 +26948,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 333, "literal": "^3.5.2", @@ -26988,7 +26988,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 336, "literal": "^6.12.4", @@ -27001,7 +27001,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 337, "literal": "^0.4.1", @@ -27014,7 +27014,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 338, "literal": "^4.0.0", @@ -27027,7 +27027,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 339, "literal": "^4.3.2", @@ -27040,7 +27040,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 340, "literal": "^9.6.1", @@ -27053,7 +27053,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 341, "literal": "^5.2.0", @@ -27066,7 +27066,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 342, "literal": "^1.4.2", @@ -27079,7 +27079,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 343, "literal": "^2.0.2", @@ -27092,7 +27092,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 344, "literal": "^5.0.0", @@ -27105,7 +27105,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 345, "literal": "^13.19.0", @@ -27118,7 +27118,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 346, "literal": "^4.0.0", @@ -27131,7 +27131,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 347, "literal": "^4.1.0", @@ -27144,7 +27144,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 348, "literal": "^3.0.0", @@ -27157,7 +27157,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 349, "literal": "^1.4.0", @@ -27170,7 +27170,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 350, "literal": "^3.1.2", @@ -27183,7 +27183,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 351, "literal": "8.50.0", @@ -27196,7 +27196,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 352, "literal": "^0.9.3", @@ -27209,7 +27209,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 353, "literal": "^6.0.1", @@ -27222,7 +27222,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 354, "literal": "^0.2.0", @@ -27235,7 +27235,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 355, "literal": "^7.0.2", @@ -27248,7 +27248,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 356, "literal": "^6.0.2", @@ -27261,7 +27261,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 357, "literal": "^0.1.4", @@ -27274,7 +27274,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 358, "literal": "^7.2.2", @@ -27287,7 +27287,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 359, "literal": "^4.6.2", @@ -27300,7 +27300,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 360, "literal": "^3.0.3", @@ -27313,7 +27313,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 361, "literal": "^3.1.3", @@ -27326,7 +27326,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 362, "literal": "^1.4.0", @@ -27339,7 +27339,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 363, "literal": "^2.1.2", @@ -27352,7 +27352,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 364, "literal": "^1.2.8", @@ -27365,7 +27365,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 365, "literal": "^6.0.1", @@ -27378,7 +27378,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 366, "literal": "^3.4.3", @@ -27391,7 +27391,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 367, "literal": "^4.0.0", @@ -27404,7 +27404,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 368, "literal": "^4.6.1", @@ -27417,7 +27417,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 369, "literal": "^0.11.11", @@ -27430,7 +27430,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 370, "literal": "^4.2.0", @@ -27443,7 +27443,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 371, "literal": "^1.0.1", @@ -27456,7 +27456,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 372, "literal": "^1.0.1", @@ -27469,7 +27469,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 373, "literal": "^3.3.0", @@ -27495,7 +27495,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 375, "literal": "^2.0.2", @@ -27508,7 +27508,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 376, "literal": "^4.3.1", @@ -27521,7 +27521,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 377, "literal": "^3.0.5", @@ -27534,7 +27534,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 378, "literal": "^1.1.7", @@ -27547,7 +27547,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 379, "literal": "^1.0.0", @@ -27560,7 +27560,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 380, "literal": "0.0.1", @@ -27573,7 +27573,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 381, "literal": "^3.0.4", @@ -27586,7 +27586,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 382, "literal": "^3.2.9", @@ -27599,7 +27599,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 383, "literal": "^4.5.3", @@ -27612,7 +27612,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 384, "literal": "^3.0.2", @@ -27625,7 +27625,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 385, "literal": "^7.1.3", @@ -27638,7 +27638,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 386, "literal": "^1.0.0", @@ -27651,7 +27651,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 387, "literal": "^1.0.4", @@ -27664,7 +27664,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 388, "literal": "2", @@ -27677,7 +27677,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 389, "literal": "^3.1.1", @@ -27690,7 +27690,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 390, "literal": "^1.3.0", @@ -27703,7 +27703,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 391, "literal": "^1.0.0", @@ -27716,7 +27716,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 392, "literal": "^1.3.0", @@ -27729,7 +27729,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 393, "literal": "1", @@ -27742,7 +27742,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 394, "literal": "3.0.1", @@ -27755,7 +27755,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 395, "literal": "^6.12.4", @@ -27768,7 +27768,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 396, "literal": "^4.3.2", @@ -27781,7 +27781,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 397, "literal": "^9.6.0", @@ -27794,7 +27794,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 398, "literal": "^13.19.0", @@ -27807,7 +27807,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 399, "literal": "^5.2.0", @@ -27820,7 +27820,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 400, "literal": "^3.2.1", @@ -27833,7 +27833,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 401, "literal": "^4.1.0", @@ -27846,7 +27846,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 402, "literal": "^3.1.2", @@ -27859,7 +27859,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 403, "literal": "^3.1.1", @@ -27872,7 +27872,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 404, "literal": "^0.20.2", @@ -27885,7 +27885,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 405, "literal": "^8.9.0", @@ -27898,7 +27898,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 406, "literal": "^5.3.2", @@ -27911,7 +27911,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 407, "literal": "^3.4.1", @@ -27937,7 +27937,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 409, "literal": "^3.1.1", @@ -27950,7 +27950,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 410, "literal": "^2.0.0", @@ -27963,7 +27963,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 411, "literal": "^0.4.1", @@ -27976,7 +27976,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 412, "literal": "^4.2.2", @@ -27989,7 +27989,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 413, "literal": "^2.1.0", @@ -28002,7 +28002,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 414, "literal": "^4.3.0", @@ -28015,7 +28015,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 415, "literal": "^5.2.0", @@ -28028,7 +28028,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 416, "literal": "^5.2.0", @@ -28041,7 +28041,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 417, "literal": "^1.2.1", @@ -28054,7 +28054,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 418, "literal": "^0.1.3", @@ -28067,7 +28067,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 419, "literal": "^1.2.5", @@ -28080,7 +28080,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 420, "literal": "^0.4.0", @@ -28093,7 +28093,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 421, "literal": "^0.4.1", @@ -28106,7 +28106,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 422, "literal": "^2.0.6", @@ -28119,7 +28119,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 423, "literal": "^1.2.1", @@ -28132,7 +28132,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 424, "literal": "~0.4.0", @@ -28145,7 +28145,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 425, "literal": "^1.2.1", @@ -28158,7 +28158,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 426, "literal": "^2.0.2", @@ -28171,7 +28171,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 427, "literal": "^6.0.0", @@ -28184,7 +28184,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 428, "literal": "^4.0.0", @@ -28197,7 +28197,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 429, "literal": "^5.0.0", @@ -28210,7 +28210,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 430, "literal": "^3.0.2", @@ -28223,7 +28223,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 431, "literal": "^0.1.0", @@ -28236,7 +28236,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 432, "literal": "^5.1.0", @@ -28249,7 +28249,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 433, "literal": "^4.1.0", @@ -28262,7 +28262,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 434, "literal": "^7.1.0", @@ -28275,7 +28275,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 435, "literal": "^4.0.0", @@ -28288,7 +28288,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 436, "literal": "^4.3.4", @@ -28301,7 +28301,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 437, "literal": "^5.12.0", @@ -28314,7 +28314,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 438, "literal": "^2.7.4", @@ -28327,7 +28327,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 439, "literal": "^3.3.1", @@ -28340,7 +28340,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 440, "literal": "^4.5.0", @@ -28353,7 +28353,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 441, "literal": "^2.11.0", @@ -28366,7 +28366,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 442, "literal": "^4.0.3", @@ -28405,7 +28405,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 445, "literal": "^3.1.7", @@ -28418,7 +28418,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 446, "literal": "^1.2.3", @@ -28431,7 +28431,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 447, "literal": "^1.3.2", @@ -28444,7 +28444,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 448, "literal": "^1.3.2", @@ -28457,7 +28457,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 449, "literal": "^3.2.7", @@ -28470,7 +28470,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 450, "literal": "^2.1.0", @@ -28483,7 +28483,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 451, "literal": "^0.3.9", @@ -28496,7 +28496,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 452, "literal": "^2.8.0", @@ -28509,7 +28509,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 453, "literal": "^2.0.0", @@ -28522,7 +28522,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 454, "literal": "^2.13.1", @@ -28535,7 +28535,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 455, "literal": "^4.0.3", @@ -28548,7 +28548,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 456, "literal": "^3.1.2", @@ -28561,7 +28561,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 457, "literal": "^2.0.7", @@ -28574,7 +28574,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 458, "literal": "^1.0.1", @@ -28587,7 +28587,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 459, "literal": "^1.1.7", @@ -28600,7 +28600,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 460, "literal": "^6.3.1", @@ -28613,7 +28613,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 461, "literal": "^3.15.0", @@ -28639,7 +28639,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 463, "literal": "^0.0.29", @@ -28652,7 +28652,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 464, "literal": "^1.0.2", @@ -28665,7 +28665,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 465, "literal": "^1.2.6", @@ -28678,7 +28678,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 466, "literal": "^3.0.0", @@ -28691,7 +28691,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 467, "literal": "^1.2.0", @@ -28704,7 +28704,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 468, "literal": "^1.0.7", @@ -28717,7 +28717,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 469, "literal": "^1.2.1", @@ -28730,7 +28730,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 470, "literal": "^1.0.0", @@ -28743,7 +28743,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 471, "literal": "^1.3.0", @@ -28756,7 +28756,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 472, "literal": "^1.0.1", @@ -28769,7 +28769,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 473, "literal": "^1.0.0", @@ -28782,7 +28782,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 474, "literal": "^1.1.1", @@ -28795,7 +28795,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 475, "literal": "^1.0.0", @@ -28808,7 +28808,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 476, "literal": "^1.2.4", @@ -28821,7 +28821,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 477, "literal": "^1.3.0", @@ -28834,7 +28834,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 478, "literal": "^1.1.2", @@ -28847,7 +28847,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 479, "literal": "^1.0.1", @@ -28860,7 +28860,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 480, "literal": "^1.0.3", @@ -28873,7 +28873,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 481, "literal": "^2.0.0", @@ -28886,7 +28886,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 482, "literal": "^1.0.0", @@ -28899,7 +28899,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 483, "literal": "^1.3.0", @@ -28912,7 +28912,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 484, "literal": "^1.0.1", @@ -28925,7 +28925,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 485, "literal": "^1.1.3", @@ -28938,7 +28938,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 486, "literal": "^1.0.0", @@ -28951,7 +28951,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 487, "literal": "^1.3.0", @@ -28964,7 +28964,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 488, "literal": "^1.1.2", @@ -28977,7 +28977,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 489, "literal": "^1.2.4", @@ -28990,7 +28990,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 490, "literal": "^1.2.1", @@ -29003,7 +29003,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 491, "literal": "^1.1.4", @@ -29016,7 +29016,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 492, "literal": "^1.3.0", @@ -29029,7 +29029,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 493, "literal": "^1.1.2", @@ -29042,7 +29042,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 494, "literal": "^1.2.4", @@ -29055,7 +29055,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 495, "literal": "^1.0.1", @@ -29068,7 +29068,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 496, "literal": "^1.0.2", @@ -29081,7 +29081,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 497, "literal": "^1.0.7", @@ -29094,7 +29094,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 498, "literal": "^1.2.1", @@ -29107,7 +29107,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 499, "literal": "^1.23.2", @@ -29120,7 +29120,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 500, "literal": "^1.0.1", @@ -29133,7 +29133,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 501, "literal": "^1.0.3", @@ -29146,7 +29146,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 502, "literal": "^1.0.7", @@ -29159,7 +29159,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 503, "literal": "^1.0.7", @@ -29172,7 +29172,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 504, "literal": "^1.0.1", @@ -29185,7 +29185,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 505, "literal": "^1.0.1", @@ -29198,7 +29198,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 506, "literal": "^1.0.0", @@ -29211,7 +29211,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 507, "literal": "^1.0.0", @@ -29224,7 +29224,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 508, "literal": "^1.3.0", @@ -29237,7 +29237,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 509, "literal": "^1.0.0", @@ -29250,7 +29250,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 510, "literal": "^2.0.3", @@ -29263,7 +29263,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 511, "literal": "^1.2.1", @@ -29276,7 +29276,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 512, "literal": "^1.1.6", @@ -29289,7 +29289,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 513, "literal": "^1.2.4", @@ -29302,7 +29302,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 514, "literal": "^1.0.2", @@ -29315,7 +29315,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 515, "literal": "^1.0.3", @@ -29328,7 +29328,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 516, "literal": "^1.0.1", @@ -29341,7 +29341,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 517, "literal": "^1.0.2", @@ -29354,7 +29354,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 518, "literal": "^1.0.3", @@ -29367,7 +29367,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 519, "literal": "^1.0.3", @@ -29380,7 +29380,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 520, "literal": "^2.0.2", @@ -29393,7 +29393,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 521, "literal": "^1.0.7", @@ -29406,7 +29406,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 522, "literal": "^3.0.4", @@ -29419,7 +29419,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 523, "literal": "^1.2.7", @@ -29432,7 +29432,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 524, "literal": "^1.0.1", @@ -29445,7 +29445,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 525, "literal": "^2.0.3", @@ -29458,7 +29458,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 526, "literal": "^1.1.4", @@ -29471,7 +29471,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 527, "literal": "^1.0.3", @@ -29484,7 +29484,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 528, "literal": "^1.0.7", @@ -29497,7 +29497,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 529, "literal": "^1.1.13", @@ -29510,7 +29510,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 530, "literal": "^1.0.2", @@ -29523,7 +29523,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 531, "literal": "^1.13.1", @@ -29536,7 +29536,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 532, "literal": "^1.1.1", @@ -29549,7 +29549,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 533, "literal": "^4.1.5", @@ -29562,7 +29562,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 534, "literal": "^1.5.2", @@ -29575,7 +29575,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 535, "literal": "^1.1.2", @@ -29588,7 +29588,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 536, "literal": "^1.0.3", @@ -29601,7 +29601,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 537, "literal": "^1.2.9", @@ -29614,7 +29614,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 538, "literal": "^1.0.8", @@ -29627,7 +29627,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 539, "literal": "^1.0.8", @@ -29640,7 +29640,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 540, "literal": "^1.0.2", @@ -29653,7 +29653,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 541, "literal": "^1.0.1", @@ -29666,7 +29666,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 542, "literal": "^1.0.2", @@ -29679,7 +29679,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 543, "literal": "^1.0.6", @@ -29692,7 +29692,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 544, "literal": "^1.0.2", @@ -29705,7 +29705,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 545, "literal": "^1.1.15", @@ -29718,7 +29718,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 546, "literal": "^1.0.7", @@ -29731,7 +29731,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 547, "literal": "^1.0.7", @@ -29744,7 +29744,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 548, "literal": "^0.3.3", @@ -29757,7 +29757,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 549, "literal": "^1.0.1", @@ -29770,7 +29770,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 550, "literal": "^1.0.2", @@ -29783,7 +29783,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 551, "literal": "^1.0.3", @@ -29796,7 +29796,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 552, "literal": "^1.1.3", @@ -29809,7 +29809,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 553, "literal": "^1.0.0", @@ -29822,7 +29822,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 554, "literal": "^1.0.2", @@ -29835,7 +29835,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 555, "literal": "^1.0.2", @@ -29848,7 +29848,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 556, "literal": "^1.0.3", @@ -29861,7 +29861,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 557, "literal": "^1.0.2", @@ -29874,7 +29874,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 558, "literal": "^1.0.1", @@ -29887,7 +29887,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 559, "literal": "^1.1.0", @@ -29900,7 +29900,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 560, "literal": "^1.0.4", @@ -29913,7 +29913,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 561, "literal": "^1.0.5", @@ -29926,7 +29926,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 562, "literal": "^1.0.3", @@ -29939,7 +29939,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 563, "literal": "^1.0.2", @@ -29952,7 +29952,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 564, "literal": "^1.0.0", @@ -29965,7 +29965,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 565, "literal": "^1.0.0", @@ -29978,7 +29978,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 566, "literal": "^1.0.2", @@ -29991,7 +29991,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 567, "literal": "^1.0.0", @@ -30004,7 +30004,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 568, "literal": "^1.0.1", @@ -30017,7 +30017,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 569, "literal": "^1.0.7", @@ -30030,7 +30030,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 570, "literal": "^0.3.3", @@ -30043,7 +30043,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 571, "literal": "^1.0.1", @@ -30056,7 +30056,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 572, "literal": "^1.0.3", @@ -30069,7 +30069,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 573, "literal": "^1.1.13", @@ -30082,7 +30082,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 574, "literal": "^1.0.0", @@ -30095,7 +30095,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 575, "literal": "^1.1.14", @@ -30108,7 +30108,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 576, "literal": "^1.0.7", @@ -30121,7 +30121,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 577, "literal": "^1.0.7", @@ -30134,7 +30134,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 578, "literal": "^0.3.3", @@ -30147,7 +30147,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 579, "literal": "^1.0.1", @@ -30160,7 +30160,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 580, "literal": "^1.0.3", @@ -30173,7 +30173,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 581, "literal": "^1.1.13", @@ -30186,7 +30186,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 582, "literal": "^1.0.7", @@ -30199,7 +30199,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 583, "literal": "^0.3.3", @@ -30212,7 +30212,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 584, "literal": "^1.0.1", @@ -30225,7 +30225,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 585, "literal": "^1.0.3", @@ -30238,7 +30238,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 586, "literal": "^1.1.13", @@ -30251,7 +30251,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 587, "literal": "^1.0.7", @@ -30264,7 +30264,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 588, "literal": "^1.3.0", @@ -30277,7 +30277,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 589, "literal": "^1.1.13", @@ -30290,7 +30290,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 590, "literal": "^1.0.7", @@ -30303,7 +30303,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 591, "literal": "^1.2.1", @@ -30316,7 +30316,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 592, "literal": "^1.0.0", @@ -30329,7 +30329,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 593, "literal": "^1.0.7", @@ -30342,7 +30342,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 594, "literal": "^1.2.1", @@ -30355,7 +30355,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 595, "literal": "^1.0.0", @@ -30368,7 +30368,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 596, "literal": "^1.0.7", @@ -30381,7 +30381,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 597, "literal": "^1.2.1", @@ -30394,7 +30394,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 598, "literal": "^1.23.0", @@ -30407,7 +30407,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 599, "literal": "^1.0.0", @@ -30420,7 +30420,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 600, "literal": "^1.0.6", @@ -30433,7 +30433,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 601, "literal": "^1.3.0", @@ -30446,7 +30446,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 602, "literal": "^1.1.4", @@ -30459,7 +30459,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 603, "literal": "^1.0.2", @@ -30472,7 +30472,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 604, "literal": "^1.0.0", @@ -30485,7 +30485,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 605, "literal": "^1.0.7", @@ -30498,7 +30498,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 606, "literal": "^1.2.4", @@ -30511,7 +30511,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 607, "literal": "^1.0.3", @@ -30524,7 +30524,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 608, "literal": "^2.0.5", @@ -30537,7 +30537,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 609, "literal": "^1.0.6", @@ -30550,7 +30550,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 610, "literal": "^1.2.1", @@ -30563,7 +30563,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 611, "literal": "^1.3.0", @@ -30576,7 +30576,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 612, "literal": "^2.0.1", @@ -30589,7 +30589,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 613, "literal": "^1.1.4", @@ -30602,7 +30602,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 614, "literal": "^1.3.0", @@ -30615,7 +30615,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 615, "literal": "^1.2.3", @@ -30628,7 +30628,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 616, "literal": "^1.0.2", @@ -30641,7 +30641,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 617, "literal": "^1.0.5", @@ -30654,7 +30654,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 618, "literal": "^1.2.1", @@ -30667,7 +30667,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 619, "literal": "^1.0.3", @@ -30680,7 +30680,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 620, "literal": "^1.1.1", @@ -30693,7 +30693,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 621, "literal": "^1.0.2", @@ -30706,7 +30706,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 622, "literal": "^1.0.7", @@ -30719,7 +30719,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 623, "literal": "^1.1.13", @@ -30732,7 +30732,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 624, "literal": "^1.0.2", @@ -30745,7 +30745,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 625, "literal": "^1.2.1", @@ -30758,7 +30758,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 626, "literal": "^1.3.0", @@ -30771,7 +30771,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 627, "literal": "^2.0.0", @@ -30784,7 +30784,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 628, "literal": "^1.0.4", @@ -30797,7 +30797,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 629, "literal": "^1.0.7", @@ -30810,7 +30810,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 630, "literal": "^1.3.0", @@ -30823,7 +30823,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 631, "literal": "^1.2.4", @@ -30836,7 +30836,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 632, "literal": "^1.13.1", @@ -30849,7 +30849,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 633, "literal": "^1.2.1", @@ -30862,7 +30862,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 634, "literal": "^1.0.1", @@ -30875,7 +30875,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 635, "literal": "^1.0.5", @@ -30888,7 +30888,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 636, "literal": "^1.3.0", @@ -30901,7 +30901,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 637, "literal": "^1.2.4", @@ -30914,7 +30914,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 638, "literal": "^1.0.2", @@ -30927,7 +30927,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 639, "literal": "^1.2.0", @@ -30940,7 +30940,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 640, "literal": "^1.22.1", @@ -30953,7 +30953,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 641, "literal": "^1.2.3", @@ -30966,7 +30966,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 642, "literal": "^1.1.4", @@ -30979,7 +30979,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 643, "literal": "^1.0.1", @@ -30992,7 +30992,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 644, "literal": "^1.0.2", @@ -31005,7 +31005,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 645, "literal": "^1.0.0", @@ -31018,7 +31018,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 646, "literal": "^1.2.4", @@ -31031,7 +31031,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 647, "literal": "^1.0.2", @@ -31044,7 +31044,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 648, "literal": "^2.0.1", @@ -31057,7 +31057,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 649, "literal": "^1.0.6", @@ -31070,7 +31070,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 650, "literal": "^1.3.0", @@ -31083,7 +31083,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 651, "literal": "^1.0.1", @@ -31096,7 +31096,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 652, "literal": "^1.0.7", @@ -31109,7 +31109,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 653, "literal": "^1.3.0", @@ -31122,7 +31122,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 654, "literal": "^1.0.1", @@ -31135,7 +31135,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 655, "literal": "^1.0.6", @@ -31148,7 +31148,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 656, "literal": "^1.3.0", @@ -31161,7 +31161,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 657, "literal": "^1.0.1", @@ -31174,7 +31174,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 658, "literal": "^1.0.1", @@ -31187,7 +31187,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 659, "literal": "^1.0.5", @@ -31200,7 +31200,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 660, "literal": "^1.2.1", @@ -31213,7 +31213,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 661, "literal": "^1.22.3", @@ -31226,7 +31226,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 662, "literal": "^1.2.1", @@ -31239,7 +31239,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 663, "literal": "^1.2.3", @@ -31252,7 +31252,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 664, "literal": "^3.0.4", @@ -31265,7 +31265,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 665, "literal": "^1.0.2", @@ -31278,7 +31278,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 666, "literal": "^1.0.5", @@ -31291,7 +31291,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 667, "literal": "^3.0.4", @@ -31304,7 +31304,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 668, "literal": "^1.0.7", @@ -31317,7 +31317,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 669, "literal": "^1.2.1", @@ -31330,7 +31330,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 670, "literal": "^1.23.2", @@ -31343,7 +31343,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 671, "literal": "^1.0.0", @@ -31356,7 +31356,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 672, "literal": "^3.2.7", @@ -31369,7 +31369,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 673, "literal": "^2.1.1", @@ -31382,7 +31382,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 674, "literal": "^3.2.7", @@ -31395,7 +31395,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 675, "literal": "^2.13.0", @@ -31408,7 +31408,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 676, "literal": "^1.22.4", @@ -31421,7 +31421,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 677, "literal": "^2.0.2", @@ -31434,7 +31434,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 678, "literal": "^1.0.2", @@ -31447,7 +31447,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 679, "literal": "^1.2.0", @@ -31460,7 +31460,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 680, "literal": "^1.22.1", @@ -31473,7 +31473,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 681, "literal": "^1.0.0", @@ -31486,7 +31486,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 682, "literal": "^2.0.0", @@ -31499,7 +31499,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 683, "literal": "^1.0.2", @@ -31512,7 +31512,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 684, "literal": "^1.2.0", @@ -31525,7 +31525,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 685, "literal": "^1.22.1", @@ -31538,7 +31538,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 686, "literal": "^1.0.0", @@ -31551,7 +31551,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 687, "literal": "^1.0.7", @@ -31564,7 +31564,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 688, "literal": "^1.2.1", @@ -31577,7 +31577,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 689, "literal": "^1.23.2", @@ -31590,7 +31590,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 690, "literal": "^1.3.0", @@ -31603,7 +31603,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 691, "literal": "^1.0.0", @@ -31616,7 +31616,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 692, "literal": "^1.0.2", @@ -31629,7 +31629,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 693, "literal": "^1.0.7", @@ -31642,7 +31642,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 694, "literal": "^1.2.1", @@ -31655,7 +31655,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 695, "literal": "^1.23.2", @@ -31668,7 +31668,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 696, "literal": "^1.0.0", @@ -31681,7 +31681,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 697, "literal": "^1.2.4", @@ -31694,7 +31694,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 698, "literal": "^1.0.7", @@ -31707,7 +31707,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 699, "literal": "^1.0.0", @@ -31720,7 +31720,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 700, "literal": "^4.2.4", @@ -31733,7 +31733,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 701, "literal": "^2.2.0", @@ -31759,7 +31759,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 703, "literal": "^4.3.4", @@ -31772,7 +31772,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 704, "literal": "6.21.0", @@ -31785,7 +31785,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 705, "literal": "6.21.0", @@ -31798,7 +31798,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 706, "literal": "6.21.0", @@ -31811,7 +31811,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 707, "literal": "6.21.0", @@ -31837,7 +31837,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 709, "literal": "^4.3.4", @@ -31850,7 +31850,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 710, "literal": "^11.1.0", @@ -31863,7 +31863,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 711, "literal": "^7.5.4", @@ -31876,7 +31876,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 712, "literal": "^4.0.3", @@ -31889,7 +31889,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 713, "literal": "9.0.3", @@ -31902,7 +31902,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 714, "literal": "^1.0.1", @@ -31915,7 +31915,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 715, "literal": "6.21.0", @@ -31928,7 +31928,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 716, "literal": "6.21.0", @@ -31941,7 +31941,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 717, "literal": "^3.4.1", @@ -31954,7 +31954,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 718, "literal": "6.21.0", @@ -31980,7 +31980,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 720, "literal": "^2.0.1", @@ -31993,7 +31993,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 721, "literal": "^2.1.0", @@ -32006,7 +32006,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 722, "literal": "^3.0.1", @@ -32019,7 +32019,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 723, "literal": "^3.2.9", @@ -32032,7 +32032,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 724, "literal": "^5.2.0", @@ -32045,7 +32045,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 725, "literal": "^1.4.1", @@ -32058,7 +32058,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 726, "literal": "^3.0.0", @@ -32071,7 +32071,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 727, "literal": "^4.0.0", @@ -32084,7 +32084,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 728, "literal": "6.21.0", @@ -32097,7 +32097,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 729, "literal": "6.21.0", @@ -32110,7 +32110,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 730, "literal": "10.3.10", @@ -32123,7 +32123,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 731, "literal": "^7.23.2", @@ -32136,7 +32136,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 732, "literal": "^5.3.0", @@ -32149,7 +32149,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 733, "literal": "^3.1.7", @@ -32162,7 +32162,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 734, "literal": "^1.3.2", @@ -32175,7 +32175,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 735, "literal": "^0.0.8", @@ -32188,7 +32188,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 736, "literal": "=4.7.0", @@ -32201,7 +32201,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 737, "literal": "^3.2.1", @@ -32214,7 +32214,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 738, "literal": "^1.0.8", @@ -32227,7 +32227,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 739, "literal": "^9.2.2", @@ -32240,7 +32240,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 740, "literal": "^1.0.15", @@ -32253,7 +32253,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 741, "literal": "^2.0.0", @@ -32266,7 +32266,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 742, "literal": "^3.3.5", @@ -32279,7 +32279,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 743, "literal": "^1.0.9", @@ -32292,7 +32292,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 744, "literal": "^3.1.2", @@ -32305,7 +32305,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 745, "literal": "^1.1.7", @@ -32318,7 +32318,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 746, "literal": "^2.0.7", @@ -32344,7 +32344,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 748, "literal": "^1.0.7", @@ -32357,7 +32357,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 749, "literal": "^1.2.1", @@ -32370,7 +32370,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 750, "literal": "^1.0.0", @@ -32383,7 +32383,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 751, "literal": "^0.3.20", @@ -32396,7 +32396,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 752, "literal": "^3.1.6", @@ -32409,7 +32409,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 753, "literal": "^1.3.1", @@ -32422,7 +32422,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 754, "literal": "^4.1.4", @@ -32435,7 +32435,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 755, "literal": "^1.1.6", @@ -32448,7 +32448,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 756, "literal": "^1.0.7", @@ -32461,7 +32461,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 757, "literal": "^1.2.1", @@ -32474,7 +32474,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 758, "literal": "^1.23.3", @@ -32487,7 +32487,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 759, "literal": "^1.3.0", @@ -32500,7 +32500,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 760, "literal": "^2.0.3", @@ -32513,7 +32513,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 761, "literal": "^1.1.2", @@ -32526,7 +32526,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 762, "literal": "^1.2.4", @@ -32539,7 +32539,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 763, "literal": "^1.0.3", @@ -32552,7 +32552,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 764, "literal": "^1.0.2", @@ -32565,7 +32565,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 765, "literal": "^1.0.3", @@ -32578,7 +32578,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 766, "literal": "^1.0.3", @@ -32591,7 +32591,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 767, "literal": "^1.0.7", @@ -32604,7 +32604,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 768, "literal": "^1.1.2", @@ -32617,7 +32617,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 769, "literal": "^1.1.2", @@ -32630,7 +32630,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 770, "literal": "^1.2.1", @@ -32643,7 +32643,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 771, "literal": "^1.2.1", @@ -32656,7 +32656,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 772, "literal": "^1.0.3", @@ -32669,7 +32669,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 773, "literal": "^1.0.4", @@ -32682,7 +32682,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 774, "literal": "^2.0.1", @@ -32695,7 +32695,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 775, "literal": "^1.0.7", @@ -32708,7 +32708,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 776, "literal": "^1.2.1", @@ -32721,7 +32721,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 777, "literal": "^1.23.1", @@ -32734,7 +32734,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 778, "literal": "^1.3.0", @@ -32747,7 +32747,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 779, "literal": "^1.2.4", @@ -32760,7 +32760,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 780, "literal": "^1.0.3", @@ -32773,7 +32773,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 781, "literal": "^1.1.3", @@ -32786,7 +32786,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 782, "literal": "^1.1.5", @@ -32799,7 +32799,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 783, "literal": "^1.0.0", @@ -32812,7 +32812,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 784, "literal": "^2.0.0", @@ -32825,7 +32825,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 785, "literal": "^1.0.5", @@ -32838,7 +32838,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 786, "literal": "^1.0.2", @@ -32851,7 +32851,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 787, "literal": "^1.0.10", @@ -32864,7 +32864,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 788, "literal": "^1.1.4", @@ -32877,7 +32877,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 789, "literal": "^1.0.2", @@ -32890,7 +32890,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 790, "literal": "^2.0.5", @@ -32903,7 +32903,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 791, "literal": "^1.0.2", @@ -32916,7 +32916,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 792, "literal": "^1.0.1", @@ -32929,7 +32929,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 793, "literal": "^1.1.9", @@ -32942,7 +32942,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 794, "literal": "^2.0.3", @@ -32955,7 +32955,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 795, "literal": "^2.0.3", @@ -32968,7 +32968,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 796, "literal": "^2.0.2", @@ -32981,7 +32981,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 797, "literal": "^2.0.3", @@ -32994,7 +32994,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 798, "literal": "^1.0.7", @@ -33007,7 +33007,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 799, "literal": "^1.2.4", @@ -33020,7 +33020,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 800, "literal": "^1.0.0", @@ -33033,7 +33033,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 801, "literal": "^1.0.2", @@ -33046,7 +33046,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 802, "literal": "^1.0.0", @@ -33059,7 +33059,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 803, "literal": "^2.0.3", @@ -33072,7 +33072,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 804, "literal": "^2.0.3", @@ -33085,7 +33085,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 805, "literal": "^0.14.0", @@ -33098,7 +33098,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 806, "literal": "^3.1.8", @@ -33111,7 +33111,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 807, "literal": "^1.2.5", @@ -33124,7 +33124,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 808, "literal": "^1.3.2", @@ -33137,7 +33137,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 809, "literal": "^1.1.2", @@ -33150,7 +33150,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 810, "literal": "^1.1.3", @@ -33163,7 +33163,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 811, "literal": "^2.1.0", @@ -33176,7 +33176,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 812, "literal": "^1.0.19", @@ -33189,7 +33189,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 813, "literal": "^5.3.0", @@ -33202,7 +33202,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 814, "literal": "^2.4.1 || ^3.0.0", @@ -33215,7 +33215,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 815, "literal": "^3.1.2", @@ -33228,7 +33228,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 816, "literal": "^1.1.8", @@ -33241,7 +33241,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 817, "literal": "^2.0.8", @@ -33254,7 +33254,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 818, "literal": "^1.1.4", @@ -33267,7 +33267,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 819, "literal": "^1.2.0", @@ -33280,7 +33280,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 820, "literal": "^15.8.1", @@ -33293,7 +33293,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 821, "literal": "^2.0.0-next.5", @@ -33306,7 +33306,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 822, "literal": "^6.3.1", @@ -33319,7 +33319,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 823, "literal": "^4.0.11", @@ -33345,7 +33345,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 825, "literal": "^1.0.7", @@ -33358,7 +33358,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 826, "literal": "^1.2.1", @@ -33371,7 +33371,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 827, "literal": "^1.23.2", @@ -33384,7 +33384,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 828, "literal": "^1.3.0", @@ -33397,7 +33397,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 829, "literal": "^1.0.0", @@ -33410,7 +33410,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 830, "literal": "^1.2.4", @@ -33423,7 +33423,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 831, "literal": "^1.0.1", @@ -33436,7 +33436,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 832, "literal": "^1.0.3", @@ -33449,7 +33449,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 833, "literal": "^1.0.7", @@ -33462,7 +33462,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 834, "literal": "^1.5.2", @@ -33475,7 +33475,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 835, "literal": "^2.0.2", @@ -33488,7 +33488,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 836, "literal": "^1.0.6", @@ -33501,7 +33501,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 837, "literal": "^2.13.0", @@ -33514,7 +33514,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 838, "literal": "^1.0.7", @@ -33527,7 +33527,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 839, "literal": "^1.0.0", @@ -33540,7 +33540,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 840, "literal": "^1.4.0", @@ -33553,7 +33553,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 841, "literal": "^4.1.1", @@ -33566,7 +33566,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 842, "literal": "^16.13.1", @@ -33579,7 +33579,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 843, "literal": "^1.2.1", @@ -33592,7 +33592,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 844, "literal": "^1.23.2", @@ -33605,7 +33605,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 845, "literal": "^1.0.0", @@ -33618,7 +33618,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 846, "literal": "^1.0.7", @@ -33631,7 +33631,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 847, "literal": "^1.2.1", @@ -33644,7 +33644,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 848, "literal": "^1.23.3", @@ -33657,7 +33657,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 849, "literal": "^1.3.0", @@ -33670,7 +33670,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 850, "literal": "^1.0.2", @@ -33683,7 +33683,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 851, "literal": "^1.0.2", @@ -33696,7 +33696,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 852, "literal": "^1.2.0", @@ -33709,7 +33709,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 853, "literal": "^1.22.1", @@ -33722,7 +33722,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 854, "literal": "^1.0.0", @@ -33735,7 +33735,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 855, "literal": "^1.0.7", @@ -33748,7 +33748,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 856, "literal": "^1.2.1", @@ -33761,7 +33761,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 857, "literal": "^1.23.2", @@ -33774,7 +33774,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 858, "literal": "^1.3.0", @@ -33787,7 +33787,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 859, "literal": "^1.0.0", @@ -33800,7 +33800,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 860, "literal": "^1.0.2", @@ -33813,7 +33813,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 861, "literal": "~8.5.10", @@ -33826,7 +33826,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 862, "literal": "~20.12.8", @@ -33839,7 +33839,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 863, "literal": "*", @@ -33852,7 +33852,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 864, "literal": "^4.21.10", @@ -33865,7 +33865,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 865, "literal": "^1.0.30001538", @@ -33878,7 +33878,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 866, "literal": "^4.3.6", @@ -33891,7 +33891,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 867, "literal": "^0.1.2", @@ -33904,7 +33904,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 868, "literal": "^1.0.0", @@ -33917,7 +33917,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 869, "literal": "^4.2.0", @@ -33943,7 +33943,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 871, "literal": "^1.0.30001587", @@ -33956,7 +33956,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 872, "literal": "^1.4.668", @@ -33969,7 +33969,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 873, "literal": "^2.0.14", @@ -33982,7 +33982,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 874, "literal": "^1.0.13", @@ -33995,7 +33995,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 875, "literal": "^3.1.2", @@ -34008,7 +34008,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 876, "literal": "^1.0.1", @@ -34034,7 +34034,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 878, "literal": "*", @@ -34047,7 +34047,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 879, "literal": "*", @@ -34060,7 +34060,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 880, "literal": "*", @@ -34073,7 +34073,7 @@ exports[`next build works: node 1`] = ` }, { "behavior": { - "normal": true, + "prod": true, }, "id": 881, "literal": "^3.0.2", From 1ae855223ce74425258d2bb60a8c12c3b315aceb Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 31 Dec 2024 14:48:54 -0800 Subject: [PATCH 116/125] Bump WebKit (#16068) --- cmake/targets/BuildBun.cmake | 1 - cmake/tools/SetupWebKit.cmake | 2 +- packages/bun-usockets/src/loop.c | 4 + src/bun.js/api/BunObject.zig | 9 +- src/bun.js/api/ffi.zig | 20 +- src/bun.js/bindings/BunProcess.cpp | 56 +-- src/bun.js/bindings/JSBuffer.cpp | 11 +- src/bun.js/bindings/ZigGlobalObject.cpp | 7 +- src/bun.js/bindings/ZigSourceProvider.cpp | 8 +- src/bun.js/bindings/bindings.cpp | 39 -- src/bun.js/bindings/bindings.zig | 9 - src/bun.js/bindings/headers.zig | 1 - src/bun.js/bindings/webcore/WebSocket.cpp | 35 +- src/bun.js/bindings/webcore/WebSocket.h | 3 + src/bun.js/bindings/webcore/Worker.cpp | 4 +- src/bun.js/bindings/windows/musl-memmem.c | 367 ------------------ src/bun.js/bindings/windows/musl-memmem.h | 1 - src/c.zig | 1 - src/darwin_c.zig | 2 + src/http/websocket_http_client.zig | 248 +++++++----- src/linux_c.zig | 1 + src/windows_c.zig | 22 ++ test/js/bun/sqlite/sqlite.test.js | 40 +- .../worker_threads/worker_thread_check.ts | 1 + .../js/web/websocket/websocket-client.test.ts | 18 +- test/js/web/websocket/websocket.test.js | 82 ++-- 26 files changed, 346 insertions(+), 646 deletions(-) delete mode 100644 src/bun.js/bindings/windows/musl-memmem.c delete mode 100644 src/bun.js/bindings/windows/musl-memmem.h diff --git a/cmake/targets/BuildBun.cmake b/cmake/targets/BuildBun.cmake index 35949d5239..bcbb8d8c5b 100644 --- a/cmake/targets/BuildBun.cmake +++ b/cmake/targets/BuildBun.cmake @@ -600,7 +600,6 @@ file(GLOB BUN_C_SOURCES ${CONFIGURE_DEPENDS} ) if(WIN32) - list(APPEND BUN_C_SOURCES ${CWD}/src/bun.js/bindings/windows/musl-memmem.c) list(APPEND BUN_CXX_SOURCES ${CWD}/src/bun.js/bindings/windows/rescle.cpp) list(APPEND BUN_CXX_SOURCES ${CWD}/src/bun.js/bindings/windows/rescle-binding.cpp) endif() diff --git a/cmake/tools/SetupWebKit.cmake b/cmake/tools/SetupWebKit.cmake index 2799048375..712f41aac8 100644 --- a/cmake/tools/SetupWebKit.cmake +++ b/cmake/tools/SetupWebKit.cmake @@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use") option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading") if(NOT WEBKIT_VERSION) - set(WEBKIT_VERSION 00e2b186fd25e79cea4cb4d63d9fd388192327f6) + set(WEBKIT_VERSION ba17b88ba9a5c1140bf74cf3a1637fbc89a3b9e7) endif() if(WEBKIT_LOCAL) diff --git a/packages/bun-usockets/src/loop.c b/packages/bun-usockets/src/loop.c index 19bb4fe9ea..0a26602d65 100644 --- a/packages/bun-usockets/src/loop.c +++ b/packages/bun-usockets/src/loop.c @@ -438,6 +438,10 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int eof, in } if(eof && s) { + if (UNLIKELY(us_socket_is_closed(0, s))) { + // Do not call on_end after the socket has been closed + return; + } if (us_socket_is_shut_down(0, s)) { /* We got FIN back after sending it */ s = us_socket_close(0, s, LIBUS_SOCKET_CLOSE_CODE_CLEAN_SHUTDOWN, NULL); diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index 4a3afe2313..a3a494b1a1 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -1154,11 +1154,11 @@ pub const Crypto = struct { }; } - pub const names: std.EnumArray(Algorithm, ZigString) = brk: { - var all = std.EnumArray(Algorithm, ZigString).initUndefined(); + pub const names: std.EnumArray(Algorithm, bun.String) = brk: { + var all = std.EnumArray(Algorithm, bun.String).initUndefined(); var iter = all.iterator(); while (iter.next()) |entry| { - entry.value.* = ZigString.init(@tagName(entry.key)); + entry.value.* = bun.String.init(@tagName(entry.key)); } break :brk all; }; @@ -2329,8 +2329,7 @@ pub const Crypto = struct { _: JSValue, _: JSValue, ) JSC.JSValue { - var values = EVP.Algorithm.names.values; - return JSC.JSValue.createStringArray(globalThis_, &values, values.len, true); + return bun.String.toJSArray(globalThis_, &EVP.Algorithm.names.values); } fn hashToEncoding(globalThis: *JSGlobalObject, evp: *EVP, input: JSC.Node.BlobOrStringOrBuffer, encoding: JSC.Node.Encoding) bun.JSError!JSC.JSValue { diff --git a/src/bun.js/api/ffi.zig b/src/bun.js/api/ffi.zig index 1f7a9a8499..9fffa7bb9d 100644 --- a/src/bun.js/api/ffi.zig +++ b/src/bun.js/api/ffi.zig @@ -983,8 +983,14 @@ pub const FFI = struct { return val; } JSC.markBinding(@src()); - var zig_strings = allocator.alloc(ZigString, symbols.count()) catch unreachable; - for (symbols.values(), 0..) |*function, i| { + var strs = std.ArrayList(bun.String).initCapacity(allocator, symbols.count()) catch bun.outOfMemory(); + defer { + for (strs.items) |str| { + str.deref(); + } + strs.deinit(); + } + for (symbols.values()) |*function| { var arraylist = std.ArrayList(u8).init(allocator); var writer = arraylist.writer(); function.printSourceCode(&writer) catch { @@ -992,9 +998,6 @@ pub const FFI = struct { for (symbols.keys()) |key| { allocator.free(@constCast(key)); } - for (zig_strings) |zig_string| { - allocator.free(@constCast(zig_string.slice())); - } for (symbols.values()) |*function_| { function_.arg_types.deinit(allocator); } @@ -1002,17 +1005,14 @@ pub const FFI = struct { symbols.clearAndFree(allocator); return ZigString.init("Error while printing code").toErrorInstance(global); }; - zig_strings[i] = ZigString.init(arraylist.items); + strs.appendAssumeCapacity(bun.String.createUTF8(arraylist.items)); } - const ret = JSC.JSValue.createStringArray(global, zig_strings.ptr, zig_strings.len, true); + const ret = bun.String.toJSArray(global, strs.items); for (symbols.keys()) |key| { allocator.free(@constCast(key)); } - for (zig_strings) |zig_string| { - allocator.free(@constCast(zig_string.slice())); - } for (symbols.values()) |*function_| { function_.arg_types.deinit(allocator); if (function_.step == .compiled) { diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index d18b1b4fc3..95c5ca6f4f 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -167,56 +167,56 @@ static JSValue constructVersions(VM& vm, JSObject* processObject) JSC::JSValue(JSC::jsOwnedString(vm, makeAtomString(ASCIILiteral::fromLiteralUnsafe(REPORTED_NODEJS_VERSION))))); object->putDirect( vm, JSC::Identifier::fromString(vm, "bun"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__version)).substring(1)))); + JSC::JSValue(JSC::jsOwnedString(vm, String(ASCIILiteral::fromLiteralUnsafe(Bun__version)).substring(1)))); object->putDirect(vm, JSC::Identifier::fromString(vm, "boringssl"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_boringssl)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, String(ASCIILiteral::fromLiteralUnsafe(Bun__versions_boringssl)))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "openssl"_s), // https://github.com/oven-sh/bun/issues/7921 // BoringSSL is a fork of OpenSSL 1.1.0, so we can report OpenSSL 1.1.0 - JSC::JSValue(JSC::jsString(vm, String("1.1.0"_s), 0))); + JSC::JSValue(JSC::jsOwnedString(vm, String("1.1.0"_s)))); object->putDirect(vm, JSC::Identifier::fromString(vm, "libarchive"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_libarchive)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_libarchive))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "mimalloc"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_mimalloc)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_mimalloc))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "picohttpparser"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_picohttpparser)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_picohttpparser))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "uwebsockets"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_uws)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_uws))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "webkit"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(BUN_WEBKIT_VERSION)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(BUN_WEBKIT_VERSION))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "zig"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_zig)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_zig))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "zlib"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_zlib)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_zlib))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "tinycc"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_tinycc)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_tinycc))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "lolhtml"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_lolhtml)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_lolhtml))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "ares"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_c_ares)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_c_ares))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "libdeflate"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_libdeflate)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_libdeflate))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "usockets"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_usockets)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_usockets))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "lshpack"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_lshpack)))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_lshpack))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "zstd"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(Bun__versions_zstd)))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "v8"_s), JSValue(JSC::jsString(vm, makeString("12.4.254.14-node.12"_s))), 0); + JSC::JSValue(JSC::jsOwnedString(vm, ASCIILiteral::fromLiteralUnsafe(Bun__versions_zstd))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "v8"_s), JSValue(JSC::jsOwnedString(vm, String("12.4.254.14-node.12"_s))), 0); #if OS(WINDOWS) - object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsString(vm, String::fromLatin1(uv_version_string()))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsOwnedString(vm, String::fromLatin1(uv_version_string()))), 0); #else - object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsString(vm, makeString("1.48.0"_s))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsOwnedString(vm, String("1.48.0"_s))), 0); #endif - object->putDirect(vm, JSC::Identifier::fromString(vm, "napi"_s), JSValue(JSC::jsString(vm, makeString("9"_s))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "napi"_s), JSValue(JSC::jsOwnedString(vm, String("9"_s))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "icu"_s), JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(U_ICU_VERSION)))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "unicode"_s), JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(U_UNICODE_VERSION)))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "icu"_s), JSValue(JSC::jsOwnedString(vm, String(ASCIILiteral::fromLiteralUnsafe(U_ICU_VERSION)))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "unicode"_s), JSValue(JSC::jsOwnedString(vm, String(ASCIILiteral::fromLiteralUnsafe(U_UNICODE_VERSION)))), 0); #define STRINGIFY_IMPL(x) #x #define STRINGIFY(x) STRINGIFY_IMPL(x) object->putDirect(vm, JSC::Identifier::fromString(vm, "modules"_s), - JSC::JSValue(JSC::jsString(vm, makeString(ASCIILiteral::fromLiteralUnsafe(STRINGIFY(REPORTED_NODEJS_ABI_VERSION)))))); + JSC::JSValue(JSC::jsOwnedString(vm, String(ASCIILiteral::fromLiteralUnsafe(STRINGIFY(REPORTED_NODEJS_ABI_VERSION)))))); #undef STRINGIFY #undef STRINGIFY_IMPL @@ -229,10 +229,10 @@ static JSValue constructProcessReleaseObject(VM& vm, JSObject* processObject) auto* release = JSC::constructEmptyObject(globalObject); // SvelteKit compatibility hack - release->putDirect(vm, vm.propertyNames->name, jsString(vm, WTF::String("node"_s)), 0); + release->putDirect(vm, vm.propertyNames->name, jsOwnedString(vm, WTF::String("node"_s)), 0); release->putDirect(vm, Identifier::fromString(vm, "lts"_s), jsBoolean(false), 0); - release->putDirect(vm, Identifier::fromString(vm, "sourceUrl"_s), jsString(vm, WTF::String(std::span { Bun__githubURL, strlen(Bun__githubURL) })), 0); + release->putDirect(vm, Identifier::fromString(vm, "sourceUrl"_s), jsOwnedString(vm, WTF::String(std::span { Bun__githubURL, strlen(Bun__githubURL) })), 0); release->putDirect(vm, Identifier::fromString(vm, "headersUrl"_s), jsEmptyString(vm), 0); release->putDirect(vm, Identifier::fromString(vm, "libUrl"_s), jsEmptyString(vm), 0); @@ -1583,7 +1583,7 @@ static JSValue constructReportObjectComplete(VM& vm, Zig::GlobalObject* globalOb auto timeStamp = WTF::String::fromLatin1(timeBuf); header->putDirect(vm, JSC::Identifier::fromString(vm, "dumpEventTime"_s), JSC::numberToString(vm, time, 10), 0); - header->putDirect(vm, JSC::Identifier::fromString(vm, "dumpEventTimeStamp"_s), JSC::jsString(vm, timeStamp, 0)); + header->putDirect(vm, JSC::Identifier::fromString(vm, "dumpEventTimeStamp"_s), JSC::jsString(vm, timeStamp)); header->putDirect(vm, JSC::Identifier::fromString(vm, "processId"_s), JSC::jsNumber(getpid()), 0); // TODO: header->putDirect(vm, JSC::Identifier::fromString(vm, "threadId"_s), JSC::jsNumber(0), 0); @@ -1634,7 +1634,7 @@ static JSValue constructReportObjectComplete(VM& vm, Zig::GlobalObject* globalOb #if OS(LINUX) #ifdef __GNU_LIBRARY__ header->putDirect(vm, JSC::Identifier::fromString(vm, "glibcVersionCompiler"_s), JSC::jsString(vm, makeString(__GLIBC__, '.', __GLIBC_MINOR__)), 0); - header->putDirect(vm, JSC::Identifier::fromString(vm, "glibcVersionRuntime"_s), JSC::jsString(vm, String::fromUTF8(gnu_get_libc_version()), 0)); + header->putDirect(vm, JSC::Identifier::fromString(vm, "glibcVersionRuntime"_s), JSC::jsString(vm, String::fromUTF8(gnu_get_libc_version())), 0); #else #endif #endif diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index fb0c0b5fe9..41976b38ad 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -63,7 +63,6 @@ #endif #if OS(WINDOWS) -#include "musl-memmem.h" #include #endif @@ -1288,12 +1287,20 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_fillBody(JSC::JSGlob RELEASE_AND_RETURN(scope, JSValue::encode(castedThis)); } +#if OS(WINDOWS) +extern "C" void* zig_memmem(const void* haystack, size_t haystack_len, const void* needle, size_t needle_len); +#define MEMMEM_IMPL zig_memmem +#else +#define MEMMEM_IMPL memmem +#endif + static int64_t indexOf(const uint8_t* thisPtr, int64_t thisLength, const uint8_t* valuePtr, int64_t valueLength, int64_t byteOffset) { if (thisLength < valueLength + byteOffset) return -1; auto start = thisPtr + byteOffset; - auto it = static_cast(memmem(start, static_cast(thisLength - byteOffset), valuePtr, static_cast(valueLength))); + + auto it = static_cast(MEMMEM_IMPL(start, static_cast(thisLength - byteOffset), valuePtr, static_cast(valueLength))); if (it != NULL) { return it - thisPtr; } diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index e08044c7c1..dcb2a251bb 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -868,7 +868,12 @@ void Zig::GlobalObject::resetOnEachMicrotaskTick() extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client, int32_t executionContextId, bool miniMode, bool evalMode, void* worker_ptr) { auto heapSize = miniMode ? JSC::HeapType::Small : JSC::HeapType::Large; - JSC::VM& vm = JSC::VM::create(heapSize).leakRef(); + RefPtr vmPtr = JSC::VM::tryCreate(heapSize); + if (UNLIKELY(!vmPtr)) { + BUN_PANIC("Failed to allocate JavaScriptCore Virtual Machine. Did your computer run out of memory? Or maybe you compiled Bun with a mismatching libc++ version or compiler?"); + } + vmPtr->refSuppressingSaferCPPChecking(); + JSC::VM& vm = *vmPtr; // This must happen before JSVMClientData::create vm.heap.acquireAccess(); JSC::JSLockHolder locker(vm); diff --git a/src/bun.js/bindings/ZigSourceProvider.cpp b/src/bun.js/bindings/ZigSourceProvider.cpp index 53c1236bb8..acb4f530f1 100644 --- a/src/bun.js/bindings/ZigSourceProvider.cpp +++ b/src/bun.js/bindings/ZigSourceProvider.cpp @@ -163,10 +163,10 @@ static JSC::VM& getVMForBytecodeCache() static thread_local JSC::VM* vmForBytecodeCache = nullptr; if (!vmForBytecodeCache) { const auto heapSize = JSC::HeapType::Small; - auto& vm = JSC::VM::create(heapSize).leakRef(); - vm.ref(); - vmForBytecodeCache = &vm; - vm.heap.acquireAccess(); + auto vmPtr = JSC::VM::tryCreate(heapSize); + vmPtr->refSuppressingSaferCPPChecking(); + vmForBytecodeCache = vmPtr.get(); + vmPtr->heap.acquireAccess(); } return *vmForBytecodeCache; } diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 244e7cc9e9..19ba3bb1df 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -2933,44 +2933,6 @@ CPP_DECL void JSC__JSValue__push(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg array->push(arg1, value2); } -JSC__JSValue JSC__JSValue__createStringArray(JSC__JSGlobalObject* globalObject, const ZigString* arg1, - size_t arg2, bool clone) -{ - JSC::VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - if (arg2 == 0) { - return JSC::JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr)); - } - - JSC::JSArray* array = nullptr; - { - JSC::GCDeferralContext deferralContext(vm); - JSC::ObjectInitializationScope initializationScope(vm); - if ((array = JSC::JSArray::tryCreateUninitializedRestricted( - initializationScope, &deferralContext, - globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), - arg2))) { - - if (!clone) { - for (size_t i = 0; i < arg2; ++i) { - array->putDirectIndex(globalObject, i, JSC::jsString(vm, Zig::toString(arg1[i]), &deferralContext)); - } - } else { - for (size_t i = 0; i < arg2; ++i) { - array->putDirectIndex(globalObject, i, JSC::jsString(vm, Zig::toStringCopy(arg1[i]), &deferralContext)); - } - } - } - - if (!array) { - JSC::throwOutOfMemoryError(globalObject, scope); - return {}; - } - - RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::JSValue(array))); - } -} - JSC__JSValue JSC__JSGlobalObject__createAggregateError(JSC__JSGlobalObject* globalObject, const JSValue* errors, size_t errors_count, const ZigString* arg3) @@ -5056,7 +5018,6 @@ size_t JSC__VM__runGC(JSC__VM* vm, bool sync) #endif vm->finalizeSynchronousJSExecution(); - WTF::releaseFastMallocFreeMemory(); if (sync) { vm->clearSourceProviderCaches(); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 9786b87e46..226ed64f8f 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -4618,15 +4618,6 @@ pub const JSValue = enum(i64) { return str; } - pub fn createStringArray(globalThis: *JSGlobalObject, str: [*c]const ZigString, strings_count: usize, clone: bool) JSValue { - return cppFn("createStringArray", .{ - globalThis, - str, - strings_count, - clone, - }); - } - pub fn print( this: JSValue, globalObject: *JSGlobalObject, diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index 5836a77370..c4f37d3490 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -209,7 +209,6 @@ pub extern fn JSC__JSValue__createInternalPromise(arg0: *bindings.JSGlobalObject pub extern fn JSC__JSValue__createObject2(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString, arg2: [*c]const ZigString, JSValue3: JSC__JSValue, JSValue4: JSC__JSValue) JSC__JSValue; pub extern fn JSC__JSValue__createRangeError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; pub extern fn JSC__JSValue__createRopeString(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) JSC__JSValue; -pub extern fn JSC__JSValue__createStringArray(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString, arg2: usize, arg3: bool) JSC__JSValue; pub extern fn JSC__JSValue__createTypeError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue; pub extern fn JSC__JSValue__createUninitializedUint8Array(arg0: *bindings.JSGlobalObject, arg1: usize) JSC__JSValue; pub extern fn JSC__JSValue__deepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; diff --git a/src/bun.js/bindings/webcore/WebSocket.cpp b/src/bun.js/bindings/webcore/WebSocket.cpp index dc1a24c81c..b2c8622f94 100644 --- a/src/bun.js/bindings/webcore/WebSocket.cpp +++ b/src/bun.js/bindings/webcore/WebSocket.cpp @@ -1027,11 +1027,7 @@ void WebSocket::didConnect() this->incPendingActivityCount(); context->postTask([this, protectedThis = Ref { *this }](ScriptExecutionContext& context) { ASSERT(scriptExecutionContext()); - - // m_subprotocol = m_channel->subprotocol(); - // m_extensions = m_channel->extensions(); protectedThis->dispatchEvent(Event::create(eventNames().openEvent, Event::CanBubble::No, Event::IsCancelable::No)); - // }); protectedThis->decPendingActivityCount(); }); } @@ -1250,25 +1246,20 @@ void WebSocket::didClose(unsigned unhandledBufferedAmount, unsigned short code, if (auto* context = scriptExecutionContext()) { context->postTask([this, protectedThis = Ref { *this }](ScriptExecutionContext& context) { ASSERT(scriptExecutionContext()); - protectedThis->decPendingActivityCount(); + protectedThis->disablePendingActivity(); }); - } else { - // we fallback if we don't have a context or we will leak - this->decPendingActivityCount(); + return; } - return; - } - - if (auto* context = scriptExecutionContext()) { + } else if (auto* context = scriptExecutionContext()) { context->postTask([this, code, wasClean, reason, protectedThis = Ref { *this }](ScriptExecutionContext& context) { ASSERT(scriptExecutionContext()); protectedThis->dispatchEvent(CloseEvent::create(wasClean, code, reason)); - protectedThis->decPendingActivityCount(); + protectedThis->disablePendingActivity(); }); - } else { - // we fallback if we don't have a context - this->decPendingActivityCount(); + return; } + + this->disablePendingActivity(); } void WebSocket::didConnect(us_socket_t* socket, char* bufferedData, size_t bufferedDataSize) @@ -1443,13 +1434,19 @@ void WebSocket::didFailWithErrorCode(int32_t code) m_state = CLOSED; if (auto* context = scriptExecutionContext()) { context->postTask([protectedThis = Ref { *this }](ScriptExecutionContext& context) { - protectedThis->decPendingActivityCount(); + protectedThis->disablePendingActivity(); }); } else { - // we fallback if we don't have a context - this->decPendingActivityCount(); + this->deref(); } } + +void WebSocket::disablePendingActivity() +{ + this->m_pendingActivityCount = 1; + this->decPendingActivityCount(); +} + void WebSocket::updateHasPendingActivity() { std::atomic_thread_fence(std::memory_order_acquire); diff --git a/src/bun.js/bindings/webcore/WebSocket.h b/src/bun.js/bindings/webcore/WebSocket.h index b9abed7a24..8aa4a8d6f2 100644 --- a/src/bun.js/bindings/webcore/WebSocket.h +++ b/src/bun.js/bindings/webcore/WebSocket.h @@ -125,6 +125,7 @@ public: using RefCounted::deref; using RefCounted::ref; void didConnect(); + void disablePendingActivity(); void didClose(unsigned unhandledBufferedAmount, unsigned short code, const String& reason); void didConnect(us_socket_t* socket, char* bufferedData, size_t bufferedDataSize); void didFailWithErrorCode(int32_t code); @@ -151,6 +152,7 @@ public: void incPendingActivityCount() { + ASSERT(m_pendingActivityCount < std::numeric_limits::max()); m_pendingActivityCount++; ref(); updateHasPendingActivity(); @@ -158,6 +160,7 @@ public: void decPendingActivityCount() { + ASSERT(m_pendingActivityCount > 0); m_pendingActivityCount--; deref(); updateHasPendingActivity(); diff --git a/src/bun.js/bindings/webcore/Worker.cpp b/src/bun.js/bindings/webcore/Worker.cpp index ad88e549ed..a9f8fdae5d 100644 --- a/src/bun.js/bindings/webcore/Worker.cpp +++ b/src/bun.js/bindings/webcore/Worker.cpp @@ -427,9 +427,9 @@ extern "C" void WebWorker__dispatchExit(Zig::GlobalObject* globalObject, Worker* // clang-tidy is smart enough to realize that deref() leads to freeing // but it's not smart enough to realize that `hasOneRef()` ensures its safety while (!vm.hasOneRef()) // NOLINT - vm.deref(); // NOLINT + vm.derefSuppressingSaferCPPChecking(); // NOLINT - vm.deref(); // NOLINT + vm.derefSuppressingSaferCPPChecking(); // NOLINT } } extern "C" void WebWorker__dispatchOnline(Worker* worker, Zig::GlobalObject* globalObject) diff --git a/src/bun.js/bindings/windows/musl-memmem.c b/src/bun.js/bindings/windows/musl-memmem.c deleted file mode 100644 index 115b99c91e..0000000000 --- a/src/bun.js/bindings/windows/musl-memmem.c +++ /dev/null @@ -1,367 +0,0 @@ -// musl as a whole is licensed under the following standard MIT license: -// -// ---------------------------------------------------------------------- -// Copyright © 2005-2020 Rich Felker, et al. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// ---------------------------------------------------------------------- -// -// Authors/contributors include: -// -// A. Wilcox -// Ada Worcester -// Alex Dowad -// Alex Suykov -// Alexander Monakov -// Andre McCurdy -// Andrew Kelley -// Anthony G. Basile -// Aric Belsito -// Arvid Picciani -// Bartosz Brachaczek -// Benjamin Peterson -// Bobby Bingham -// Boris Brezillon -// Brent Cook -// Chris Spiegel -// Clément Vasseur -// Daniel Micay -// Daniel Sabogal -// Daurnimator -// David Carlier -// David Edelsohn -// Denys Vlasenko -// Dmitry Ivanov -// Dmitry V. Levin -// Drew DeVault -// Emil Renner Berthing -// Fangrui Song -// Felix Fietkau -// Felix Janda -// Gianluca Anzolin -// Hauke Mehrtens -// He X -// Hiltjo Posthuma -// Isaac Dunham -// Jaydeep Patil -// Jens Gustedt -// Jeremy Huntwork -// Jo-Philipp Wich -// Joakim Sindholt -// John Spencer -// Julien Ramseier -// Justin Cormack -// Kaarle Ritvanen -// Khem Raj -// Kylie McClain -// Leah Neukirchen -// Luca Barbato -// Luka Perkov -// M Farkas-Dyck (Strake) -// Mahesh Bodapati -// Markus Wichmann -// Masanori Ogino -// Michael Clark -// Michael Forney -// Mikhail Kremnyov -// Natanael Copa -// Nicholas J. Kain -// orc -// Pascal Cuoq -// Patrick Oppenlander -// Petr Hosek -// Petr Skocik -// Pierre Carrier -// Reini Urban -// Rich Felker -// Richard Pennington -// Ryan Fairfax -// Samuel Holland -// Segev Finer -// Shiz -// sin -// Solar Designer -// Stefan Kristiansson -// Stefan O'Rear -// Szabolcs Nagy -// Timo Teräs -// Trutz Behn -// Valentin Ochs -// Will Dietz -// William Haddon -// William Pitcock -// -// Portions of this software are derived from third-party works licensed -// under terms compatible with the above MIT license: -// -// The TRE regular expression implementation (src/regex/reg* and -// src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed -// under a 2-clause BSD license (license text in the source files). The -// included version has been heavily modified by Rich Felker in 2012, in -// the interests of size, simplicity, and namespace cleanliness. -// -// Much of the math library code (src/math/* and src/complex/*) is -// Copyright © 1993,2004 Sun Microsystems or -// Copyright © 2003-2011 David Schultz or -// Copyright © 2003-2009 Steven G. Kargl or -// Copyright © 2003-2009 Bruce D. Evans or -// Copyright © 2008 Stephen L. Moshier or -// Copyright © 2017-2018 Arm Limited -// and labelled as such in comments in the individual source files. All -// have been licensed under extremely permissive terms. -// -// The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 -// The Android Open Source Project and is licensed under a two-clause BSD -// license. It was taken from Bionic libc, used on Android. -// -// The AArch64 memcpy and memset code (src/string/aarch64/*) are -// Copyright © 1999-2019, Arm Limited. -// -// The implementation of DES for crypt (src/crypt/crypt_des.c) is -// Copyright © 1994 David Burren. It is licensed under a BSD license. -// -// The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was -// originally written by Solar Designer and placed into the public -// domain. The code also comes with a fallback permissive license for use -// in jurisdictions that may not recognize the public domain. -// -// The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 -// Valentin Ochs and is licensed under an MIT-style license. -// -// The x86_64 port was written by Nicholas J. Kain and is licensed under -// the standard MIT terms. -// -// The mips and microblaze ports were originally written by Richard -// Pennington for use in the ellcc project. The original code was adapted -// by Rich Felker for build system and code conventions during upstream -// integration. It is licensed under the standard MIT terms. -// -// The mips64 port was contributed by Imagination Technologies and is -// licensed under the standard MIT terms. -// -// The powerpc port was also originally written by Richard Pennington, -// and later supplemented and integrated by John Spencer. It is licensed -// under the standard MIT terms. -// -// All other files which have no copyright comments are original works -// produced specifically for use as part of this library, written either -// by Rich Felker, the main author of the library, or by one or more -// contibutors listed above. Details on authorship of individual files -// can be found in the git version control history of the project. The -// omission of copyright and license comments in each file is in the -// interest of source tree size. -// -// In addition, permission is hereby granted for all public header files -// (include/* and arch/*/bits/*) and crt files intended to be linked into -// applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit -// the copyright notice and permission notice otherwise required by the -// license, and to use these files without any requirement of -// attribution. These files include substantial contributions from: -// -// Bobby Bingham -// John Spencer -// Nicholas J. Kain -// Rich Felker -// Richard Pennington -// Stefan Kristiansson -// Szabolcs Nagy -// -// all of whom have explicitly granted such permission. -// -// This file previously contained text expressing a belief that most of -// the files covered by the above exception were sufficiently trivial not -// to be subject to copyright, resulting in confusion over whether it -// negated the permissions granted in the license. In the spirit of -// permissive licensing, and of not having licensing issues being an -// obstacle to adoption, that text has been removed. -#ifdef WIN32 -#include -#include - -static char* twobyte_memmem(const unsigned char* h, size_t k, const unsigned char* n) -{ - uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1]; - for (h += 2, k -= 2; k; k--, hw = hw << 8 | *h++) - if (hw == nw) - return (char*)h - 2; - return hw == nw ? (char*)h - 2 : 0; -} - -static char* threebyte_memmem(const unsigned char* h, size_t k, const unsigned char* n) -{ - uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8; - uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8; - for (h += 3, k -= 3; k; k--, hw = (hw | *h++) << 8) - if (hw == nw) - return (char*)h - 3; - return hw == nw ? (char*)h - 3 : 0; -} - -static char* fourbyte_memmem(const unsigned char* h, size_t k, const unsigned char* n) -{ - uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; - uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; - for (h += 4, k -= 4; k; k--, hw = hw << 8 | *h++) - if (hw == nw) - return (char*)h - 4; - return hw == nw ? (char*)h - 4 : 0; -} - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -#define BITOP(a, b, op) \ - ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) - -static char* twoway_memmem(const unsigned char* h, const unsigned char* z, const unsigned char* n, size_t l) -{ - size_t i, ip, jp, k, p, ms, p0, mem, mem0; - size_t byteset[32 / sizeof(size_t)] = { 0 }; - size_t shift[256]; - - /* Computing length of needle and fill shift table */ - for (i = 0; i < l; i++) - BITOP(byteset, n[i], |=), shift[n[i]] = i + 1; - - /* Compute maximal suffix */ - ip = -1; - jp = 0; - k = p = 1; - while (jp + k < l) { - if (n[ip + k] == n[jp + k]) { - if (k == p) { - jp += p; - k = 1; - } else - k++; - } else if (n[ip + k] > n[jp + k]) { - jp += k; - k = 1; - p = jp - ip; - } else { - ip = jp++; - k = p = 1; - } - } - ms = ip; - p0 = p; - - /* And with the opposite comparison */ - ip = -1; - jp = 0; - k = p = 1; - while (jp + k < l) { - if (n[ip + k] == n[jp + k]) { - if (k == p) { - jp += p; - k = 1; - } else - k++; - } else if (n[ip + k] < n[jp + k]) { - jp += k; - k = 1; - p = jp - ip; - } else { - ip = jp++; - k = p = 1; - } - } - if (ip + 1 > ms + 1) - ms = ip; - else - p = p0; - - /* Periodic needle? */ - if (memcmp(n, n + p, ms + 1)) { - mem0 = 0; - p = MAX(ms, l - ms - 1) + 1; - } else - mem0 = l - p; - mem = 0; - - /* Search loop */ - for (;;) { - /* If remainder of haystack is shorter than needle, done */ - if (z - h < l) - return 0; - - /* Check last byte first; advance by shift on mismatch */ - if (BITOP(byteset, h[l - 1], &)) { - k = l - shift[h[l - 1]]; - if (k) { - if (k < mem) - k = mem; - h += k; - mem = 0; - continue; - } - } else { - h += l; - mem = 0; - continue; - } - - /* Compare right half */ - for (k = MAX(ms + 1, mem); k < l && n[k] == h[k]; k++) - ; - if (k < l) { - h += k - ms; - mem = 0; - continue; - } - /* Compare left half */ - for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) - ; - if (k <= mem) - return (char*)h; - h += p; - mem = mem0; - } -} - -extern void* memmem(const void* h0, size_t k, const void* n0, size_t l) -{ - const unsigned char *h = h0, *n = n0; - - /* Return immediately on empty needle */ - if (!l) - return (void*)h; - - /* Return immediately when needle is longer than haystack */ - if (k < l) - return 0; - - /* Use faster algorithms for short needles */ - h = memchr(h0, *n, k); - if (!h || l == 1) - return (void*)h; - k -= h - (const unsigned char*)h0; - if (k < l) - return 0; - if (l == 2) - return twobyte_memmem(h, k, n); - if (l == 3) - return threebyte_memmem(h, k, n); - if (l == 4) - return fourbyte_memmem(h, k, n); - - return twoway_memmem(h, h + k, n, l); -} -#endif \ No newline at end of file diff --git a/src/bun.js/bindings/windows/musl-memmem.h b/src/bun.js/bindings/windows/musl-memmem.h deleted file mode 100644 index b0d2f38fec..0000000000 --- a/src/bun.js/bindings/windows/musl-memmem.h +++ /dev/null @@ -1 +0,0 @@ -extern "C" void* memmem(const void* h0, size_t k, const void* n0, size_t l); \ No newline at end of file diff --git a/src/c.zig b/src/c.zig index 4b70e7c3fc..03ee097e08 100644 --- a/src/c.zig +++ b/src/c.zig @@ -398,7 +398,6 @@ pub fn getRelease(buf: []u8) []const u8 { } } -pub extern fn memmem(haystack: [*]const u8, haystacklen: usize, needle: [*]const u8, needlelen: usize) ?[*]const u8; pub extern fn cfmakeraw(*std.posix.termios) void; const LazyStatus = enum { diff --git a/src/darwin_c.zig b/src/darwin_c.zig index ed367f5f05..b13c73ff9d 100644 --- a/src/darwin_c.zig +++ b/src/darwin_c.zig @@ -66,6 +66,8 @@ pub const COPYFILE_CONTINUE = @as(c_int, 0); pub const COPYFILE_SKIP = @as(c_int, 1); pub const COPYFILE_QUIT = @as(c_int, 2); +pub extern "C" fn memmem(haystack: [*]const u8, haystacklen: usize, needle: [*]const u8, needlelen: usize) ?[*]const u8; + // int clonefileat(int src_dirfd, const char * src, int dst_dirfd, const char * dst, int flags); pub extern "c" fn clonefileat(c_int, [*:0]const u8, c_int, [*:0]const u8, uint32_t: c_int) c_int; // int fclonefileat(int srcfd, int dst_dirfd, const char * dst, int flags); diff --git a/src/http/websocket_http_client.zig b/src/http/websocket_http_client.zig index d93e2aff46..734b795835 100644 --- a/src/http/websocket_http_client.zig +++ b/src/http/websocket_http_client.zig @@ -207,7 +207,7 @@ const CppWebSocket = opaque { pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { return struct { pub const Socket = uws.NewSocketHandler(ssl); - tcp: ?Socket = null, + tcp: Socket, outgoing_websocket: ?*CppWebSocket, input_body_buf: []u8 = &[_]u8{}, client_protocol: []const u8 = "", @@ -219,13 +219,14 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { hostname: [:0]const u8 = "", poll_ref: Async.KeepAlive = Async.KeepAlive.init(), state: State = .initializing, + ref_count: u32 = 1, const State = enum { initializing, reading, failed }; pub const name = if (ssl) "WebSocketHTTPSClient" else "WebSocketHTTPClient"; pub const shim = JSC.Shimmer("Bun", name, @This()); - pub usingnamespace bun.New(@This()); + pub usingnamespace bun.NewRefCounted(@This(), deinit); const HTTPClient = @This(); pub fn register(_: *JSC.JSGlobalObject, _: *anyopaque, ctx: *uws.SocketContext) callconv(.C) void { @@ -247,6 +248,12 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { ); } + pub fn deinit(this: *HTTPClient) void { + this.clearData(); + bun.debugAssert(this.tcp.isDetached()); + this.destroy(); + } + /// On error, this returns null. /// Returning null signals to the parent function that the connection failed. pub fn connect( @@ -278,7 +285,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { ) catch return null; var client = HTTPClient.new(.{ - .tcp = null, + .tcp = .{ .socket = .{ .detached = {} } }, .outgoing_websocket = websocket, .input_body_buf = body, .websocket_protocol = client_protocol_hash, @@ -306,8 +313,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { )) |out| { // I don't think this case gets reached. if (out.state == .failed) { - client.clearData(); - client.destroy(); + client.deref(); return null; } bun.Analytics.Features.WebSocket += 1; @@ -318,12 +324,13 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { } } - out.tcp.?.timeout(120); + out.tcp.timeout(120); out.state = .reading; + // +1 for cpp_websocket + out.ref(); return out; } else |_| { - client.clearData(); - client.destroy(); + client.deref(); } return null; @@ -341,40 +348,58 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { } pub fn cancel(this: *HTTPClient) callconv(.C) void { this.clearData(); - this.outgoing_websocket = null; - const tcp = this.tcp orelse return; - this.tcp = null; + + // Either of the below two operations - closing the TCP socket or clearing the C++ reference could trigger a deref + // Therefore, we need to make sure the `this` pointer is valid until the end of the function. + this.ref(); + defer this.deref(); + + // The C++ end of the socket is no longer holding a reference to this, sowe must clear it. + if (this.outgoing_websocket != null) { + this.outgoing_websocket = null; + this.deref(); + } + // no need to be .failure we still wanna to send pending SSL buffer + close_notify if (comptime ssl) { - tcp.close(.normal); + this.tcp.close(.normal); } else { - tcp.close(.failure); + this.tcp.close(.failure); } } pub fn fail(this: *HTTPClient, code: ErrorCode) void { - log("onFail", .{}); + log("onFail: {s}", .{@tagName(code)}); JSC.markBinding(@src()); + + this.ref(); + defer this.deref(); + + this.dispatchAbruptClose(code); + + if (comptime ssl) { + this.tcp.close(.normal); + } else { + this.tcp.close(.failure); + } + } + + fn dispatchAbruptClose(this: *HTTPClient, code: ErrorCode) void { if (this.outgoing_websocket) |ws| { this.outgoing_websocket = null; ws.didAbruptClose(code); + this.deref(); } - - this.cancel(); } pub fn handleClose(this: *HTTPClient, _: Socket, _: c_int, _: ?*anyopaque) void { log("onClose", .{}); JSC.markBinding(@src()); this.clearData(); - this.tcp = null; + this.tcp.detach(); + this.dispatchAbruptClose(ErrorCode.ended); - if (this.outgoing_websocket) |ws| { - this.outgoing_websocket = null; - - ws.didAbruptClose(ErrorCode.ended); - } - this.destroy(); + this.deref(); } pub fn terminate(this: *HTTPClient, code: ErrorCode) void { @@ -441,18 +466,18 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { } pub fn isSameSocket(this: *HTTPClient, socket: Socket) bool { - if (this.tcp) |tcp| { - return socket.socket.eq(tcp.socket); - } - return false; + return socket.socket.eq(this.tcp.socket); } pub fn handleData(this: *HTTPClient, socket: Socket, data: []const u8) void { log("onData", .{}); if (this.outgoing_websocket == null) { this.clearData(); + socket.close(.failure); return; } + this.ref(); + defer this.deref(); bun.assert(this.isSameSocket(socket)); @@ -493,10 +518,8 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { this.processResponse(response, body[@as(usize, @intCast(response.bytes_read))..]); } - pub fn handleEnd(this: *HTTPClient, socket: Socket) void { + pub fn handleEnd(this: *HTTPClient, _: Socket) void { log("onEnd", .{}); - - bun.assert(this.isSameSocket(socket)); this.terminate(ErrorCode.ended); } @@ -612,11 +635,24 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { this.clearData(); JSC.markBinding(@src()); - if (this.tcp != null and this.outgoing_websocket != null) { - this.tcp.?.timeout(0); + if (!this.tcp.isClosed() and this.outgoing_websocket != null) { + this.tcp.timeout(0); log("onDidConnect", .{}); - this.outgoing_websocket.?.didConnect(this.tcp.?.socket.get().?, overflow.ptr, overflow.len); + // Once for the outgoing_websocket. + defer this.deref(); + const ws = bun.take(&this.outgoing_websocket).?; + const socket = this.tcp; + + this.tcp.detach(); + // Once again for the TCP socket. + defer this.deref(); + + ws.didConnect(socket.socket.get().?, overflow.ptr, overflow.len); + } else if (this.tcp.isClosed()) { + this.terminate(ErrorCode.cancel); + } else if (this.outgoing_websocket == null) { + this.tcp.close(.failure); } } @@ -636,6 +672,9 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { if (this.to_send.len == 0) return; + this.ref(); + defer this.deref(); + // Do not set MSG_MORE, see https://github.com/oven-sh/bun/issues/4010 const wrote = socket.write(this.to_send, false); if (wrote < 0) { @@ -654,13 +693,13 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { // In theory, this could be called immediately // In that case, we set `state` to `failed` and return, expecting the parent to call `destroy`. pub fn handleConnectError(this: *HTTPClient, _: Socket, _: c_int) void { - this.tcp = null; + this.tcp.detach(); - // the socket is freed by usockets when the connection fails + // For the TCP socket. + defer this.deref(); if (this.state == .reading) { this.terminate(ErrorCode.failed_to_connect); - this.destroy(); } else { this.state = .failed; } @@ -956,7 +995,7 @@ const Copy = union(enum) { pub fn NewWebSocketClient(comptime ssl: bool) type { return struct { pub const Socket = uws.NewSocketHandler(ssl); - tcp: ?Socket = null, + tcp: Socket, outgoing_websocket: ?*CppWebSocket = null, receive_state: ReceiveState = ReceiveState.need_header, @@ -986,6 +1025,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { initial_data_handler: ?*InitialDataHandler = null, event_loop: *JSC.EventLoop = undefined, + ref_count: u32 = 1, pub const name = if (ssl) "WebSocketClientTLS" else "WebSocketClient"; @@ -994,7 +1034,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { const WebSocket = @This(); - pub usingnamespace bun.New(@This()); + pub usingnamespace bun.NewRefCounted(@This(), deinit); pub fn register(global: *JSC.JSGlobalObject, loop_: *anyopaque, ctx_: *anyopaque) callconv(.C) void { const vm = global.bunVM(); const loop = @as(*uws.Loop, @ptrCast(@alignCast(loop_))); @@ -1037,13 +1077,12 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { pub fn cancel(this: *WebSocket) callconv(.C) void { log("cancel", .{}); this.clearData(); - const tcp = this.tcp orelse return; - this.tcp = null; - // no need to be .failure we still wanna to send pending SSL buffer + close_notify + if (comptime ssl) { - tcp.close(.normal); + // we still want to send pending SSL buffer + close_notify + this.tcp.close(.normal); } else { - tcp.close(.failure); + this.tcp.close(.failure); } } @@ -1052,8 +1091,8 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { if (this.outgoing_websocket) |ws| { this.outgoing_websocket = null; log("fail ({s})", .{@tagName(code)}); - ws.didAbruptClose(code); + this.deref(); } this.cancel(); @@ -1092,10 +1131,12 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { log("onClose", .{}); JSC.markBinding(@src()); this.clearData(); - if (this.outgoing_websocket) |ws| { - this.outgoing_websocket = null; - ws.didAbruptClose(ErrorCode.ended); - } + this.tcp.detach(); + + this.dispatchAbruptClose(ErrorCode.ended); + + // For the socket. + this.deref(); } pub fn terminate(this: *WebSocket, code: ErrorCode) void { @@ -1202,6 +1243,8 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { // after receiving close we should ignore the data if (this.close_received) return; + this.ref(); + defer this.deref(); // Due to scheduling, it is possible for the websocket onData // handler to run with additional data before the microtask queue is @@ -1217,7 +1260,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { bun.assert(this.initial_data_handler == null); // If we disconnected for any reason in the re-entrant case, we should just ignore the data - if (this.outgoing_websocket == null or this.tcp == null or this.tcp.?.isShutdown() or this.tcp.?.isClosed()) + if (this.outgoing_websocket == null or !this.hasTCP()) return; } @@ -1528,9 +1571,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { } pub fn sendClose(this: *WebSocket) void { - if (this.tcp) |tcp| { - this.sendCloseWithBody(tcp, 1000, null, 0); - } + this.sendCloseWithBody(this.tcp, 1000, null, 0); } fn enqueueEncodedBytes( @@ -1574,11 +1615,9 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { if (do_write) { if (comptime Environment.allow_assert) { - if (this.tcp) |tcp| { - bun.assert(!tcp.isShutdown()); - bun.assert(!tcp.isClosed()); - bun.assert(tcp.isEstablished()); - } + bun.assert(!this.tcp.isShutdown()); + bun.assert(!this.tcp.isClosed()); + bun.assert(this.tcp.isEstablished()); } return this.sendBuffer(this.send_buffer.readableSlice(0)); } @@ -1592,8 +1631,10 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { ) bool { bun.assert(out_buf.len > 0); // Do not set MSG_MORE, see https://github.com/oven-sh/bun/issues/4010 - const tcp = this.tcp orelse return false; - const wrote = tcp.write(out_buf, false); + if (this.tcp.isClosed()) { + return false; + } + const wrote = this.tcp.write(out_buf, false); if (wrote < 0) { this.terminate(ErrorCode.failed_to_write); return false; @@ -1609,7 +1650,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { fn sendPong(this: *WebSocket, socket: Socket) bool { if (socket.isClosed() or socket.isShutdown()) { - this.dispatchAbruptClose(); + this.dispatchAbruptClose(ErrorCode.ended); return false; } @@ -1641,7 +1682,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { ) void { log("Sending close with code {d}", .{code}); if (socket.isClosed() or socket.isShutdown()) { - this.dispatchAbruptClose(); + this.dispatchAbruptClose(ErrorCode.ended); this.clearData(); return; } @@ -1678,15 +1719,12 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { Mask.fill(this.globalThis, mask_buf, slice[6..], slice[6..]); if (this.enqueueEncodedBytes(socket, slice)) { - this.dispatchClose(code, &reason); this.clearData(); + this.dispatchClose(code, &reason); } } pub fn isSameSocket(this: *WebSocket, socket: Socket) bool { - if (this.tcp) |tcp| { - return socket.socket.eq(tcp.socket); - } - return false; + return socket.socket.eq(this.tcp.socket); } pub fn handleEnd(this: *WebSocket, socket: Socket) void { @@ -1712,6 +1750,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { this.terminate(ErrorCode.timeout); } pub fn handleConnectError(this: *WebSocket, _: Socket, _: c_int) void { + this.tcp.detach(); this.terminate(ErrorCode.failed_to_connect); } @@ -1726,7 +1765,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { op: u8, ) callconv(.C) void { if (!this.hasTCP() or op > 0xF) { - this.dispatchAbruptClose(); + this.dispatchAbruptClose(ErrorCode.ended); return; } @@ -1738,17 +1777,14 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { if (!this.hasBackpressure() and frame_size < stack_frame_size) { var inline_buf: [stack_frame_size]u8 = undefined; bytes.copy(this.globalThis, inline_buf[0..frame_size], slice.len, opcode); - _ = this.enqueueEncodedBytes(this.tcp.?, inline_buf[0..frame_size]); + _ = this.enqueueEncodedBytes(this.tcp, inline_buf[0..frame_size]); return; } _ = this.sendData(bytes, !this.hasBackpressure(), opcode); } fn hasTCP(this: *WebSocket) bool { - if (this.tcp) |tcp| { - return !tcp.isClosed() and !tcp.isShutdown(); - } - return false; + return !this.tcp.isClosed() and !this.tcp.isShutdown(); } pub fn writeString( @@ -1758,10 +1794,10 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { ) callconv(.C) void { const str = str_.*; if (!this.hasTCP()) { - this.dispatchAbruptClose(); + this.dispatchAbruptClose(ErrorCode.ended); return; } - const tcp = this.tcp.?; + const tcp = this.tcp; // Note: 0 is valid @@ -1801,12 +1837,13 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { ); } - fn dispatchAbruptClose(this: *WebSocket) void { + fn dispatchAbruptClose(this: *WebSocket, code: ErrorCode) void { var out = this.outgoing_websocket orelse return; this.poll_ref.unref(this.globalThis.bunVM()); JSC.markBinding(@src()); this.outgoing_websocket = null; - out.didAbruptClose(ErrorCode.closed); + out.didAbruptClose(code); + this.deref(); } fn dispatchClose(this: *WebSocket, code: u16, reason: *const bun.String) void { @@ -1815,12 +1852,13 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { JSC.markBinding(@src()); this.outgoing_websocket = null; out.didClose(code, reason); + this.deref(); } pub fn close(this: *WebSocket, code: u16, reason: ?*const JSC.ZigString) callconv(.C) void { if (!this.hasTCP()) return; - const tcp = this.tcp.?; + const tcp = this.tcp; var close_reason_buf: [128]u8 = undefined; if (reason) |str| { inner: { @@ -1842,6 +1880,8 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { pub const Handle = JSC.AnyTask.New(@This(), handle); + pub usingnamespace bun.New(@This()); + pub fn handleWithoutDeinit(this: *@This()) void { var this_socket = this.adopted orelse return; this.adopted = null; @@ -1849,17 +1889,19 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { var ws = this.ws; defer ws.unref(); - if (this_socket.outgoing_websocket != null and this_socket.tcp != null) { - this_socket.handleData(this_socket.tcp.?, this.slice); + if (this_socket.outgoing_websocket != null and !this_socket.tcp.isClosed()) { + this_socket.handleData(this_socket.tcp, this.slice); } } pub fn handle(this: *@This()) void { - defer { - bun.default_allocator.free(this.slice); - bun.default_allocator.destroy(this); - } this.handleWithoutDeinit(); + this.deinit(); + } + + pub fn deinit(this: *@This()) void { + bun.default_allocator.free(this.slice); + this.destroy(); } }; @@ -1874,13 +1916,14 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { const tcp = @as(*uws.Socket, @ptrCast(input_socket)); const ctx = @as(*uws.SocketContext, @ptrCast(socket_ctx)); var ws = WebSocket.new(WebSocket{ - .tcp = undefined, + .tcp = .{ .socket = .{ .detached = {} } }, .outgoing_websocket = outgoing, .globalThis = globalThis, .send_buffer = bun.LinearFifo(u8, .Dynamic).init(bun.default_allocator), .receive_buffer = bun.LinearFifo(u8, .Dynamic).init(bun.default_allocator), .event_loop = globalThis.bunVM().eventLoop(), }); + if (!Socket.adoptPtr( tcp, ctx, @@ -1888,7 +1931,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { "tcp", ws, )) { - ws.destroy(); + ws.deref(); return null; } @@ -1898,12 +1941,11 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { const buffered_slice: []u8 = buffered_data[0..buffered_data_len]; if (buffered_slice.len > 0) { - const initial_data = bun.default_allocator.create(InitialDataHandler) catch unreachable; - initial_data.* = .{ + const initial_data = InitialDataHandler.new(.{ .adopted = ws, .slice = buffered_slice, .ws = outgoing, - }; + }); // Use a higher-priority callback for the initial onData handler globalThis.queueMicrotaskCallback(initial_data, InitialDataHandler.handle); @@ -1912,6 +1954,10 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { // before the initial data handler is called outgoing.ref(); } + + // And lastly, ref the new websocket since C++ has a reference to it + ws.ref(); + return @as( *anyopaque, @ptrCast(ws), @@ -1922,15 +1968,25 @@ pub fn NewWebSocketClient(comptime ssl: bool) type { log("finalize", .{}); this.clearData(); - this.outgoing_websocket = null; - const tcp = this.tcp orelse return; - this.tcp = null; - // no need to be .failure we still wanna to send pending SSL buffer + close_notify - if (comptime ssl) { - tcp.close(.normal); - } else { - tcp.close(.failure); + // This is only called by outgoing_websocket. + if (this.outgoing_websocket != null) { + this.outgoing_websocket = null; + this.deref(); } + + if (!this.tcp.isClosed()) { + // no need to be .failure we still wanna to send pending SSL buffer + close_notify + if (comptime ssl) { + this.tcp.close(.normal); + } else { + this.tcp.close(.failure); + } + } + } + + pub fn deinit(this: *WebSocket) void { + this.clearData(); + this.destroy(); } pub fn memoryCost(this: *WebSocket) callconv(.C) usize { diff --git a/src/linux_c.zig b/src/linux_c.zig index bf99c08271..d29d846da3 100644 --- a/src/linux_c.zig +++ b/src/linux_c.zig @@ -1,5 +1,6 @@ const std = @import("std"); const bun = @import("root").bun; +pub extern "C" fn memmem(haystack: [*]const u8, haystacklen: usize, needle: [*]const u8, needlelen: usize) ?[*]const u8; pub const SystemErrno = enum(u8) { SUCCESS = 0, EPERM = 1, diff --git a/src/windows_c.zig b/src/windows_c.zig index 86d3c32f95..df725226c6 100644 --- a/src/windows_c.zig +++ b/src/windows_c.zig @@ -8,6 +8,28 @@ const Stat = std.fs.File.Stat; const Kind = std.fs.File.Kind; const StatError = std.fs.File.StatError; +// Windows doesn't have memmem, so we need to implement it +pub export fn memmem(haystack: ?[*]const u8, haystacklen: usize, needle: ?[*]const u8, needlelen: usize) ?[*]const u8 { + // Handle null pointers + if (haystack == null or needle == null) return null; + + // Handle empty needle case + if (needlelen == 0) return haystack; + + // Handle case where needle is longer than haystack + if (needlelen > haystacklen) return null; + + const hay = haystack.?[0..haystacklen]; + const nee = needle.?[0..needlelen]; + + const i = std.mem.indexOf(u8, hay, nee) orelse return null; + return hay.ptr + i; +} + +comptime { + @export(memmem, .{ .name = "zig_memmem" }); +} + pub const lstat = blk: { const T = *const fn ([*c]const u8, [*c]std.c.Stat) callconv(.C) c_int; break :blk @extern(T, .{ .name = "lstat64" }); diff --git a/test/js/bun/sqlite/sqlite.test.js b/test/js/bun/sqlite/sqlite.test.js index ae57c6cad8..28795ec13f 100644 --- a/test/js/bun/sqlite/sqlite.test.js +++ b/test/js/bun/sqlite/sqlite.test.js @@ -1242,27 +1242,33 @@ it("should dispose", () => { it("can continue to use existing statements after database has been GC'd", async () => { let called = false; - const registry = new FinalizationRegistry(() => { - called = true; - }); - function leakTheStatement() { - const db = new Database(":memory:"); - console.log("---"); - db.exec("CREATE TABLE foo (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)"); - db.exec("INSERT INTO foo (name) VALUES ('foo')"); - const prepared = db.prepare("SELECT * FROM foo"); - registry.register(db); - return prepared; + async function run() { + const registry = new FinalizationRegistry(() => { + called = true; + }); + function leakTheStatement() { + const db = new Database(":memory:"); + console.log("---"); + db.exec("CREATE TABLE foo (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)"); + db.exec("INSERT INTO foo (name) VALUES ('foo')"); + const prepared = db.prepare("SELECT * FROM foo"); + registry.register(db); + return prepared; + } + + const stmt = leakTheStatement(); + + Bun.gc(true); + await Bun.sleep(1); + Bun.gc(true); + expect(stmt.all()).toEqual([{ id: 1, name: "foo" }]); + stmt.finalize(); + expect(() => stmt.all()).toThrow(); } - - const stmt = leakTheStatement(); - + await run(); Bun.gc(true); await Bun.sleep(1); Bun.gc(true); - expect(stmt.all()).toEqual([{ id: 1, name: "foo" }]); - stmt.finalize(); - expect(() => stmt.all()).toThrow(); if (!isWindows) { // on Windows, FinalizationRegistry is more flaky than on POSIX. expect(called).toBe(true); diff --git a/test/js/node/worker_threads/worker_thread_check.ts b/test/js/node/worker_threads/worker_thread_check.ts index 48ae9de7a1..004786cad6 100644 --- a/test/js/node/worker_threads/worker_thread_check.ts +++ b/test/js/node/worker_threads/worker_thread_check.ts @@ -28,6 +28,7 @@ if (isMainThread) { action, port: server.port, }, + env: process.env, }); worker.ref(); const { promise, resolve } = Promise.withResolvers(); diff --git a/test/js/web/websocket/websocket-client.test.ts b/test/js/web/websocket/websocket-client.test.ts index 3e260f6eba..d771350fad 100644 --- a/test/js/web/websocket/websocket-client.test.ts +++ b/test/js/web/websocket/websocket-client.test.ts @@ -3,6 +3,15 @@ import { spawn } from "bun"; import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { bunEnv, bunExe, nodeExe } from "harness"; import * as path from "node:path"; +function test( + label: string, + fn: (ws: WebSocket, done: (err?: unknown) => void) => void, + timeout?: number, + isOnly = false, +) { + return makeTest(label, fn, timeout, isOnly); +} +test.only = (label, fn, timeout) => makeTest(label, fn, timeout, true); const strings = [ { @@ -236,8 +245,13 @@ describe("WebSocket", () => { }); }); -function test(label: string, fn: (ws: WebSocket, done: (err?: unknown) => void) => void, timeout?: number) { - it( +function makeTest( + label: string, + fn: (ws: WebSocket, done: (err?: unknown) => void) => void, + timeout?: number, + isOnly = false, +) { + return (isOnly ? it.only : it)( label, testDone => { let isDone = false; diff --git a/test/js/web/websocket/websocket.test.js b/test/js/web/websocket/websocket.test.js index e1736b1199..7a84a615e3 100644 --- a/test/js/web/websocket/websocket.test.js +++ b/test/js/web/websocket/websocket.test.js @@ -500,34 +500,8 @@ describe("WebSocket", () => { }); it("instances should be finalized when GC'd", async () => { - const { expect } = require("bun:test"); - - using server = Bun.serve({ - port: 0, - fetch(req, server) { - return server.upgrade(req); - }, - websocket: { - open() {}, - data() {}, - message() {}, - drain() {}, - }, - }); - - function openAndCloseWS() { - const { promise, resolve } = Promise.withResolvers(); - const sock = new WebSocket(server.url.href.replace("http", "ws")); - sock.addEventListener("open", _ => { - sock.addEventListener("close", () => { - resolve(); - }); - sock.close(); - }); - - return promise; - } - + let current_websocket_count = 0; + let initial_websocket_count = 0; function getWebSocketCount() { Bun.gc(true); const objectTypeCounts = require("bun:jsc").heapStats().objectTypeCounts || { @@ -535,25 +509,53 @@ describe("WebSocket", () => { }; return objectTypeCounts.WebSocket || 0; } - let current_websocket_count = 0; - let initial_websocket_count = 0; - for (let i = 0; i < 1000; i++) { - await openAndCloseWS(); - if (i % 100 === 0) { - current_websocket_count = getWebSocketCount(); - // if we have more than 1 batch of websockets open, we have a problem - expect(current_websocket_count).toBeLessThanOrEqual(100); - if (initial_websocket_count === 0) { - initial_websocket_count = current_websocket_count; + async function run() { + using server = Bun.serve({ + port: 0, + fetch(req, server) { + return server.upgrade(req); + }, + websocket: { + open() {}, + data() {}, + message() {}, + drain() {}, + }, + }); + + function onOpen(sock, resolve) { + sock.addEventListener("close", resolve, { once: true }); + sock.close(); + } + + function openAndCloseWS() { + const { promise, resolve } = Promise.withResolvers(); + const sock = new WebSocket(server.url.href.replace("http", "ws")); + sock.addEventListener("open", onOpen.bind(undefined, sock, resolve), { + once: true, + }); + + return promise; + } + + for (let i = 0; i < 1000; i++) { + await openAndCloseWS(); + if (i % 100 === 0) { + if (initial_websocket_count === 0) { + initial_websocket_count = getWebSocketCount(); + } } } } + await run(); + // wait next tick to run the last time - await Bun.sleep(1); + await Bun.sleep(100); current_websocket_count = getWebSocketCount(); + console.log({ current_websocket_count, initial_websocket_count }); // expect that current and initial websocket be close to the same (normaly 1 or 2 difference) - expect(Math.abs(current_websocket_count - initial_websocket_count)).toBeLessThanOrEqual(5); + expect(Math.abs(current_websocket_count - initial_websocket_count)).toBeLessThanOrEqual(50); }); it("should be able to send big messages", async () => { From 02196cbf0e4c30a0ddf4387d4c8cb05e79fec798 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 31 Dec 2024 17:06:49 -0800 Subject: [PATCH 117/125] Avoid resolving substrings unnecessarily (#16090) --- src/bun.js/bindings/DOMFormData.cpp | 10 ++++---- src/bun.js/bindings/DOMFormData.h | 8 +++--- src/bun.js/bindings/ErrorCode.cpp | 2 +- src/bun.js/bindings/ErrorCode.h | 2 +- src/bun.js/bindings/JSBuffer.cpp | 25 ++++++++++++------- src/bun.js/bindings/JSBufferEncodingType.cpp | 10 ++++++-- src/bun.js/bindings/JSBufferEncodingType.h | 2 +- src/bun.js/bindings/JSStringDecoder.cpp | 5 ++-- src/bun.js/bindings/NodeHTTP.cpp | 5 +++- src/bun.js/bindings/URLSearchParams.cpp | 8 +++--- src/bun.js/bindings/URLSearchParams.h | 8 +++--- src/bun.js/bindings/ZigGlobalObject.cpp | 2 +- src/bun.js/bindings/helpers.h | 18 ++++++++++--- src/bun.js/bindings/webcore/FetchHeaders.cpp | 6 ++--- src/bun.js/bindings/webcore/FetchHeaders.h | 6 ++--- src/bun.js/bindings/webcore/HTTPHeaderMap.cpp | 8 +++--- src/bun.js/bindings/webcore/HTTPHeaderMap.h | 10 ++++---- .../bindings/webcore/HTTPHeaderNames.cpp | 2 +- src/bun.js/bindings/webcore/HTTPHeaderNames.h | 2 +- src/bun.js/bindings/webcore/HTTPParsers.cpp | 21 ++++++---------- src/bun.js/bindings/webcore/HTTPParsers.h | 17 ++++++------- src/bun.js/bindings/webcore/JSDOMFormData.cpp | 12 ++++++--- .../bindings/webcore/JSFetchHeaders.cpp | 24 ++++++++++++------ src/bun.js/bindings/webcore/JSTextEncoder.cpp | 13 +++++++--- .../bindings/webcore/JSURLSearchParams.cpp | 18 ++++++++----- 25 files changed, 146 insertions(+), 98 deletions(-) diff --git a/src/bun.js/bindings/DOMFormData.cpp b/src/bun.js/bindings/DOMFormData.cpp index 34cd431cb6..08c203585f 100644 --- a/src/bun.js/bindings/DOMFormData.cpp +++ b/src/bun.js/bindings/DOMFormData.cpp @@ -110,14 +110,14 @@ void DOMFormData::append(const String& name, RefPtr blob, const String& fi blob->setFileName(replaceUnpairedSurrogatesWithReplacementCharacter(String(filename))); m_items.append({ replaceUnpairedSurrogatesWithReplacementCharacter(String(name)), blob }); } -void DOMFormData::remove(const String& name) +void DOMFormData::remove(const StringView name) { - m_items.removeAllMatching([&name](const auto& item) { + m_items.removeAllMatching([name](const auto& item) { return item.name == name; }); } -auto DOMFormData::get(const String& name) -> std::optional +auto DOMFormData::get(const StringView name) -> std::optional { for (auto& item : m_items) { if (item.name == name) @@ -127,7 +127,7 @@ auto DOMFormData::get(const String& name) -> std::optional return std::nullopt; } -auto DOMFormData::getAll(const String& name) -> Vector +auto DOMFormData::getAll(const StringView name) -> Vector { Vector result; @@ -139,7 +139,7 @@ auto DOMFormData::getAll(const String& name) -> Vector return result; } -bool DOMFormData::has(const String& name) +bool DOMFormData::has(const StringView name) { for (auto& item : m_items) { if (item.name == name) diff --git a/src/bun.js/bindings/DOMFormData.h b/src/bun.js/bindings/DOMFormData.h index 0f0c1518ce..8a25f0b60a 100644 --- a/src/bun.js/bindings/DOMFormData.h +++ b/src/bun.js/bindings/DOMFormData.h @@ -65,10 +65,10 @@ public: void append(const String& name, const String& value); void append(const String& name, RefPtr, const String& filename = {}); - void remove(const String& name); - std::optional get(const String& name); - Vector getAll(const String& name); - bool has(const String& name); + void remove(const StringView name); + std::optional get(const StringView name); + Vector getAll(const StringView name); + bool has(const StringView name); void set(const String& name, const String& value); void set(const String& name, RefPtr, const String& filename = {}); Ref clone() const; diff --git a/src/bun.js/bindings/ErrorCode.cpp b/src/bun.js/bindings/ErrorCode.cpp index 8a7d9c2e97..bb7c91195c 100644 --- a/src/bun.js/bindings/ErrorCode.cpp +++ b/src/bun.js/bindings/ErrorCode.cpp @@ -522,7 +522,7 @@ JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobal return {}; } -JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& encoding) +JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::StringView encoding) { auto message = makeString("Unknown encoding: "_s, encoding); throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_ENCODING, message)); diff --git a/src/bun.js/bindings/ErrorCode.h b/src/bun.js/bindings/ErrorCode.h index 6a4387e51c..9c288f9b06 100644 --- a/src/bun.js/bindings/ErrorCode.h +++ b/src/bun.js/bindings/ErrorCode.h @@ -85,7 +85,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name_val, const WTF::String& msg, JSC::JSValue actual); JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, WTF::ASCIILiteral name, JSC::JSValue value, const WTF::String& reason = "is invalid"_s); JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, const WTF::String& reason = "is invalid"_s); -JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& encoding); +JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::StringView encoding); JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& statemsg); JSC::EncodedJSValue STRING_TOO_LONG(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject); JSC::EncodedJSValue BUFFER_OUT_OF_BOUNDS(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject); diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index 41976b38ad..ef55090712 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -251,11 +251,11 @@ static inline WebCore::BufferEncodingType parseEncoding(JSC::JSGlobalObject* lex { auto arg_ = arg.toStringOrNull(lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, {}); - auto arg_s = arg_->getString(lexicalGlobalObject); + const auto& view = arg_->view(lexicalGlobalObject); - std::optional encoded = parseEnumeration2(*lexicalGlobalObject, arg_s); + std::optional encoded = parseEnumeration2(*lexicalGlobalObject, view); if (UNLIKELY(!encoded)) { - Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg_s); + Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, view); return WebCore::BufferEncodingType::utf8; } @@ -322,7 +322,7 @@ static inline JSC::EncodedJSValue writeToBuffer(JSC::JSGlobalObject* lexicalGlob if (UNLIKELY(str->length() == 0)) return JSC::JSValue::encode(JSC::jsNumber(0)); - const auto& view = str->value(lexicalGlobalObject); + const auto& view = str->view(lexicalGlobalObject); if (view->isNull()) { return {}; } @@ -444,7 +444,9 @@ static JSC::EncodedJSValue constructFromEncoding(JSGlobalObject* lexicalGlobalOb auto& vm = JSC::getVM(lexicalGlobalObject); auto scope = DECLARE_THROW_SCOPE(vm); - const auto& view = str->tryGetValue(lexicalGlobalObject); + // Use ->view() here instead of ->value() as that will avoid flattening ropestrings from .slice() + const auto& view = str->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, {}); JSC::EncodedJSValue result; if (view->is8Bit()) { @@ -524,7 +526,10 @@ static inline JSC::EncodedJSValue constructBufferFromStringAndEncoding(JSC::JSGl if (arg1 && arg1.isString()) { std::optional encoded = parseEnumeration(*lexicalGlobalObject, arg1); if (!encoded) { - return Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg1.getString(lexicalGlobalObject)); + auto* encodingString = arg1.toString(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, {}); + const auto& view = encodingString->view(lexicalGlobalObject); + return Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, view); } encoding = encoded.value(); @@ -569,13 +574,15 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocBody(JSC::JSG } } auto startPtr = uint8Array->typedVector() + start; - auto str_ = value.toWTFString(lexicalGlobalObject); - if (str_.isEmpty()) { + auto str_ = value.toString(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, {}); + const auto& view = str_->view(lexicalGlobalObject); + if (view->isEmpty()) { memset(startPtr, 0, length); RELEASE_AND_RETURN(scope, JSC::JSValue::encode(uint8Array)); } - ZigString str = Zig::toZigString(str_); + ZigString str = Zig::toZigString(view); if (UNLIKELY(!Bun__Buffer_fill(&str, startPtr, end - start, encoding))) { throwTypeError(lexicalGlobalObject, scope, "Failed to decode value"_s); diff --git a/src/bun.js/bindings/JSBufferEncodingType.cpp b/src/bun.js/bindings/JSBufferEncodingType.cpp index 903ba94951..cd4efd318d 100644 --- a/src/bun.js/bindings/JSBufferEncodingType.cpp +++ b/src/bun.js/bindings/JSBufferEncodingType.cpp @@ -57,10 +57,16 @@ template<> std::optional parseEnumerationview(&lexicalGlobalObject); + return parseEnumeration2(lexicalGlobalObject, view); } -std::optional parseEnumeration2(JSGlobalObject& lexicalGlobalObject, WTF::String encoding) +std::optional parseEnumeration2(JSGlobalObject& lexicalGlobalObject, const WTF::StringView encoding) { // caller must check if value is a string switch (encoding.length()) { diff --git a/src/bun.js/bindings/JSBufferEncodingType.h b/src/bun.js/bindings/JSBufferEncodingType.h index f6e26116fa..e468b09cd1 100644 --- a/src/bun.js/bindings/JSBufferEncodingType.h +++ b/src/bun.js/bindings/JSBufferEncodingType.h @@ -8,7 +8,7 @@ String convertEnumerationToString(BufferEncodingType); template<> JSC::JSString* convertEnumerationToJS(JSC::JSGlobalObject&, BufferEncodingType); template<> std::optional parseEnumeration(JSC::JSGlobalObject&, JSValue); -std::optional parseEnumeration2(JSC::JSGlobalObject&, WTF::String); +std::optional parseEnumeration2(JSC::JSGlobalObject&, const WTF::StringView); template<> WTF::ASCIILiteral expectedEnumerationValues(); } // namespace WebCore diff --git a/src/bun.js/bindings/JSStringDecoder.cpp b/src/bun.js/bindings/JSStringDecoder.cpp index ff6a0c18c0..42c4aac1d7 100644 --- a/src/bun.js/bindings/JSStringDecoder.cpp +++ b/src/bun.js/bindings/JSStringDecoder.cpp @@ -571,9 +571,10 @@ JSC::EncodedJSValue JSStringDecoderConstructor::construct(JSC::JSGlobalObject* l if (opt.has_value()) { encoding = opt.value(); } else { - WTF::String encodingString = jsEncoding.toWTFString(lexicalGlobalObject); + auto* encodingString = jsEncoding.toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); - return Bun::ERR::UNKNOWN_ENCODING(throwScope, lexicalGlobalObject, encodingString); + const auto& view = encodingString->view(lexicalGlobalObject); + return Bun::ERR::UNKNOWN_ENCODING(throwScope, lexicalGlobalObject, view); } } JSValue thisValue = callFrame->newTarget(); diff --git a/src/bun.js/bindings/NodeHTTP.cpp b/src/bun.js/bindings/NodeHTTP.cpp index 1bef336c82..943bfd8f7f 100644 --- a/src/bun.js/bindings/NodeHTTP.cpp +++ b/src/bun.js/bindings/NodeHTTP.cpp @@ -386,7 +386,10 @@ JSC_DEFINE_HOST_FUNCTION(jsHTTPGetHeader, (JSGlobalObject * globalObject, CallFr JSValue nameValue = callFrame->argument(1); if (nameValue.isString()) { FetchHeaders* impl = &headers->wrapped(); - String name = nameValue.toWTFString(globalObject); + JSString* nameString = nameValue.toString(globalObject); + RETURN_IF_EXCEPTION(scope, {}); + const auto name = nameString->view(globalObject); + RETURN_IF_EXCEPTION(scope, {}); if (WTF::equalIgnoringASCIICase(name, "set-cookie"_s)) { return fetchHeadersGetSetCookie(globalObject, vm, impl); } diff --git a/src/bun.js/bindings/URLSearchParams.cpp b/src/bun.js/bindings/URLSearchParams.cpp index 0b688b8be2..e8a15e5194 100644 --- a/src/bun.js/bindings/URLSearchParams.cpp +++ b/src/bun.js/bindings/URLSearchParams.cpp @@ -79,7 +79,7 @@ ExceptionOr> URLSearchParams::create(std::variant URLSearchParams::getAll(const String& name) const +Vector URLSearchParams::getAll(const StringView name) const { Vector values; values.reserveInitialCapacity(m_pairs.size()); @@ -150,7 +150,7 @@ Vector URLSearchParams::getAll(const String& name) const return values; } -void URLSearchParams::remove(const String& name, const String& value) +void URLSearchParams::remove(const StringView name, const String& value) { m_pairs.removeAllMatching([&](const auto& pair) { return pair.key == name && (value.isNull() || pair.value == value); diff --git a/src/bun.js/bindings/URLSearchParams.h b/src/bun.js/bindings/URLSearchParams.h index a8744053e5..2bc00cb590 100644 --- a/src/bun.js/bindings/URLSearchParams.h +++ b/src/bun.js/bindings/URLSearchParams.h @@ -47,10 +47,10 @@ public: } void append(const String& name, const String& value); - void remove(const String& name, const String& value = {}); - String get(const String& name) const; - Vector getAll(const String& name) const; - bool has(const String& name, const String& value = {}) const; + void remove(const StringView name, const String& value = {}); + String get(const StringView name) const; + Vector getAll(const StringView name) const; + bool has(const StringView name, const String& value = {}) const; void set(const String& name, const String& value); String toString() const; void updateFromAssociatedURL(); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index dcb2a251bb..e718a28527 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -297,7 +297,7 @@ static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalO auto* str = errorMessage.toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, {}); if (str->length() > 0) { - auto value = str->value(lexicalGlobalObject); + auto value = str->view(lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, {}); sb.append("Error: "_s); sb.append(value.data); diff --git a/src/bun.js/bindings/helpers.h b/src/bun.js/bindings/helpers.h index cf5a5e875f..cabb787ce1 100644 --- a/src/bun.js/bindings/helpers.h +++ b/src/bun.js/bindings/helpers.h @@ -251,11 +251,18 @@ static ZigString toZigString(const WTF::StringView& str) static ZigString toZigString(JSC::JSString& str, JSC::JSGlobalObject* global) { + if (str.isSubstring()) { + return toZigString(str.view(global)); + } + return toZigString(str.value(global)); } static ZigString toZigString(JSC::JSString* str, JSC::JSGlobalObject* global) { + if (str->isSubstring()) { + return toZigString(str->view(global)); + } return toZigString(str->value(global)); } @@ -283,7 +290,7 @@ static void throwException(JSC::ThrowScope& scope, ZigErrorType err, JSC::JSGlob static ZigString toZigString(JSC::JSValue val, JSC::JSGlobalObject* global) { auto scope = DECLARE_THROW_SCOPE(global->vm()); - WTF::String str = val.toWTFString(global); + auto* str = val.toString(global); if (scope.exception()) { scope.clearException(); @@ -291,9 +298,14 @@ static ZigString toZigString(JSC::JSValue val, JSC::JSGlobalObject* global) return ZigStringEmpty; } - scope.release(); + auto view = str->view(global); + if (scope.exception()) { + scope.clearException(); + scope.release(); + return ZigStringEmpty; + } - return toZigString(str); + return toZigString(view); } static const WTF::String toStringStatic(ZigString str) diff --git a/src/bun.js/bindings/webcore/FetchHeaders.cpp b/src/bun.js/bindings/webcore/FetchHeaders.cpp index f50fdc8923..a6b64d5cd1 100644 --- a/src/bun.js/bindings/webcore/FetchHeaders.cpp +++ b/src/bun.js/bindings/webcore/FetchHeaders.cpp @@ -205,7 +205,7 @@ ExceptionOr FetchHeaders::append(const String& name, const String& value) } // https://fetch.spec.whatwg.org/#dom-headers-delete -ExceptionOr FetchHeaders::remove(const String& name) +ExceptionOr FetchHeaders::remove(const StringView name) { if (!isValidHTTPToken(name)) return Exception { TypeError, makeString("Invalid header name: '"_s, name, "'"_s) }; @@ -232,14 +232,14 @@ size_t FetchHeaders::memoryCost() const return m_headers.memoryCost() + sizeof(*this); } -ExceptionOr FetchHeaders::get(const String& name) const +ExceptionOr FetchHeaders::get(const StringView name) const { if (!isValidHTTPToken(name)) return Exception { TypeError, makeString("Invalid header name: '"_s, name, "'"_s) }; return m_headers.get(name); } -ExceptionOr FetchHeaders::has(const String& name) const +ExceptionOr FetchHeaders::has(const StringView name) const { if (!isValidHTTPToken(name)) return Exception { TypeError, makeString("Invalid header name: '"_s, name, '"') }; diff --git a/src/bun.js/bindings/webcore/FetchHeaders.h b/src/bun.js/bindings/webcore/FetchHeaders.h index e28db4f966..eac56928c7 100644 --- a/src/bun.js/bindings/webcore/FetchHeaders.h +++ b/src/bun.js/bindings/webcore/FetchHeaders.h @@ -59,9 +59,9 @@ public: static Ref create(const FetchHeaders& headers) { return adoptRef(*new FetchHeaders { headers }); } ExceptionOr append(const String& name, const String& value); - ExceptionOr remove(const String&); - ExceptionOr get(const String&) const; - ExceptionOr has(const String&) const; + ExceptionOr remove(const StringView); + ExceptionOr get(const StringView) const; + ExceptionOr has(const StringView) const; ExceptionOr set(const String& name, const String& value); ExceptionOr set(const HTTPHeaderName name, const String& value); diff --git a/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp b/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp index 577485117b..65330b5af5 100644 --- a/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp +++ b/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp @@ -68,7 +68,7 @@ HTTPHeaderMap HTTPHeaderMap::isolatedCopy() && return map; } -String HTTPHeaderMap::get(const String& name) const +String HTTPHeaderMap::get(const StringView name) const { HTTPHeaderName headerName; if (findHTTPHeaderName(name, headerName)) @@ -96,7 +96,7 @@ size_t HTTPHeaderMap::memoryCost() const return cost; } -String HTTPHeaderMap::getUncommonHeader(const String& name) const +String HTTPHeaderMap::getUncommonHeader(const StringView name) const { auto index = m_uncommonHeaders.findIf([&](auto& header) { return equalIgnoringASCIICase(header.key, name); @@ -201,7 +201,7 @@ bool HTTPHeaderMap::addIfNotPresent(HTTPHeaderName headerName, const String& val return true; } -bool HTTPHeaderMap::contains(const String& name) const +bool HTTPHeaderMap::contains(const StringView name) const { HTTPHeaderName headerName; if (findHTTPHeaderName(name, headerName)) @@ -212,7 +212,7 @@ bool HTTPHeaderMap::contains(const String& name) const }) != notFound; } -bool HTTPHeaderMap::remove(const String& name) +bool HTTPHeaderMap::remove(const StringView name) { HTTPHeaderName headerName; diff --git a/src/bun.js/bindings/webcore/HTTPHeaderMap.h b/src/bun.js/bindings/webcore/HTTPHeaderMap.h index 589d2945cf..bbc28eedf0 100644 --- a/src/bun.js/bindings/webcore/HTTPHeaderMap.h +++ b/src/bun.js/bindings/webcore/HTTPHeaderMap.h @@ -182,13 +182,13 @@ public: m_uncommonHeaders.shrinkToFit(); } - WEBCORE_EXPORT String get(const String &name) const; + WEBCORE_EXPORT String get(const StringView name) const; WEBCORE_EXPORT void set(const String &name, const String &value); WEBCORE_EXPORT void add(const String &name, const String &value); WEBCORE_EXPORT void append(const String &name, const String &value); - WEBCORE_EXPORT bool contains(const String &) const; - WEBCORE_EXPORT int64_t indexOf(String &name) const; - WEBCORE_EXPORT bool remove(const String &); + WEBCORE_EXPORT bool contains(const StringView) const; + WEBCORE_EXPORT int64_t indexOf(StringView name) const; + WEBCORE_EXPORT bool remove(const StringView); WEBCORE_EXPORT String getIndex(HeaderIndex index) const; WEBCORE_EXPORT bool setIndex(HeaderIndex index, const String &value); @@ -265,7 +265,7 @@ public: void setUncommonHeaderCloneName(const StringView name, const String &value); private: - WEBCORE_EXPORT String getUncommonHeader(const String &name) const; + WEBCORE_EXPORT String getUncommonHeader(const StringView name) const; CommonHeadersVector m_commonHeaders; UncommonHeadersVector m_uncommonHeaders; diff --git a/src/bun.js/bindings/webcore/HTTPHeaderNames.cpp b/src/bun.js/bindings/webcore/HTTPHeaderNames.cpp index 2c548b6a01..8b36ed87cb 100644 --- a/src/bun.js/bindings/webcore/HTTPHeaderNames.cpp +++ b/src/bun.js/bindings/webcore/HTTPHeaderNames.cpp @@ -655,7 +655,7 @@ HTTPHeaderNamesHash::findHeaderNameImpl(const char* str, size_t len) } #line 253 "HTTPHeaderNames.gperf" -bool findHTTPHeaderName(StringView stringView, HTTPHeaderName& headerName) +bool findHTTPHeaderName(const StringView stringView, HTTPHeaderName& headerName) { unsigned length = stringView.length(); if (length > maxHTTPHeaderNameLength || length < minHTTPHeaderNameLength) diff --git a/src/bun.js/bindings/webcore/HTTPHeaderNames.h b/src/bun.js/bindings/webcore/HTTPHeaderNames.h index 42db45a00f..4f7575e283 100644 --- a/src/bun.js/bindings/webcore/HTTPHeaderNames.h +++ b/src/bun.js/bindings/webcore/HTTPHeaderNames.h @@ -132,7 +132,7 @@ const unsigned numHTTPHeaderNames = 93; const size_t minHTTPHeaderNameLength = 2; const size_t maxHTTPHeaderNameLength = 40; -bool findHTTPHeaderName(StringView, HTTPHeaderName&); +bool findHTTPHeaderName(const StringView, HTTPHeaderName&); WEBCORE_EXPORT StringView httpHeaderNameString(HTTPHeaderName); } // namespace WebCore diff --git a/src/bun.js/bindings/webcore/HTTPParsers.cpp b/src/bun.js/bindings/webcore/HTTPParsers.cpp index 2bef4f365e..7318ce5914 100644 --- a/src/bun.js/bindings/webcore/HTTPParsers.cpp +++ b/src/bun.js/bindings/webcore/HTTPParsers.cpp @@ -193,7 +193,7 @@ bool isValidLanguageHeaderValue(const String& value) } // See RFC 7230, Section 3.2.6. -bool isValidHTTPToken(StringView value) +bool isValidHTTPToken(const StringView value) { if (value.isEmpty()) return false; @@ -215,11 +215,6 @@ bool isValidHTTPToken(StringView value) return true; } -bool isValidHTTPToken(const String& value) -{ - return isValidHTTPToken(StringView(value)); -} - #if USE(GLIB) // True if the character at the given position satisifies a predicate, incrementing "pos" by one. // Note: Might return pos == str.length() @@ -817,18 +812,18 @@ size_t parseHTTPRequestBody(const uint8_t* data, size_t length, Vector& } // Implements . -bool isForbiddenHeaderName(const String& name) +bool isForbiddenHeaderName(const StringView name) { return false; } -bool isForbiddenHeader(const String& name, StringView value) +bool isForbiddenHeader(const StringView name, StringView value) { return false; } // Implements . -bool isNoCORSSafelistedRequestHeaderName(const String& name) +bool isNoCORSSafelistedRequestHeaderName(const StringView name) { HTTPHeaderName headerName; if (findHTTPHeaderName(name, headerName)) { @@ -846,27 +841,27 @@ bool isNoCORSSafelistedRequestHeaderName(const String& name) } // Implements . -bool isPriviledgedNoCORSRequestHeaderName(const String& name) +bool isPriviledgedNoCORSRequestHeaderName(const StringView name) { return false; // return equalLettersIgnoringASCIICase(name, "range"_s); } // Implements . -bool isForbiddenResponseHeaderName(const String& name) +bool isForbiddenResponseHeaderName(const StringView name) { return false; // return equalLettersIgnoringASCIICase(name, "set-cookie"_s) || equalLettersIgnoringASCIICase(name, "set-cookie2"_s); } // Implements . -bool isForbiddenMethod(StringView name) +bool isForbiddenMethod(const StringView name) { // return equalLettersIgnoringASCIICase(name, "connect"_s) || equalLettersIgnoringASCIICase(name, "trace"_s) || equalLettersIgnoringASCIICase(name, "track"_s); return false; } -bool isSimpleHeader(const String& name, const String& value) +bool isSimpleHeader(const StringView name, const StringView value) { HTTPHeaderName headerName; return !findHTTPHeaderName(name, headerName); diff --git a/src/bun.js/bindings/webcore/HTTPParsers.h b/src/bun.js/bindings/webcore/HTTPParsers.h index bf56caccb1..05c9aebc55 100644 --- a/src/bun.js/bindings/webcore/HTTPParsers.h +++ b/src/bun.js/bindings/webcore/HTTPParsers.h @@ -80,8 +80,7 @@ bool isValidLanguageHeaderValue(const String&); #if USE(GLIB) WEBCORE_EXPORT bool isValidUserAgentHeaderValue(const String&); #endif -bool isValidHTTPToken(const String&); -bool isValidHTTPToken(StringView); +bool isValidHTTPToken(const StringView); std::optional parseHTTPDate(const String&); StringView filenameFromHTTPContentDisposition(StringView); WEBCORE_EXPORT String extractMIMETypeFromMediaType(const String&); @@ -101,15 +100,15 @@ size_t parseHTTPHeader(const uint8_t* data, size_t length, String& failureReason size_t parseHTTPRequestBody(const uint8_t* data, size_t length, Vector& body); // HTTP Header routine as per https://fetch.spec.whatwg.org/#terminology-headers -bool isForbiddenHeaderName(const String&); -bool isNoCORSSafelistedRequestHeaderName(const String&); -bool isPriviledgedNoCORSRequestHeaderName(const String&); -bool isForbiddenResponseHeaderName(const String&); -bool isForbiddenMethod(const String&); -bool isSimpleHeader(const String& name, const String& value); +bool isForbiddenHeaderName(const StringView); +bool isNoCORSSafelistedRequestHeaderName(const StringView); +bool isPriviledgedNoCORSRequestHeaderName(const StringView); +bool isForbiddenResponseHeaderName(const StringView); +bool isForbiddenMethod(const StringView); +bool isSimpleHeader(const StringView name, const StringView value); // bool isCrossOriginSafeHeader(HTTPHeaderName, const HTTPHeaderSet&); // bool isCrossOriginSafeHeader(const String&, const HTTPHeaderSet&); -bool isCrossOriginSafeRequestHeader(HTTPHeaderName, const String&); +bool isCrossOriginSafeRequestHeader(HTTPHeaderName, const StringView); String normalizeHTTPMethod(const String&); bool isSafeMethod(const String&); diff --git a/src/bun.js/bindings/webcore/JSDOMFormData.cpp b/src/bun.js/bindings/webcore/JSDOMFormData.cpp index 92bb50c8cf..1ddee5427b 100644 --- a/src/bun.js/bindings/webcore/JSDOMFormData.cpp +++ b/src/bun.js/bindings/webcore/JSDOMFormData.cpp @@ -373,9 +373,11 @@ static inline JSC::EncodedJSValue jsDOMFormDataPrototypeFunction_getBody(JSC::JS if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto name = convert(*lexicalGlobalObject, argument0.value()); + auto* nameStr = argument0.value().toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, impl.get(WTFMove(name))))); + auto name = nameStr->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, impl.get(name)))); } JSC_DEFINE_HOST_FUNCTION(jsDOMFormDataPrototypeFunction_get, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) @@ -393,9 +395,11 @@ static inline JSC::EncodedJSValue jsDOMFormDataPrototypeFunction_getAllBody(JSC: if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto name = convert(*lexicalGlobalObject, argument0.value()); + auto* nameStr = argument0.value().toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); - auto entries = impl.getAll(WTFMove(name)); + auto name = nameStr->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + auto entries = impl.getAll(name); JSC::JSArray* result = JSC::constructEmptyArray(lexicalGlobalObject, nullptr, 0); for (auto entry : entries) { if (auto string = std::get_if(&entry)) { diff --git a/src/bun.js/bindings/webcore/JSFetchHeaders.cpp b/src/bun.js/bindings/webcore/JSFetchHeaders.cpp index 8a57ca1908..c2d42fc86d 100644 --- a/src/bun.js/bindings/webcore/JSFetchHeaders.cpp +++ b/src/bun.js/bindings/webcore/JSFetchHeaders.cpp @@ -210,11 +210,13 @@ JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_getAll, (JSGlobalObject return {}; } - auto name = convert(*lexicalGlobalObject, callFrame->uncheckedArgument(0)); + auto* nameStr = callFrame->uncheckedArgument(0).toString(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, {}); + auto name = nameStr->view(lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, {}); auto& impl = castedThis->wrapped(); - if (name.length() != "set-cookie"_s.length() || name.convertToASCIILowercase() != "set-cookie"_s) { + if (name->length() != "set-cookie"_s.length() || name->convertToASCIILowercase() != "set-cookie"_s) { throwTypeError(lexicalGlobalObject, scope, "Only \"set-cookie\" is supported."_s); } @@ -429,9 +431,11 @@ static inline JSC::EncodedJSValue jsFetchHeadersPrototypeFunction_deleteBody(JSC if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto name = convert(*lexicalGlobalObject, argument0.value()); + auto* nameString = argument0.value().toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.remove(WTFMove(name)); }))); + const auto name = nameString->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.remove(name); }))); } JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_delete, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) @@ -449,9 +453,11 @@ static inline JSC::EncodedJSValue jsFetchHeadersPrototypeFunction_getBody(JSC::J if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto name = convert(*lexicalGlobalObject, argument0.value()); + auto* nameString = argument0.value().toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>(*lexicalGlobalObject, throwScope, impl.get(WTFMove(name))))); + const auto name = nameString->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>(*lexicalGlobalObject, throwScope, impl.get(name)))); } JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_get, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) @@ -469,9 +475,11 @@ static inline JSC::EncodedJSValue jsFetchHeadersPrototypeFunction_hasBody(JSC::J if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto name = convert(*lexicalGlobalObject, argument0.value()); + auto* nameString = argument0.value().toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, impl.has(WTFMove(name))))); + const auto name = nameString->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, impl.has(name)))); } JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_has, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) diff --git a/src/bun.js/bindings/webcore/JSTextEncoder.cpp b/src/bun.js/bindings/webcore/JSTextEncoder.cpp index e8264a7319..e33bf367ed 100644 --- a/src/bun.js/bindings/webcore/JSTextEncoder.cpp +++ b/src/bun.js/bindings/webcore/JSTextEncoder.cpp @@ -19,6 +19,7 @@ */ #include "root.h" +#include "JavaScriptCore/ExceptionScope.h" #include "JSTextEncoder.h" @@ -384,7 +385,7 @@ static inline JSC::EncodedJSValue jsTextEncoderPrototypeFunction_encodeBody(JSC: } JSC::JSString* input = argument0.value().toStringOrNull(lexicalGlobalObject); JSC::EncodedJSValue res; - String str; + StringView str; if (input->is8Bit()) { if (input->isRope()) { GCDeferralContext gcDeferralContext(vm); @@ -392,15 +393,21 @@ static inline JSC::EncodedJSValue jsTextEncoderPrototypeFunction_encodeBody(JSC: if (!JSC::JSValue::decode(encodedValue).isUndefined()) { RELEASE_AND_RETURN(throwScope, encodedValue); } + + RETURN_IF_EXCEPTION(throwScope, {}); } - str = input->value(lexicalGlobalObject); + str = input->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); res = TextEncoder__encode8(lexicalGlobalObject, str.span8().data(), str.length()); } else { - str = input->value(lexicalGlobalObject); + str = input->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); res = TextEncoder__encode16(lexicalGlobalObject, str.span16().data(), str.length()); } + RETURN_IF_EXCEPTION(throwScope, {}); + if (UNLIKELY(JSC::JSValue::decode(res).isObject() && JSC::JSValue::decode(res).getObject()->isErrorInstance())) { throwScope.throwException(lexicalGlobalObject, JSC::JSValue::decode(res)); return {}; diff --git a/src/bun.js/bindings/webcore/JSURLSearchParams.cpp b/src/bun.js/bindings/webcore/JSURLSearchParams.cpp index a938234a4a..674d076eff 100644 --- a/src/bun.js/bindings/webcore/JSURLSearchParams.cpp +++ b/src/bun.js/bindings/webcore/JSURLSearchParams.cpp @@ -305,9 +305,11 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_getBody(JSC if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto name = convert(*lexicalGlobalObject, argument0.value()); + auto* nameString = argument0.value().toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>(*lexicalGlobalObject, throwScope, impl.get(WTFMove(name))))); + const auto name = nameString->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>(*lexicalGlobalObject, throwScope, impl.get(name)))); } JSC_DEFINE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_get, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) @@ -325,9 +327,11 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_getAllBody( if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto name = convert(*lexicalGlobalObject, argument0.value()); + auto* nameString = argument0.value().toString(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, impl.getAll(WTFMove(name))))); + const auto name = nameString->view(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, impl.getAll(name)))); } JSC_DEFINE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_getAll, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) @@ -345,7 +349,9 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_hasBody(JSC if (UNLIKELY(callFrame->argumentCount() < 1)) return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); - auto name = convert(*lexicalGlobalObject, argument0.value()); + auto* nameString = argument0.value().toString(lexicalGlobalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + const auto name = nameString->view(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, {}); String value; @@ -355,7 +361,7 @@ static inline JSC::EncodedJSValue jsURLSearchParamsPrototypeFunction_hasBody(JSC RETURN_IF_EXCEPTION(throwScope, {}); } - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, impl.has(WTFMove(name), WTFMove(value))))); + RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, impl.has(name, WTFMove(value))))); } JSC_DEFINE_HOST_FUNCTION(jsURLSearchParamsPrototypeFunction_has, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) From e3a1d026f97e85125219cb258a15715752a8d9c6 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 31 Dec 2024 17:16:12 -0800 Subject: [PATCH 118/125] Fix crash in bake on load (#16021) --- src/bake/BakeGlobalObject.cpp | 23 ++++++++++++++++++----- src/bake/BakeGlobalObject.h | 13 +++++++++---- src/bun.js/bindings/BunClientData.cpp | 3 ++- src/bun.js/bindings/BunClientData.h | 1 + 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/bake/BakeGlobalObject.cpp b/src/bake/BakeGlobalObject.cpp index 4bd4a4647e..2e3df0c2de 100644 --- a/src/bake/BakeGlobalObject.cpp +++ b/src/bake/BakeGlobalObject.cpp @@ -11,6 +11,7 @@ extern "C" BunString BakeProdResolve(JSC::JSGlobalObject*, BunString a, BunString b); namespace Bake { +using namespace JSC; JSC::JSInternalPromise* bakeModuleLoaderImportModule(JSC::JSGlobalObject* global, @@ -151,13 +152,14 @@ const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { INHERIT_HOOK_METHOD(deriveShadowRealmGlobalObject), INHERIT_HOOK_METHOD(codeForEval), INHERIT_HOOK_METHOD(canCompileStrings), + INHERIT_HOOK_METHOD(trustedScriptStructure), }; GlobalObject* GlobalObject::create(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable) { - GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) - GlobalObject(vm, structure, methodTable); + Bake::GlobalObject* ptr = new (NotNull, JSC::allocateCell(vm)) + Bake::GlobalObject(vm, structure, methodTable); ptr->finishCreation(vm); return ptr; } @@ -168,6 +170,13 @@ void GlobalObject::finishCreation(JSC::VM& vm) ASSERT(inherits(info())); } +JSC::Structure* GlobalObject::createStructure(JSC::VM& vm) +{ + auto* structure = JSC::Structure::create(vm, nullptr, jsNull(), JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags & ~IsImmutablePrototypeExoticObject), info()); + structure->setTransitionWatchpointIsLikelyToBeFired(true); + return structure; +} + struct BunVirtualMachine; extern "C" BunVirtualMachine* Bun__getVM(); @@ -181,9 +190,9 @@ extern "C" GlobalObject* BakeCreateProdGlobal(void* console) BunVirtualMachine* bunVM = Bun__getVM(); WebCore::JSVMClientData::create(&vm, bunVM); - JSC::Structure* structure = GlobalObject::createStructure(vm); - GlobalObject* global = GlobalObject::create( - vm, structure, &GlobalObject::s_globalObjectMethodTable); + JSC::Structure* structure = Bake::GlobalObject::createStructure(vm); + Bake::GlobalObject* global = Bake::GlobalObject::create( + vm, structure, &Bake::GlobalObject::s_globalObjectMethodTable); if (!global) BUN_PANIC("Failed to create BakeGlobalObject"); @@ -193,6 +202,7 @@ extern "C" GlobalObject* BakeCreateProdGlobal(void* console) global->setConsole(console); global->setStackTraceLimit(10); // Node.js defaults to 10 + global->isThreadLocalDefaultGlobalObject = true; // TODO: it segfaults! process.nextTick is scoped out for now i guess! // vm.setOnComputeErrorInfo(computeErrorInfoWrapper); @@ -214,4 +224,7 @@ extern "C" void BakeGlobalObject__attachPerThreadData(GlobalObject* global, Prod global->m_perThreadData = perThreadData; } +const JSC::ClassInfo Bake::GlobalObject::s_info = { "GlobalObject"_s, &Base::s_info, nullptr, nullptr, + CREATE_METHOD_TABLE(Bake::GlobalObject) }; + }; // namespace Bake diff --git a/src/bake/BakeGlobalObject.h b/src/bake/BakeGlobalObject.h index 0ac902422e..a4dcf04a0a 100644 --- a/src/bake/BakeGlobalObject.h +++ b/src/bake/BakeGlobalObject.h @@ -10,7 +10,8 @@ class GlobalObject : public Zig::GlobalObject { public: using Base = Zig::GlobalObject; - ProductionPerThread* m_perThreadData; + ProductionPerThread* m_perThreadData = nullptr; + DECLARE_INFO; template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { @@ -22,16 +23,20 @@ public: [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForBakeGlobalScope = std::forward(space); }, [](auto& spaces) { return spaces.m_subspaceForBakeGlobalScope.get(); }, [](auto& spaces, auto&& space) { spaces.m_subspaceForBakeGlobalScope = std::forward(space); }, - [](auto& server) -> JSC::HeapCellType& { return server.m_heapCellTypeForJSWorkerGlobalScope; }); + [](auto& server) -> JSC::HeapCellType& { return server.m_heapCellTypeForBakeGlobalObject; }); } static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable; static GlobalObject* create(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable); + static JSC::Structure* createStructure(JSC::VM& vm); + void finishCreation(JSC::VM& vm); - GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable) - : Zig::GlobalObject(vm, structure, methodTable) { } + GlobalObject(JSC::VM& vm, JSC::Structure* structure, const JSC::GlobalObjectMethodTable* methodTable) + : Zig::GlobalObject(vm, structure, methodTable) + { + } }; }; // namespace Kit diff --git a/src/bun.js/bindings/BunClientData.cpp b/src/bun.js/bindings/BunClientData.cpp index 37f1e097f2..b5c037f0c2 100644 --- a/src/bun.js/bindings/BunClientData.cpp +++ b/src/bun.js/bindings/BunClientData.cpp @@ -23,7 +23,7 @@ #include "JSDOMWrapper.h" #include #include "NodeVM.h" - +#include "../../bake/BakeGlobalObject.h" namespace WebCore { using namespace JSC; @@ -32,6 +32,7 @@ RefPtr createBuiltinsSourceProvider(); JSHeapData::JSHeapData(Heap& heap) : m_heapCellTypeForJSWorkerGlobalScope(JSC::IsoHeapCellType::Args()) , m_heapCellTypeForNodeVMGlobalObject(JSC::IsoHeapCellType::Args()) + , m_heapCellTypeForBakeGlobalObject(JSC::IsoHeapCellType::Args()) , m_domBuiltinConstructorSpace ISO_SUBSPACE_INIT(heap, heap.cellHeapCellType, JSDOMBuiltinConstructorBase) , m_domConstructorSpace ISO_SUBSPACE_INIT(heap, heap.cellHeapCellType, JSDOMConstructorBase) , m_domNamespaceObjectSpace ISO_SUBSPACE_INIT(heap, heap.cellHeapCellType, JSDOMObject) diff --git a/src/bun.js/bindings/BunClientData.h b/src/bun.js/bindings/BunClientData.h index 92fcad4ad4..ef210b02ad 100644 --- a/src/bun.js/bindings/BunClientData.h +++ b/src/bun.js/bindings/BunClientData.h @@ -59,6 +59,7 @@ public: JSC::IsoHeapCellType m_heapCellTypeForJSWorkerGlobalScope; JSC::IsoHeapCellType m_heapCellTypeForNodeVMGlobalObject; + JSC::IsoHeapCellType m_heapCellTypeForBakeGlobalObject; private: Lock m_lock; From 30008ed0fcee804de1c879f8461e8233ecd88775 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 31 Dec 2024 18:17:56 -0800 Subject: [PATCH 119/125] Bump WebKit again (#16091) --- cmake/tools/SetupWebKit.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/tools/SetupWebKit.cmake b/cmake/tools/SetupWebKit.cmake index 712f41aac8..7ff6ffca0d 100644 --- a/cmake/tools/SetupWebKit.cmake +++ b/cmake/tools/SetupWebKit.cmake @@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use") option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading") if(NOT WEBKIT_VERSION) - set(WEBKIT_VERSION ba17b88ba9a5c1140bf74cf3a1637fbc89a3b9e7) + set(WEBKIT_VERSION 30046aef5ec6590c74c6a696e4f01683f962a6a2) endif() if(WEBKIT_LOCAL) From 19191659cfa9403ce186c2616024cff9fe0a76ba Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 31 Dec 2024 19:48:33 -0800 Subject: [PATCH 120/125] Avoid resolving substrings in bun:sqlite and Buffer.byteLength (#16092) --- bench/snippets/byteLength.mjs | 27 ++++++++++++++++ src/bun.js/api/server.zig | 13 ++++++-- src/bun.js/bindings/BunObject.cpp | 2 +- src/bun.js/bindings/JSBuffer.cpp | 8 ++--- src/bun.js/bindings/bindings.zig | 6 ++++ src/bun.js/bindings/sqlite/JSSQLStatement.cpp | 14 ++++----- src/bun.js/webcore/streams.zig | 31 +++++++++++++------ 7 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 bench/snippets/byteLength.mjs diff --git a/bench/snippets/byteLength.mjs b/bench/snippets/byteLength.mjs new file mode 100644 index 0000000000..810bf487fd --- /dev/null +++ b/bench/snippets/byteLength.mjs @@ -0,0 +1,27 @@ +import { Buffer } from "node:buffer"; +import { bench, run } from "../runner.mjs"; + +const variations = [ + ["latin1", "hello world"], + ["utf16", "hello emoji 🤔"], +]; + +for (const [label, string] of variations) { + const big = Buffer.alloc(1000000, string).toString(); + const small = Buffer.from(string).toString(); + const substring = big.slice(0, big.length - 2); + + bench(`${substring.length}`, () => { + return Buffer.byteLength(substring, "utf8"); + }); + + bench(`${small.length}`, () => { + return Buffer.byteLength(small); + }); + + bench(`${big.length}`, () => { + return Buffer.byteLength(big); + }); +} + +await run(); diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 1335e7b7dc..b540da6317 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -5239,10 +5239,17 @@ pub const ServerWebSocket = struct { return globalThis.throw("sendText expects a string", .{}); } - var string_slice = message_value.toSlice(globalThis, bun.default_allocator); - defer string_slice.deinit(); + var js_string = message_value.toString(globalThis); + if (globalThis.hasException()) { + return .zero; + } + const view = js_string.view(globalThis); + const slice = view.toSlice(bun.default_allocator); + defer slice.deinit(); - const buffer = string_slice.slice(); + defer js_string.ensureStillAlive(); + + const buffer = slice.slice(); switch (this.websocket().send(buffer, .text, compress, true)) { .backpressure => { log("sendText() backpressure ({d} bytes string)", .{buffer.len}); diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index 502e8cf796..5e1062a2bb 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -428,7 +428,7 @@ JSC_DEFINE_HOST_FUNCTION(functionBunEscapeHTML, (JSC::JSGlobalObject * lexicalGl if (string->length() == 0) RELEASE_AND_RETURN(scope, JSValue::encode(string)); - auto resolvedString = string->value(lexicalGlobalObject); + auto resolvedString = string->view(lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, {}); JSC::EncodedJSValue encodedInput = JSValue::encode(string); diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index ef55090712..0476e797bb 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -113,7 +113,7 @@ namespace Bun { // Use a JSString* here to avoid unnecessarily joining the rope string. // If we're only getting the length property, it won't join the rope string. -std::optional byteLength(JSC::JSString* str, WebCore::BufferEncodingType encoding) +std::optional byteLength(JSC::JSString* str, JSC::JSGlobalObject* lexicalGlobalObject, WebCore::BufferEncodingType encoding) { if (str->length() == 0) return 0; @@ -135,7 +135,7 @@ std::optional byteLength(JSC::JSString* str, WebCore::BufferEncodingType case WebCore::BufferEncodingType::base64: case WebCore::BufferEncodingType::base64url: { int64_t length = str->length(); - const auto& view = str->tryGetValue(true); + const auto view = str->view(lexicalGlobalObject); if (UNLIKELY(view->isNull())) { return std::nullopt; } @@ -167,7 +167,7 @@ std::optional byteLength(JSC::JSString* str, WebCore::BufferEncodingType } case WebCore::BufferEncodingType::utf8: { - const auto& view = str->tryGetValue(true); + const auto view = str->view(lexicalGlobalObject); if (UNLIKELY(view->isNull())) { return std::nullopt; } @@ -657,7 +657,7 @@ static inline JSC::EncodedJSValue jsBufferByteLengthFromStringAndEncoding(JSC::J return {}; } - if (auto length = Bun::byteLength(str, encoding)) { + if (auto length = Bun::byteLength(str, lexicalGlobalObject, encoding)) { return JSValue::encode(jsNumber(*length)); } if (!scope.exception()) { diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 226ed64f8f..909e8dc1e2 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -1915,12 +1915,18 @@ pub const JSString = extern struct { return shim.cppFn("toZigString", .{ this, global, zig_str }); } + pub fn ensureStillAlive(this: *JSString) void { + std.mem.doNotOptimizeAway(this); + } + pub fn getZigString(this: *JSString, global: *JSGlobalObject) JSC.ZigString { var out = JSC.ZigString.init(""); this.toZigString(global, &out); return out; } + pub const view = getZigString; + // doesn't always allocate pub fn toSlice( this: *JSString, diff --git a/src/bun.js/bindings/sqlite/JSSQLStatement.cpp b/src/bun.js/bindings/sqlite/JSSQLStatement.cpp index be8ff4b90b..e27d4159fe 100644 --- a/src/bun.js/bindings/sqlite/JSSQLStatement.cpp +++ b/src/bun.js/bindings/sqlite/JSSQLStatement.cpp @@ -785,18 +785,18 @@ static inline bool rebindValue(JSC::JSGlobalObject* lexicalGlobalObject, sqlite3 return false; } - String roped = str->tryGetValue(lexicalGlobalObject); - if (UNLIKELY(!roped)) { + const auto roped = str->view(lexicalGlobalObject); + if (UNLIKELY(roped->isNull())) { throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, "Out of memory :("_s)); return false; } - if (roped.is8Bit() && roped.containsOnlyASCII()) { - CHECK_BIND(sqlite3_bind_text(stmt, i, reinterpret_cast(roped.span8().data()), roped.length(), transientOrStatic)); - } else if (!roped.is8Bit()) { - CHECK_BIND(sqlite3_bind_text16(stmt, i, roped.span16().data(), roped.length() * 2, transientOrStatic)); + if (roped->is8Bit() && roped->containsOnlyASCII()) { + CHECK_BIND(sqlite3_bind_text(stmt, i, reinterpret_cast(roped->span8().data()), roped->length(), transientOrStatic)); + } else if (!roped->is8Bit()) { + CHECK_BIND(sqlite3_bind_text16(stmt, i, roped->span16().data(), roped->length() * 2, transientOrStatic)); } else { - auto utf8 = roped.utf8(); + auto utf8 = roped->utf8(); CHECK_BIND(sqlite3_bind_text(stmt, i, utf8.data(), utf8.length(), SQLITE_TRANSIENT)); } diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index 8c7f348dfb..0d437358ea 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -1790,16 +1790,23 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type { return globalThis.throwValue(JSC.toTypeError(.ERR_INVALID_ARG_TYPE, "write() expects a string, ArrayBufferView, or ArrayBuffer", .{}, globalThis)); } - const str = arg.getZigString(globalThis); - if (str.len == 0) { + const str = arg.toString(globalThis); + if (globalThis.hasException()) { + return .zero; + } + + const view = str.view(globalThis); + + if (view.isEmpty()) { return JSC.JSValue.jsNumber(0); } - if (str.is16Bit()) { - return this.sink.writeUTF16(.{ .temporary = bun.ByteList.initConst(std.mem.sliceAsBytes(str.utf16SliceAligned())) }).toJS(globalThis); + defer str.ensureStillAlive(); + if (view.is16Bit()) { + return this.sink.writeUTF16(.{ .temporary = bun.ByteList.initConst(std.mem.sliceAsBytes(view.utf16SliceAligned())) }).toJS(globalThis); } - return this.sink.writeLatin1(.{ .temporary = bun.ByteList.initConst(str.slice()) }).toJS(globalThis); + return this.sink.writeLatin1(.{ .temporary = bun.ByteList.initConst(view.slice()) }).toJS(globalThis); } pub fn writeUTF8(globalThis: *JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { @@ -1827,16 +1834,22 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type { const arg = args[0]; - const str = arg.getZigString(globalThis); - if (str.len == 0) { + const str = arg.toString(globalThis); + if (globalThis.hasException()) { + return .zero; + } + + const view = str.view(globalThis); + if (view.isEmpty()) { return JSC.JSValue.jsNumber(0); } + defer str.ensureStillAlive(); if (str.is16Bit()) { - return this.sink.writeUTF16(.{ .temporary = str.utf16SliceAligned() }).toJS(globalThis); + return this.sink.writeUTF16(.{ .temporary = view.utf16SliceAligned() }).toJS(globalThis); } - return this.sink.writeLatin1(.{ .temporary = str.slice() }).toJS(globalThis); + return this.sink.writeLatin1(.{ .temporary = view.slice() }).toJS(globalThis); } pub fn close(globalThis: *JSGlobalObject, sink_ptr: ?*anyopaque) callconv(.C) JSValue { From be959e111ab6842026a54328e5c06747a8e47f6f Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 31 Dec 2024 21:08:07 -0800 Subject: [PATCH 121/125] Do not assert valid windows path in chdirOSPath because the `SetCurrentDirectoryW` function will validate the path --- src/sys.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sys.zig b/src/sys.zig index 33e98c14de..2327c3bc7e 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -506,8 +506,6 @@ pub fn chmod(path: [:0]const u8, mode: bun.Mode) Maybe(void) { } pub fn chdirOSPath(destination: bun.OSPathSliceZ) Maybe(void) { - assertIsValidWindowsPath(bun.OSPathChar, destination); - if (comptime Environment.isPosix) { const rc = syscall.chdir(destination); return Maybe(void).errnoSys(rc, .chdir) orelse Maybe(void).success; From aa1b0c9c40efc6b095a67505535a229b7647de28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Bergstr=C3=B6m?= Date: Wed, 1 Jan 2025 18:56:10 +0000 Subject: [PATCH 122/125] fix: avoid world-writable permissions for lockfiles (#16018) --- src/install/lockfile.zig | 8 +++-- test/cli/install/bun-lock.test.ts | 51 ++++++++++++++++++++++++++++++ test/cli/install/bun-lockb.test.ts | 16 ++++++++-- 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 test/cli/install/bun-lock.test.ts diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 26528cc984..e0a0f54a4a 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -2423,8 +2423,12 @@ pub fn saveToDisk(this: *Lockfile, save_format: LoadResult.LockfileFormat, verbo } if (comptime Environment.isPosix) { - // chmod 777 on posix - switch (bun.sys.fchmod(file.handle, 0o777)) { + // chmod 755 for binary, 644 for plaintext + var filemode: bun.Mode = 0o755; + if (save_format == .text) { + filemode = 0o644; + } + switch (bun.sys.fchmod(file.handle, filemode)) { .err => |err| { file.close(); _ = bun.sys.unlink(tmpname); diff --git a/test/cli/install/bun-lock.test.ts b/test/cli/install/bun-lock.test.ts new file mode 100644 index 0000000000..d5d6ce6c3c --- /dev/null +++ b/test/cli/install/bun-lock.test.ts @@ -0,0 +1,51 @@ +import { spawn } from "bun"; +import { expect, it } from "bun:test"; +import { access, copyFile, open, writeFile } from "fs/promises"; +import { bunExe, bunEnv as env, isWindows, tmpdirSync } from "harness"; +import { join } from "path"; + +it("should write plaintext lockfiles", async () => { + const package_dir = tmpdirSync(); + + // copy bar-0.0.2.tgz to package_dir + await copyFile(join(__dirname, "bar-0.0.2.tgz"), join(package_dir, "bar-0.0.2.tgz")); + + // Create a simple package.json + await writeFile( + join(package_dir, "package.json"), + JSON.stringify({ + name: "test-package", + version: "1.0.0", + dependencies: { + "dummy-package": "file:./bar-0.0.2.tgz", + }, + }), + ); + + // Run 'bun install' to generate the lockfile + const installResult = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile"], + cwd: package_dir, + env, + }); + await installResult.exited; + + // Ensure the lockfile was created + await access(join(package_dir, "bun.lock")); + + // Assert that the lockfile has the correct permissions + const file = await open(join(package_dir, "bun.lock"), "r"); + const stat = await file.stat(); + + // in unix, 0o644 == 33188 + let mode = 33188; + // ..but windows is different + if (isWindows) { + mode = 33206; + } + expect(stat.mode).toBe(mode); + + expect(await file.readFile({ encoding: "utf8" })).toEqual( + `{\n \"lockfileVersion\": 0,\n \"workspaces\": {\n \"\": {\n \"dependencies\": {\n \"dummy-package\": \"file:./bar-0.0.2.tgz\",\n },\n },\n },\n \"packages\": {\n \"dummy-package\": [\"bar@./bar-0.0.2.tgz\", {}],\n }\n}\n`, + ); +}); diff --git a/test/cli/install/bun-lockb.test.ts b/test/cli/install/bun-lockb.test.ts index b97bc1759a..cf0ab704ef 100644 --- a/test/cli/install/bun-lockb.test.ts +++ b/test/cli/install/bun-lockb.test.ts @@ -1,7 +1,7 @@ import { spawn } from "bun"; import { expect, it } from "bun:test"; -import { access, copyFile, writeFile } from "fs/promises"; -import { bunExe, bunEnv as env, tmpdirSync } from "harness"; +import { access, copyFile, open, writeFile } from "fs/promises"; +import { bunExe, bunEnv as env, isWindows, tmpdirSync } from "harness"; import { join } from "path"; it("should not print anything to stderr when running bun.lockb", async () => { @@ -33,6 +33,18 @@ it("should not print anything to stderr when running bun.lockb", async () => { // Ensure the lockfile was created await access(join(package_dir, "bun.lockb")); + // Assert that the lockfile has the correct permissions + const file = await open(join(package_dir, "bun.lockb"), "r"); + const stat = await file.stat(); + + // in unix, 0o755 == 33261 + let mode = 33261; + // ..but windows is different + if(isWindows) { + mode = 33206; + } + expect(stat.mode).toBe(mode); + // create a .env await writeFile(join(package_dir, ".env"), "FOO=bar"); From 7a52ec55a524203ce71722d73fac1d040142b7ff Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Wed, 1 Jan 2025 19:06:08 -0800 Subject: [PATCH 123/125] fix(server) HEAD requests (#16099) --- src/bun.js/api/server.zig | 218 +++++++++++++++++++++----- test/js/bun/http/bun-server.test.ts | 227 +++++++++++++++++++++++++++- 2 files changed, 403 insertions(+), 42 deletions(-) diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index b540da6317..52366fefb2 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -90,6 +90,7 @@ const linux = std.os.linux; const Async = bun.Async; const httplog = Output.scoped(.Server, false); const ctxLog = Output.scoped(.RequestContext, false); +const AWS = @import("../../s3.zig").AWSCredentials; const BlobFileContentResult = struct { data: [:0]const u8, @@ -2029,6 +2030,14 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp ctx.flags.response_protected = true; JSC.C.JSValueProtect(ctx.server.?.globalThis, value.asObjectRef()); + if (ctx.method == .HEAD) { + if (ctx.resp) |resp| { + var pair = HeaderResponsePair{ .this = ctx, .response = response }; + resp.runCorkedWithType(*HeaderResponsePair, doRenderHeadResponse, &pair); + } + return; + } + ctx.render(response); } @@ -2354,7 +2363,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } if (this.method == .HEAD) { - this.end("", this.shouldCloseConnection()); + this.endWithoutBody(this.shouldCloseConnection()); return false; } @@ -3162,6 +3171,105 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp // resp == null or aborted or server.stop(true) return this.resp == null or this.flags.aborted or this.server == null or this.server.?.flags.terminated; } + const HeaderResponseSizePair = struct { this: *RequestContext, size: usize }; + pub fn doRenderHeadResponseAfterS3SizeResolved(pair: *HeaderResponseSizePair) void { + var this = pair.this; + + if (this.resp) |resp| { + resp.writeHeaderInt("content-length", pair.size); + } + this.renderMetadata(); + this.endWithoutBody(this.shouldCloseConnection()); + this.deref(); + } + pub fn onS3SizeResolved(result: AWS.S3StatResult, this: *RequestContext) void { + defer { + this.deref(); + } + if (this.resp) |resp| { + var pair = HeaderResponseSizePair{ .this = this, .size = switch (result) { + .failure, .not_found => 0, + .success => |stat| stat.size, + } }; + resp.runCorkedWithType(*HeaderResponseSizePair, doRenderHeadResponseAfterS3SizeResolved, &pair); + } + } + const HeaderResponsePair = struct { this: *RequestContext, response: *JSC.WebCore.Response }; + + fn doRenderHeadResponse(pair: *HeaderResponsePair) void { + var this = pair.this; + var response = pair.response; + this.flags.needs_content_length = false; + if (this.resp == null) { + return; + } + const resp = this.resp.?; + this.response_ptr = response; + const server = this.server orelse { + // server detached? + resp.writeHeaderInt("content-length", 0); + this.renderMetadata(); + this.endWithoutBody(this.shouldCloseConnection()); + return; + }; + const globalThis = server.globalThis; + if (response.getFetchHeaders()) |headers| { + // first respect the headers + if (headers.get("transfer-encoding", globalThis)) |transfer_encoding| { + resp.writeHeader("transfer-encoding", transfer_encoding); + } else if (headers.get("content-length", globalThis)) |content_length| { + const len = std.fmt.parseInt(usize, content_length, 10) catch 0; + resp.writeHeaderInt("content-length", len); + } else { + resp.writeHeaderInt("content-length", 0); + } + } else { + // then respect the body + response.body.value.toBlobIfPossible(); + switch (response.body.value) { + .InternalBlob, .WTFStringImpl => { + var blob = response.body.value.useAsAnyBlobAllowNonUTF8String(); + defer blob.detach(); + const size = blob.size(); + if (size == Blob.max_size) { + resp.writeHeaderInt("content-length", 0); + } else { + resp.writeHeaderInt("content-length", size); + } + }, + + .Blob => |*blob| { + if (blob.isS3()) { + // we need to read the size asynchronously + // in this case should always be a redirect so should not hit this path, but in case we change it in the future lets handle it + this.ref(); + + const credentials = blob.store.?.data.s3.getCredentials(); + const path = blob.store.?.data.s3.path(); + const env = globalThis.bunVM().transpiler.env; + + credentials.s3Stat(path, @ptrCast(&onS3SizeResolved), this, if (env.getHttpProxy(true, null)) |proxy| proxy.href else null); + + return; + } + blob.resolveSize(); + if (blob.size == Blob.max_size) { + resp.writeHeaderInt("content-length", 0); + } else { + resp.writeHeaderInt("content-length", blob.size); + } + }, + .Locked => { + resp.writeHeader("transfer-encoding", "chunked"); + }, + .Used, .Null, .Empty, .Error => { + resp.writeHeaderInt("content-length", 0); + }, + } + } + this.renderMetadata(); + this.endWithoutBody(this.shouldCloseConnection()); + } // Each HTTP request or TCP socket connection is effectively a "task". // @@ -3208,23 +3316,30 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp ctx.response_jsvalue = response_value; ctx.response_jsvalue.ensureStillAlive(); ctx.flags.response_protected = false; + if (ctx.method == .HEAD) { + if (ctx.resp) |resp| { + var pair = HeaderResponsePair{ .this = ctx, .response = response }; + resp.runCorkedWithType(*HeaderResponsePair, doRenderHeadResponse, &pair); + } + return; + } else { + response.body.value.toBlobIfPossible(); - response.body.value.toBlobIfPossible(); - - switch (response.body.value) { - .Blob => |*blob| { - if (blob.needsToReadFile()) { + switch (response.body.value) { + .Blob => |*blob| { + if (blob.needsToReadFile()) { + response_value.protect(); + ctx.flags.response_protected = true; + } + }, + .Locked => { response_value.protect(); ctx.flags.response_protected = true; - } - }, - .Locked => { - response_value.protect(); - ctx.flags.response_protected = true; - }, - else => {}, + }, + else => {}, + } + ctx.render(response); } - ctx.render(response); return; } @@ -3260,7 +3375,13 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp ctx.response_jsvalue.ensureStillAlive(); ctx.flags.response_protected = false; ctx.response_ptr = response; - + if (ctx.method == .HEAD) { + if (ctx.resp) |resp| { + var pair = HeaderResponsePair{ .this = ctx, .response = response }; + resp.runCorkedWithType(*HeaderResponsePair, doRenderHeadResponse, &pair); + } + return; + } response.body.value.toBlobIfPossible(); switch (response.body.value) { .Blob => |*blob| { @@ -3467,17 +3588,17 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp // If we've received the complete body by the time this function is called // we can avoid streaming it and just send it all at once. if (byte_stream.has_received_last_chunk) { - this.blob.from(byte_stream.buffer); + this.blob.from(byte_stream.drain().listManaged(bun.default_allocator)); this.readable_stream_ref.deinit(); this.doRenderBlob(); return; } - + this.ref(); byte_stream.pipe = JSC.WebCore.Pipe.New(@This(), onPipe).init(this); this.readable_stream_ref = JSC.WebCore.ReadableStream.Strong.init(stream, globalThis); this.byte_stream = byte_stream; - this.response_buf_owned = byte_stream.buffer.moveToUnmanaged(); + this.response_buf_owned = byte_stream.drain().list(); // we don't set size here because even if we have a hint // uWebSockets won't let us partially write streaming content @@ -3517,10 +3638,11 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp pub fn onPipe(this: *RequestContext, stream: JSC.WebCore.StreamResult, allocator: std.mem.Allocator) void { const stream_needs_deinit = stream == .owned or stream == .owned_and_done; - + const is_done = stream.isDone(); defer { + if (is_done) this.deref(); if (stream_needs_deinit) { - if (stream.isDone()) { + if (is_done) { stream.owned_and_done.listManaged(allocator).deinit(); } else { stream.owned.listManaged(allocator).deinit(); @@ -3539,12 +3661,12 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp // uSockets will append and manage the buffer // so any write will buffer if the write fails if (resp.write(chunk)) { - if (stream.isDone()) { + if (is_done) { this.endStream(this.shouldCloseConnection()); } } else { // when it's the last one, we just want to know if it's done - if (stream.isDone()) { + if (is_done) { this.flags.has_marked_pending = true; resp.onWritable(*RequestContext, onWritableResponseBuffer, this); } @@ -4877,10 +4999,17 @@ pub const ServerWebSocket = struct { } { - var string_slice = message_value.toSlice(globalThis, bun.default_allocator); - defer string_slice.deinit(); + var js_string = message_value.toString(globalThis); + if (globalThis.hasException()) { + return .zero; + } + const view = js_string.view(globalThis); + const slice = view.toSlice(bun.default_allocator); + defer slice.deinit(); - const buffer = string_slice.slice(); + defer js_string.ensureStillAlive(); + + const buffer = slice.slice(); const result = if (!publish_to_self and !this.isClosed()) this.websocket().publish(topic_slice.slice(), buffer, .text, compress) @@ -4939,10 +5068,17 @@ pub const ServerWebSocket = struct { return globalThis.throw("publishText requires a non-empty message", .{}); } - var string_slice = message_value.toSlice(globalThis, bun.default_allocator); - defer string_slice.deinit(); + var js_string = message_value.toString(globalThis); + if (globalThis.hasException()) { + return .zero; + } + const view = js_string.view(globalThis); + const slice = view.toSlice(bun.default_allocator); + defer slice.deinit(); - const buffer = string_slice.slice(); + defer js_string.ensureStillAlive(); + + const buffer = slice.slice(); const result = if (!publish_to_self and !this.isClosed()) this.websocket().publish(topic_slice.slice(), buffer, .text, compress) @@ -5186,10 +5322,17 @@ pub const ServerWebSocket = struct { } { - var string_slice = message_value.toSlice(globalThis, bun.default_allocator); - defer string_slice.deinit(); + var js_string = message_value.toString(globalThis); + if (globalThis.hasException()) { + return .zero; + } + const view = js_string.view(globalThis); + const slice = view.toSlice(bun.default_allocator); + defer slice.deinit(); - const buffer = string_slice.slice(); + defer js_string.ensureStillAlive(); + + const buffer = slice.slice(); switch (this.websocket().send(buffer, .text, compress, true)) { .backpressure => { log("send() backpressure ({d} bytes string)", .{buffer.len}); @@ -5870,10 +6013,17 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp } { - var string_slice = message_value.toSlice(globalThis, bun.default_allocator); - defer string_slice.deinit(); + var js_string = message_value.toString(globalThis); + if (globalThis.hasException()) { + return .zero; + } + const view = js_string.view(globalThis); + const slice = view.toSlice(bun.default_allocator); + defer slice.deinit(); - const buffer = string_slice.slice(); + defer js_string.ensureStillAlive(); + + const buffer = slice.slice(); return JSValue.jsNumber( // if 0, return 0 // else return number of bytes sent diff --git a/test/js/bun/http/bun-server.test.ts b/test/js/bun/http/bun-server.test.ts index de430f36e3..771debc7f1 100644 --- a/test/js/bun/http/bun-server.test.ts +++ b/test/js/bun/http/bun-server.test.ts @@ -1,6 +1,6 @@ import type { Server, ServerWebSocket, Socket } from "bun"; import { describe, expect, test } from "bun:test"; -import { bunEnv, bunExe, rejectUnauthorizedScope } from "harness"; +import { bunEnv, bunExe, rejectUnauthorizedScope, tempDirWithFiles } from "harness"; import path from "path"; describe("Server", () => { @@ -317,8 +317,7 @@ describe("Server", () => { } }); - - test('server should return a body for a OPTIONS Request', async () => { + test("server should return a body for a OPTIONS Request", async () => { using server = Bun.serve({ port: 0, fetch(req) { @@ -327,16 +326,17 @@ describe("Server", () => { }); { const url = `http://${server.hostname}:${server.port}/`; - const response = await fetch(new Request(url, { - method: 'OPTIONS', - })); + const response = await fetch( + new Request(url, { + method: "OPTIONS", + }), + ); expect(await response.text()).toBe("Hello World!"); expect(response.status).toBe(200); expect(response.url).toBe(url); } }); - test("abort signal on server with stream", async () => { { let signalOnServer = false; @@ -456,7 +456,7 @@ describe("Server", () => { env: bunEnv, stderr: "pipe", }); - expect(stderr.toString('utf-8')).toBeEmpty(); + expect(stderr.toString("utf-8")).toBeEmpty(); expect(exitCode).toBe(0); }); }); @@ -768,3 +768,214 @@ test.skip("should be able to stream huge amounts of data", async () => { expect(written).toBe(CONTENT_LENGTH); expect(received).toBe(CONTENT_LENGTH); }, 30_000); + +describe("HEAD requests #15355", () => { + test("should be able to make HEAD requests with content-length or transfer-encoding (async)", async () => { + using server = Bun.serve({ + port: 0, + async fetch(req) { + await Bun.sleep(1); + if (req.method === "HEAD") { + if (req.url.endsWith("/content-length")) { + return new Response(null, { + headers: { + "Content-Length": "11", + }, + }); + } + return new Response(null, { + headers: { + "Transfer-Encoding": "chunked", + }, + }); + } + if (req.url.endsWith("/content-length")) { + return new Response("Hello World"); + } + return new Response(async function* () { + yield "Hello"; + await Bun.sleep(1); + yield " "; + await Bun.sleep(1); + yield "World"; + }); + }, + }); + + { + const response = await fetch(server.url + "/content-length"); + expect(response.status).toBe(200); + expect(response.headers.get("content-length")).toBe("11"); + expect(await response.text()).toBe("Hello World"); + } + { + const response = await fetch(server.url + "/chunked"); + expect(response.status).toBe(200); + expect(response.headers.get("transfer-encoding")).toBe("chunked"); + expect(await response.text()).toBe("Hello World"); + } + + { + const response = await fetch(server.url + "/content-length", { + method: "HEAD", + }); + expect(response.status).toBe(200); + expect(response.headers.get("content-length")).toBe("11"); + expect(await response.text()).toBe(""); + } + { + const response = await fetch(server.url + "/chunked", { + method: "HEAD", + }); + expect(response.status).toBe(200); + expect(response.headers.get("transfer-encoding")).toBe("chunked"); + expect(await response.text()).toBe(""); + } + }); + + test("should be able to make HEAD requests with content-length or transfer-encoding (sync)", async () => { + using server = Bun.serve({ + port: 0, + fetch(req) { + if (req.method === "HEAD") { + if (req.url.endsWith("/content-length")) { + return new Response(null, { + headers: { + "Content-Length": "11", + }, + }); + } + return new Response(null, { + headers: { + "Transfer-Encoding": "chunked", + }, + }); + } + if (req.url.endsWith("/content-length")) { + return new Response("Hello World"); + } + return new Response(async function* () { + yield "Hello"; + await Bun.sleep(1); + yield " "; + await Bun.sleep(1); + yield "World"; + }); + }, + }); + + { + const response = await fetch(server.url + "/content-length"); + expect(response.status).toBe(200); + expect(response.headers.get("content-length")).toBe("11"); + expect(await response.text()).toBe("Hello World"); + } + { + const response = await fetch(server.url + "/chunked"); + expect(response.status).toBe(200); + expect(response.headers.get("transfer-encoding")).toBe("chunked"); + expect(await response.text()).toBe("Hello World"); + } + + { + const response = await fetch(server.url + "/content-length", { + method: "HEAD", + }); + expect(response.status).toBe(200); + expect(response.headers.get("content-length")).toBe("11"); + expect(await response.text()).toBe(""); + } + { + const response = await fetch(server.url + "/chunked", { + method: "HEAD", + }); + expect(response.status).toBe(200); + expect(response.headers.get("transfer-encoding")).toBe("chunked"); + expect(await response.text()).toBe(""); + } + }); + + test("HEAD requests should not have body", async () => { + const dir = tempDirWithFiles("fsr", { + "hello": "Hello World", + }); + + const filename = path.join(dir, "hello"); + using server = Bun.serve({ + port: 0, + fetch(req) { + if (req.url.endsWith("/file")) { + return new Response(Bun.file(filename)); + } + return new Response("Hello World"); + }, + }); + + { + const response = await fetch(server.url); + expect(response.status).toBe(200); + expect(response.headers.get("content-length")).toBe("11"); + expect(await response.text()).toBe("Hello World"); + } + { + const response = await fetch(server.url + "/file"); + expect(response.status).toBe(200); + expect(response.headers.get("content-length")).toBe("11"); + expect(await response.text()).toBe("Hello World"); + } + + function doHead(server: Server, path: string): Promise<{ headers: string; body: string }> { + const { promise, resolve } = Promise.withResolvers(); + // use node net to make a HEAD request + const net = require("net"); + const url = new URL(server.url); + const socket = net.createConnection(url.port, url.hostname); + socket.write(`HEAD ${path} HTTP/1.1\r\nHost: ${url.hostname}:${url.port}\r\n\r\n`); + let body = ""; + let headers = ""; + socket.on("data", data => { + body += data.toString(); + if (!headers) { + const headerIndex = body.indexOf("\r\n\r\n"); + if (headerIndex !== -1) { + headers = body.slice(0, headerIndex); + body = body.slice(headerIndex + 4); + + setTimeout(() => { + // wait to see if we get extra data + resolve({ headers, body }); + socket.destroy(); + }, 100); + } + } + }); + return promise as Promise<{ headers: string; body: string }>; + } + { + const response = await fetch(server.url, { + method: "HEAD", + }); + expect(response.status).toBe(200); + expect(response.headers.get("content-length")).toBe("11"); + expect(await response.text()).toBe(""); + } + { + const response = await fetch(server.url + "/file", { + method: "HEAD", + }); + expect(response.status).toBe(200); + expect(response.headers.get("content-length")).toBe("11"); + expect(await response.text()).toBe(""); + } + { + const { headers, body } = await doHead(server, "/"); + expect(headers.toLowerCase()).toContain("content-length: 11"); + expect(body).toBe(""); + } + { + const { headers, body } = await doHead(server, "/file"); + expect(headers.toLowerCase()).toContain("content-length: 11"); + expect(body).toBe(""); + } + }); +}); From ee955591e2b1f29c685c2f112a3eb895906cb934 Mon Sep 17 00:00:00 2001 From: KOMIYA Atsushi <344568+komiya-atsushi@users.noreply.github.com> Date: Thu, 2 Jan 2025 12:07:18 +0900 Subject: [PATCH 124/125] Update `defines` to `define` in `cc` function documentation (#16097) --- docs/api/cc.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/cc.md b/docs/api/cc.md index 212b928df5..0cdf0b0a75 100644 --- a/docs/api/cc.md +++ b/docs/api/cc.md @@ -179,16 +179,16 @@ type Flags = string | string[]; These are flags like `-I` for include directories and `-D` for preprocessor definitions. -#### `defines: Record` +#### `define: Record` -The `defines` is an optional object that should be passed to the TinyCC compiler. +The `define` is an optional object that should be passed to the TinyCC compiler. ```ts type Defines = Record; cc({ source: "hello.c", - defines: { + define: { "NDEBUG": "1", }, }); From a8b3f732c52f1cb7832e33b16d66afbac545ceed Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 1 Jan 2025 19:23:13 -0800 Subject: [PATCH 125/125] Report memory size of performance.measure / performance.mark (#16094) --- .../bindings/JSDOMExceptionHandling.cpp | 1 + src/bun.js/bindings/webcore/JSPerformance.cpp | 6 +++++ src/bun.js/bindings/webcore/JSPerformance.h | 1 + src/bun.js/bindings/webcore/Performance.cpp | 10 +++++++ src/bun.js/bindings/webcore/Performance.h | 2 ++ .../bindings/webcore/PerformanceEntry.cpp | 26 +++++++++++++++++++ .../bindings/webcore/PerformanceEntry.h | 2 ++ .../bindings/webcore/PerformanceMark.cpp | 9 +++++++ src/bun.js/bindings/webcore/PerformanceMark.h | 2 ++ .../bindings/webcore/PerformanceMeasure.cpp | 9 +++++++ .../bindings/webcore/PerformanceMeasure.h | 2 ++ .../webcore/PerformanceResourceTiming.cpp | 7 +++++ .../webcore/PerformanceResourceTiming.h | 2 ++ .../webcore/PerformanceUserTiming.cpp | 23 ++++++++++++++++ .../bindings/webcore/PerformanceUserTiming.h | 2 ++ .../js/web/timers/performance-entries.test.ts | 17 ++++++++++++ 16 files changed, 121 insertions(+) create mode 100644 test/js/web/timers/performance-entries.test.ts diff --git a/src/bun.js/bindings/JSDOMExceptionHandling.cpp b/src/bun.js/bindings/JSDOMExceptionHandling.cpp index 9531f9594c..ff9552fe7b 100644 --- a/src/bun.js/bindings/JSDOMExceptionHandling.cpp +++ b/src/bun.js/bindings/JSDOMExceptionHandling.cpp @@ -164,6 +164,7 @@ JSValue createDOMException(JSGlobalObject* lexicalGlobalObject, ExceptionCode ec return createRangeError(lexicalGlobalObject, "Bad value"_s); return createRangeError(lexicalGlobalObject, message); + case ExceptionCode::SyntaxError: case ExceptionCode::JSSyntaxError: if (message.isEmpty()) return createSyntaxError(lexicalGlobalObject); diff --git a/src/bun.js/bindings/webcore/JSPerformance.cpp b/src/bun.js/bindings/webcore/JSPerformance.cpp index c9ae3699f2..8d10c604e3 100644 --- a/src/bun.js/bindings/webcore/JSPerformance.cpp +++ b/src/bun.js/bindings/webcore/JSPerformance.cpp @@ -255,6 +255,12 @@ JSPerformance::JSPerformance(Structure* structure, JSDOMGlobalObject& globalObje { } +size_t JSPerformance::estimatedSize(JSCell* cell, VM& vm) +{ + JSPerformance* thisObject = jsCast(cell); + return Base::estimatedSize(cell, vm) + thisObject->wrapped().memoryCost(); +} + // static_assert(!std::is_base_of::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject."); void JSPerformance::finishCreation(VM& vm) diff --git a/src/bun.js/bindings/webcore/JSPerformance.h b/src/bun.js/bindings/webcore/JSPerformance.h index 1f50fc5431..9aa6f243e9 100644 --- a/src/bun.js/bindings/webcore/JSPerformance.h +++ b/src/bun.js/bindings/webcore/JSPerformance.h @@ -60,6 +60,7 @@ public: } static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm); Performance& wrapped() const { return static_cast(Base::wrapped()); diff --git a/src/bun.js/bindings/webcore/Performance.cpp b/src/bun.js/bindings/webcore/Performance.cpp index 55abe5bbe4..46478e1a85 100644 --- a/src/bun.js/bindings/webcore/Performance.cpp +++ b/src/bun.js/bindings/webcore/Performance.cpp @@ -189,6 +189,16 @@ Vector> Performance::getEntriesByType(const String& ent return entries; } +size_t Performance::memoryCost() const +{ + size_t size = sizeof(Performance); + size += m_resourceTimingBuffer.size() * sizeof(PerformanceResourceTiming); + if (m_userTiming) { + size += m_userTiming->memoryCost(); + } + return size; +} + Vector> Performance::getEntriesByName(const String& name, const String& entryType) const { Vector> entries; diff --git a/src/bun.js/bindings/webcore/Performance.h b/src/bun.js/bindings/webcore/Performance.h index b6dc421c66..49c9bb07f1 100644 --- a/src/bun.js/bindings/webcore/Performance.h +++ b/src/bun.js/bindings/webcore/Performance.h @@ -111,6 +111,8 @@ public: // void reportFirstContentfulPaint(); + size_t memoryCost() const; + void removeAllObservers(); void registerPerformanceObserver(PerformanceObserver&); void unregisterPerformanceObserver(PerformanceObserver&); diff --git a/src/bun.js/bindings/webcore/PerformanceEntry.cpp b/src/bun.js/bindings/webcore/PerformanceEntry.cpp index 0a7dad5d82..0db197b54f 100644 --- a/src/bun.js/bindings/webcore/PerformanceEntry.cpp +++ b/src/bun.js/bindings/webcore/PerformanceEntry.cpp @@ -31,6 +31,10 @@ #include "config.h" #include "PerformanceEntry.h" +#include "PerformanceMark.h" +#include "PerformanceMeasure.h" +#include "PerformanceResourceTiming.h" + // #include "DeprecatedGlobalSettings.h" namespace WebCore { @@ -46,6 +50,28 @@ PerformanceEntry::PerformanceEntry(const String& name, double startTime, double PerformanceEntry::~PerformanceEntry() = default; +size_t PerformanceEntry::memoryCost() const +{ + size_t baseCost = this->m_name.sizeInBytes(); + switch (performanceEntryType()) { + case Type::Mark: { + const PerformanceMark* mark = static_cast(this); + return mark->memoryCost() + baseCost; + } + case Type::Measure: { + const PerformanceMeasure* measure = static_cast(this); + return measure->memoryCost() + baseCost; + } + case Type::Resource: { + const PerformanceResourceTiming* resource = static_cast(this); + return resource->memoryCost() + baseCost; + } + default: { + return sizeof(PerformanceEntry) + baseCost; + } + } +} + std::optional PerformanceEntry::parseEntryTypeString(const String& entryType) { if (entryType == "navigation"_s) diff --git a/src/bun.js/bindings/webcore/PerformanceEntry.h b/src/bun.js/bindings/webcore/PerformanceEntry.h index f019ce417c..1fb135c68f 100644 --- a/src/bun.js/bindings/webcore/PerformanceEntry.h +++ b/src/bun.js/bindings/webcore/PerformanceEntry.h @@ -59,6 +59,8 @@ public: virtual Type performanceEntryType() const = 0; virtual ASCIILiteral entryType() const = 0; + size_t memoryCost() const; + static std::optional parseEntryTypeString(const String& entryType); static bool startTimeCompareLessThan(const RefPtr& a, const RefPtr& b) diff --git a/src/bun.js/bindings/webcore/PerformanceMark.cpp b/src/bun.js/bindings/webcore/PerformanceMark.cpp index 6e4601f6db..c61bd847a6 100644 --- a/src/bun.js/bindings/webcore/PerformanceMark.cpp +++ b/src/bun.js/bindings/webcore/PerformanceMark.cpp @@ -85,6 +85,15 @@ PerformanceMark::PerformanceMark(const String& name, double startTime, RefPtrmemoryCost(); + } + return size; +} + JSC::JSValue PerformanceMark::detail(JSC::JSGlobalObject& globalObject) { if (!m_serializedDetail) { diff --git a/src/bun.js/bindings/webcore/PerformanceMark.h b/src/bun.js/bindings/webcore/PerformanceMark.h index 0ba2ee5d12..034551c247 100644 --- a/src/bun.js/bindings/webcore/PerformanceMark.h +++ b/src/bun.js/bindings/webcore/PerformanceMark.h @@ -44,6 +44,8 @@ public: JSC::JSValue detail(JSC::JSGlobalObject&); + size_t memoryCost() const; + private: PerformanceMark(const String& name, double startTime, RefPtr&&); ~PerformanceMark(); diff --git a/src/bun.js/bindings/webcore/PerformanceMeasure.cpp b/src/bun.js/bindings/webcore/PerformanceMeasure.cpp index 5c24b08dea..358257de43 100644 --- a/src/bun.js/bindings/webcore/PerformanceMeasure.cpp +++ b/src/bun.js/bindings/webcore/PerformanceMeasure.cpp @@ -30,6 +30,15 @@ namespace WebCore { +size_t PerformanceMeasure::memoryCost() const +{ + size_t size = sizeof(PerformanceMeasure); + if (m_serializedDetail) { + size += m_serializedDetail->memoryCost(); + } + return size; +} + ExceptionOr> PerformanceMeasure::create(const String& name, double startTime, double endTime, RefPtr&& serializedDetail) { return adoptRef(*new PerformanceMeasure(name, startTime, endTime, WTFMove(serializedDetail))); diff --git a/src/bun.js/bindings/webcore/PerformanceMeasure.h b/src/bun.js/bindings/webcore/PerformanceMeasure.h index 369f5ca69f..4e9d7897fa 100644 --- a/src/bun.js/bindings/webcore/PerformanceMeasure.h +++ b/src/bun.js/bindings/webcore/PerformanceMeasure.h @@ -44,6 +44,8 @@ public: JSC::JSValue detail(JSC::JSGlobalObject&); + size_t memoryCost() const; + private: PerformanceMeasure(const String& name, double startTime, double endTime, RefPtr&& detail); ~PerformanceMeasure(); diff --git a/src/bun.js/bindings/webcore/PerformanceResourceTiming.cpp b/src/bun.js/bindings/webcore/PerformanceResourceTiming.cpp index 57b9e1a500..ecbe7b114b 100644 --- a/src/bun.js/bindings/webcore/PerformanceResourceTiming.cpp +++ b/src/bun.js/bindings/webcore/PerformanceResourceTiming.cpp @@ -62,6 +62,13 @@ static double fetchStart(MonotonicTime timeOrigin, const ResourceTiming& resourc return networkLoadTimeToDOMHighResTimeStamp(timeOrigin, startTime); } +size_t PerformanceResourceTiming::memoryCost() const +{ + size_t size = sizeof(PerformanceResourceTiming); + size += m_serverTiming.size() * sizeof(PerformanceServerTiming); + return size; +} + static double entryStartTime(MonotonicTime timeOrigin, const ResourceTiming& resourceTiming) { if (resourceTiming.networkLoadMetrics().failsTAOCheck diff --git a/src/bun.js/bindings/webcore/PerformanceResourceTiming.h b/src/bun.js/bindings/webcore/PerformanceResourceTiming.h index cb79a86633..fdaef3675d 100644 --- a/src/bun.js/bindings/webcore/PerformanceResourceTiming.h +++ b/src/bun.js/bindings/webcore/PerformanceResourceTiming.h @@ -65,6 +65,8 @@ public: uint64_t encodedBodySize() const; uint64_t decodedBodySize() const; + size_t memoryCost() const; + const Vector>& serverTiming() const { return m_serverTiming; } Type performanceEntryType() const override { return Type::Resource; } diff --git a/src/bun.js/bindings/webcore/PerformanceUserTiming.cpp b/src/bun.js/bindings/webcore/PerformanceUserTiming.cpp index 81061abfb2..359dafe02a 100644 --- a/src/bun.js/bindings/webcore/PerformanceUserTiming.cpp +++ b/src/bun.js/bindings/webcore/PerformanceUserTiming.cpp @@ -78,6 +78,29 @@ PerformanceUserTiming::PerformanceUserTiming(Performance& performance) { } +size_t PerformanceUserTiming::memoryCost() const +{ + size_t size = sizeof(PerformanceUserTiming); + size += m_marksMap.byteSize(); + size += m_measuresMap.byteSize(); + + for (const auto& entry : m_marksMap) { + size += entry.value.sizeInBytes(); + for (const auto& entry : entry.value) { + size += entry->memoryCost(); + } + } + + for (const auto& entry : m_measuresMap) { + size += entry.value.sizeInBytes(); + for (const auto& entry : entry.value) { + size += entry->memoryCost(); + } + } + + return size; +} + static void clearPerformanceEntries(PerformanceEntryMap& map, const String& name) { if (name.isNull()) diff --git a/src/bun.js/bindings/webcore/PerformanceUserTiming.h b/src/bun.js/bindings/webcore/PerformanceUserTiming.h index 624e60fa59..69f734fd73 100644 --- a/src/bun.js/bindings/webcore/PerformanceUserTiming.h +++ b/src/bun.js/bindings/webcore/PerformanceUserTiming.h @@ -62,6 +62,8 @@ public: static bool isRestrictedMarkName(const String& markName); + size_t memoryCost() const; + private: ExceptionOr convertMarkToTimestamp(const std::variant&) const; ExceptionOr convertMarkToTimestamp(const String& markName) const; diff --git a/test/js/web/timers/performance-entries.test.ts b/test/js/web/timers/performance-entries.test.ts new file mode 100644 index 0000000000..bfc297cc1a --- /dev/null +++ b/test/js/web/timers/performance-entries.test.ts @@ -0,0 +1,17 @@ +import { expect, test } from "bun:test"; +import { estimateShallowMemoryUsageOf } from "bun:jsc"; + +test("memory usage of Performance", () => { + const initial = estimateShallowMemoryUsageOf(performance); + for (let i = 0; i < 1024; i++) { + performance.mark(`mark-${i}`); + } + const final = estimateShallowMemoryUsageOf(performance); + + for (let i = 1; i < 1024; i++) { + performance.measure(`measure-${i}`, `mark-${i}`, `mark-${i - 1}`); + } + const final2 = estimateShallowMemoryUsageOf(performance); + expect(final2).toBeGreaterThan(final); + expect(final).toBeGreaterThan(initial); +});