routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* A counter that can be atomically incremented and decremented, and which
|
||||
* callers can synchronously listen for it becoming non-zero.
|
||||
*
|
||||
* This can be "open" or "closed"; once it's closed, {@link wait} will no longer
|
||||
* emit useful events.
|
||||
*/
|
||||
export declare class AtomicCounter {
|
||||
/**
|
||||
* The underlying BigInt64Array.
|
||||
*
|
||||
* The first BigInt64 represents the current value of the counter. The second
|
||||
* BigInt64 is used to track the closed state.
|
||||
*/
|
||||
private readonly buffer;
|
||||
constructor(buffer: SharedArrayBuffer);
|
||||
/** Atomically decrement the current value by one. */
|
||||
decrement(): void;
|
||||
/** Atomically increment the current value by one. */
|
||||
increment(): void;
|
||||
/**
|
||||
* Closes the counter.
|
||||
*
|
||||
* This will cause any outstanding calls to {@link wait} on any thread to
|
||||
* return `true` immediately.
|
||||
*/
|
||||
close(): void;
|
||||
/**
|
||||
* Waits until the current value is not zero or the counter is closed.
|
||||
*
|
||||
* Returns `true` when the counter is non-zero *or* when it's closed. Returns
|
||||
* `false` if the counter remains zero for `timeout` milliseconds.
|
||||
*/
|
||||
wait(timeout?: number): boolean;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AtomicCounter = void 0;
|
||||
/**
|
||||
* A counter that can be atomically incremented and decremented, and which
|
||||
* callers can synchronously listen for it becoming non-zero.
|
||||
*
|
||||
* This can be "open" or "closed"; once it's closed, {@link wait} will no longer
|
||||
* emit useful events.
|
||||
*/
|
||||
class AtomicCounter {
|
||||
/**
|
||||
* The underlying BigInt64Array.
|
||||
*
|
||||
* The first BigInt64 represents the current value of the counter. The second
|
||||
* BigInt64 is used to track the closed state.
|
||||
*/
|
||||
buffer;
|
||||
constructor(buffer) {
|
||||
if (buffer.byteLength !== 16) {
|
||||
throw new Error('SharedArrayBuffer must have a byteLength of 16.');
|
||||
}
|
||||
this.buffer = new BigInt64Array(buffer);
|
||||
}
|
||||
/** Atomically decrement the current value by one. */
|
||||
decrement() {
|
||||
Atomics.sub(this.buffer, 0, 1n);
|
||||
}
|
||||
/** Atomically increment the current value by one. */
|
||||
increment() {
|
||||
if (Atomics.add(this.buffer, 0, 1n) === 0n) {
|
||||
Atomics.notify(this.buffer, 0, 1);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Closes the counter.
|
||||
*
|
||||
* This will cause any outstanding calls to {@link wait} on any thread to
|
||||
* return `true` immediately.
|
||||
*/
|
||||
close() {
|
||||
// The current value is no longer relevant once closed, therefore set it to
|
||||
// non-zero to prevent a potential deadlock when `Atomics.notify` is called
|
||||
// immediately before `Atomics.wait`.
|
||||
if (Atomics.compareExchange(this.buffer, 1, 0n, 1n) === 0n &&
|
||||
Atomics.compareExchange(this.buffer, 0, 0n, 1n) === 0n) {
|
||||
Atomics.notify(this.buffer, 0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Waits until the current value is not zero or the counter is closed.
|
||||
*
|
||||
* Returns `true` when the counter is non-zero *or* when it's closed. Returns
|
||||
* `false` if the counter remains zero for `timeout` milliseconds.
|
||||
*/
|
||||
wait(timeout) {
|
||||
while (Atomics.load(this.buffer, 0) === 0n &&
|
||||
Atomics.load(this.buffer, 1) === 0n) {
|
||||
const result = Atomics.wait(this.buffer, 0, 0n, timeout);
|
||||
if (result !== 'ok') {
|
||||
return result !== 'timed-out';
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
exports.AtomicCounter = AtomicCounter;
|
||||
//# sourceMappingURL=atomic_counter.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"atomic_counter.js","sourceRoot":"","sources":["../../lib/atomic_counter.ts"],"names":[],"mappings":";;;AAAA;;;;;;GAMG;AACH,MAAa,aAAa;IACxB;;;;;OAKG;IACc,MAAM,CAAgB;IAEvC,YAAY,MAAyB;QACnC,IAAI,MAAM,CAAC,UAAU,KAAK,EAAE,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED,qDAAqD;IACrD,SAAS;QACP,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,qDAAqD;IACrD,SAAS;QACP,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;YAC3C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK;QACH,2EAA2E;QAC3E,2EAA2E;QAC3E,qCAAqC;QACrC,IACE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE;YACtD,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,EACtD,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,OAAgB;QACnB,OACE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE;YACnC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,EACnC,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YACzD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,OAAO,MAAM,KAAK,WAAW,CAAC;YAChC,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAhED,sCAgEC"}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { MessageChannel, MessagePort, Transferable } from 'worker_threads';
|
||||
/**
|
||||
* Options that can be passed to {@link SyncMessagePort.receiveMessage}.
|
||||
*/
|
||||
export interface ReceiveMessageOptions {
|
||||
/**
|
||||
* The time (in milliseconds) to wait for a message before returning {@link
|
||||
* timeoutValue} (if set) or throwing a [TimeoutException] otherwise.
|
||||
*/
|
||||
timeout?: number;
|
||||
/**
|
||||
* If a message isn't received within {@link timeout} milliseconds, this value
|
||||
* is returned. Ignored if {@link timeout} is not set.
|
||||
*/
|
||||
timeoutValue?: unknown;
|
||||
/**
|
||||
* If the underlying channel is closed before calling {@link
|
||||
* SyncMessagePort.receiveMessage} or while a call is pending, return this
|
||||
* value.
|
||||
*/
|
||||
closedValue?: unknown;
|
||||
}
|
||||
/**
|
||||
* An exception thrown by {@link SyncMessagePort.receiveMessage} if a message
|
||||
* isn't received within {@link ReceivedMessageOptions.timeout} milliseconds.
|
||||
*/
|
||||
export declare class TimeoutException extends Error {
|
||||
constructor(message: string);
|
||||
}
|
||||
/**
|
||||
* A communication port that can receive messages synchronously from another
|
||||
* `SyncMessagePort`.
|
||||
*
|
||||
* This also emits the same asynchronous events as `MessagePort`. Messages are
|
||||
* preferentially sent to {@link receiveMessage} if a call to it is outstanding,
|
||||
* and only sent to the event handler if they weren't received synchronously.
|
||||
*/
|
||||
export declare class SyncMessagePort extends EventEmitter {
|
||||
private readonly port;
|
||||
/** Creates a channel whose ports can be passed to `new SyncMessagePort()`. */
|
||||
static createChannel(): MessageChannel;
|
||||
/**
|
||||
* An atomic counter of messages posted yet to be received.
|
||||
*/
|
||||
private readonly postCounter;
|
||||
/**
|
||||
* An atomic counter of messages available to be received.
|
||||
*/
|
||||
private readonly receiveCounter;
|
||||
/**
|
||||
* Creates a new message port. The `port` must be created by
|
||||
* `SyncMessagePort.createChannel()` and must connect to a port passed to
|
||||
* another `SyncMessagePort` in another worker.
|
||||
*/
|
||||
constructor(port: MessagePort);
|
||||
/** See `MessagePort.postMesage()`. */
|
||||
postMessage(value: unknown, transferList?: Transferable[]): void;
|
||||
/**
|
||||
* Returns the message sent by the other port, if one is available. This *does
|
||||
* not* block, and will return `undefined` immediately if no message is
|
||||
* available. In order to distinguish between a message with value `undefined`
|
||||
* and no message, a message is return in an object with a `message` field.
|
||||
*
|
||||
* It does *not* throw an error if the port is closed when this is called;
|
||||
* instead, it just returns `undefined`.
|
||||
*/
|
||||
receiveMessageIfAvailable(): {
|
||||
message: unknown;
|
||||
} | undefined;
|
||||
/**
|
||||
* Blocks and returns the next message sent by the other port.
|
||||
*
|
||||
* Throws an error if the channel is closed and all messages are drained,
|
||||
* including if it closes while this is waiting for a message, unless
|
||||
* {@link ReceiveMessageOptions.closedValue} is passed.
|
||||
*/
|
||||
receiveMessage(options?: ReceiveMessageOptions): unknown;
|
||||
/** See `MessagePort.close()`. */
|
||||
close(): void;
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
"use strict";
|
||||
// Copyright 2021 Google LLC. Use of this source code is governed by an
|
||||
// MIT-style license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SyncMessagePort = exports.TimeoutException = void 0;
|
||||
const events_1 = require("events");
|
||||
const worker_threads_1 = require("worker_threads");
|
||||
const atomic_counter_1 = require("./atomic_counter");
|
||||
/**
|
||||
* An exception thrown by {@link SyncMessagePort.receiveMessage} if a message
|
||||
* isn't received within {@link ReceivedMessageOptions.timeout} milliseconds.
|
||||
*/
|
||||
class TimeoutException extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
exports.TimeoutException = TimeoutException;
|
||||
/**
|
||||
* A communication port that can receive messages synchronously from another
|
||||
* `SyncMessagePort`.
|
||||
*
|
||||
* This also emits the same asynchronous events as `MessagePort`. Messages are
|
||||
* preferentially sent to {@link receiveMessage} if a call to it is outstanding,
|
||||
* and only sent to the event handler if they weren't received synchronously.
|
||||
*/
|
||||
class SyncMessagePort extends events_1.EventEmitter {
|
||||
port;
|
||||
/** Creates a channel whose ports can be passed to `new SyncMessagePort()`. */
|
||||
static createChannel() {
|
||||
const channel = new worker_threads_1.MessageChannel();
|
||||
// 16 bytes is required for `AtomicCounter`.
|
||||
const buffer1 = new SharedArrayBuffer(16);
|
||||
const buffer2 = new SharedArrayBuffer(16);
|
||||
// Queue up messages on each port so the caller doesn't have to explicitly
|
||||
// pass the buffer around along with them.
|
||||
channel.port1.postMessage(buffer1);
|
||||
channel.port1.postMessage(buffer2);
|
||||
channel.port2.postMessage(buffer2);
|
||||
channel.port2.postMessage(buffer1);
|
||||
return channel;
|
||||
}
|
||||
/**
|
||||
* An atomic counter of messages posted yet to be received.
|
||||
*/
|
||||
postCounter;
|
||||
/**
|
||||
* An atomic counter of messages available to be received.
|
||||
*/
|
||||
receiveCounter;
|
||||
/**
|
||||
* Creates a new message port. The `port` must be created by
|
||||
* `SyncMessagePort.createChannel()` and must connect to a port passed to
|
||||
* another `SyncMessagePort` in another worker.
|
||||
*/
|
||||
constructor(port) {
|
||||
super();
|
||||
this.port = port;
|
||||
const buffer1 = (0, worker_threads_1.receiveMessageOnPort)(this.port)?.message;
|
||||
const buffer2 = (0, worker_threads_1.receiveMessageOnPort)(this.port)?.message;
|
||||
if (!buffer1 || !buffer2) {
|
||||
throw new Error('new SyncMessagePort() must be passed a port from ' +
|
||||
'SyncMessagePort.createChannel().');
|
||||
}
|
||||
this.postCounter = new atomic_counter_1.AtomicCounter(buffer1);
|
||||
this.receiveCounter = new atomic_counter_1.AtomicCounter(buffer2);
|
||||
const messageHandler = () => {
|
||||
this.receiveCounter.wait();
|
||||
this.receiveCounter.decrement();
|
||||
};
|
||||
this.port.on('messageerror', (error) => {
|
||||
messageHandler();
|
||||
if (!this.listenerCount('messageerror')) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
this.on('newListener', (event, listener) => {
|
||||
if (event === 'message' && !this.listenerCount(event)) {
|
||||
this.port.on(event, messageHandler);
|
||||
}
|
||||
this.port.on(event, listener);
|
||||
});
|
||||
this.on('removeListener', (event, listener) => {
|
||||
this.port.removeListener(event, listener);
|
||||
if (event === 'message' && !this.listenerCount(event)) {
|
||||
this.port.removeListener(event, messageHandler);
|
||||
}
|
||||
});
|
||||
}
|
||||
/** See `MessagePort.postMesage()`. */
|
||||
postMessage(value, transferList) {
|
||||
// @ts-expect-error: TypeScript gets confused with the overloads.
|
||||
this.port.postMessage(value, transferList);
|
||||
this.postCounter.increment();
|
||||
}
|
||||
/**
|
||||
* Returns the message sent by the other port, if one is available. This *does
|
||||
* not* block, and will return `undefined` immediately if no message is
|
||||
* available. In order to distinguish between a message with value `undefined`
|
||||
* and no message, a message is return in an object with a `message` field.
|
||||
*
|
||||
* It does *not* throw an error if the port is closed when this is called;
|
||||
* instead, it just returns `undefined`.
|
||||
*/
|
||||
receiveMessageIfAvailable() {
|
||||
const message = (0, worker_threads_1.receiveMessageOnPort)(this.port);
|
||||
if (message) {
|
||||
this.receiveCounter.wait();
|
||||
this.receiveCounter.decrement();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
/**
|
||||
* Blocks and returns the next message sent by the other port.
|
||||
*
|
||||
* Throws an error if the channel is closed and all messages are drained,
|
||||
* including if it closes while this is waiting for a message, unless
|
||||
* {@link ReceiveMessageOptions.closedValue} is passed.
|
||||
*/
|
||||
receiveMessage(options) {
|
||||
if (!this.receiveCounter.wait(options?.timeout)) {
|
||||
if ('timeoutValue' in options)
|
||||
return options.timeoutValue;
|
||||
throw new TimeoutException('SyncMessagePort.receiveMessage() timed out.');
|
||||
}
|
||||
const message = (0, worker_threads_1.receiveMessageOnPort)(this.port);
|
||||
if (message) {
|
||||
this.receiveCounter.decrement();
|
||||
return message.message;
|
||||
}
|
||||
// The port is closed and all remaining messages are drained.
|
||||
if (options && 'closedValue' in options)
|
||||
return options.closedValue;
|
||||
throw new Error("The SyncMessagePort's channel is closed.");
|
||||
}
|
||||
/** See `MessagePort.close()`. */
|
||||
close() {
|
||||
this.port.close();
|
||||
this.postCounter.close();
|
||||
this.receiveCounter.close();
|
||||
}
|
||||
}
|
||||
exports.SyncMessagePort = SyncMessagePort;
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":";AAAA,uEAAuE;AACvE,gEAAgE;AAChE,uCAAuC;;;AAEvC,mCAAoC;AACpC,mDAKwB;AACxB,qDAA+C;AA0B/C;;;GAGG;AACH,MAAa,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AAJD,4CAIC;AAED;;;;;;;GAOG;AACH,MAAa,eAAgB,SAAQ,qBAAY;IAgClB;IA/B7B,8EAA8E;IAC9E,MAAM,CAAC,aAAa;QAClB,MAAM,OAAO,GAAG,IAAI,+BAAc,EAAE,CAAC;QACrC,4CAA4C;QAC5C,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,EAAE,CAAC,CAAC;QAE1C,0EAA0E;QAC1E,0CAA0C;QAC1C,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACnC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACc,WAAW,CAAgB;IAE5C;;OAEG;IACc,cAAc,CAAgB;IAE/C;;;;OAIG;IACH,YAA6B,IAAiB;QAC5C,KAAK,EAAE,CAAC;QADmB,SAAI,GAAJ,IAAI,CAAa;QAG5C,MAAM,OAAO,GAAG,IAAA,qCAAoB,EAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QACzD,MAAM,OAAO,GAAG,IAAA,qCAAoB,EAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QACzD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,mDAAmD;gBACjD,kCAAkC,CACrC,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,IAAI,8BAAa,CAAC,OAA4B,CAAC,CAAC;QACnE,IAAI,CAAC,cAAc,GAAG,IAAI,8BAAa,CAAC,OAA4B,CAAC,CAAC;QAEtE,MAAM,cAAc,GAAG,GAAS,EAAE;YAChC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;QAClC,CAAC,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,KAAY,EAAQ,EAAE;YAClD,cAAc,EAAE,CAAC;YACjB,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC;gBACxC,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;YACzC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;YACtC,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;YAC5C,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC1C,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,sCAAsC;IACtC,WAAW,CAAC,KAAc,EAAE,YAA6B;QACvD,iEAAiE;QACjE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QAC3C,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;IAC/B,CAAC;IAED;;;;;;;;OAQG;IACH,yBAAyB;QACvB,MAAM,OAAO,GAAG,IAAA,qCAAoB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;QAClC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;OAMG;IACH,cAAc,CAAC,OAA+B;QAC5C,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;YAChD,IAAI,cAAc,IAAI,OAAQ;gBAAE,OAAO,OAAO,CAAC,YAAY,CAAC;YAC5D,MAAM,IAAI,gBAAgB,CAAC,6CAA6C,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,OAAO,GAAG,IAAA,qCAAoB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;YAChC,OAAO,OAAO,CAAC,OAAO,CAAC;QACzB,CAAC;QAED,6DAA6D;QAC7D,IAAI,OAAO,IAAI,aAAa,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC,WAAW,CAAC;QACpE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IAED,iCAAiC;IACjC,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;CACF;AA7HD,0CA6HC"}
|
||||
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user