@tscircuit/curvy-trace-solver 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +16 -0
- package/README.md +3 -0
- package/biome.json +96 -0
- package/bunfig.toml +5 -0
- package/cosmos.config.json +5 -0
- package/cosmos.decorator.tsx +21 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +1643 -0
- package/fixtures/basics/basics01-input.json +15 -0
- package/fixtures/basics/basics01.fixture.tsx +11 -0
- package/fixtures/problem-generator.fixture.tsx +50 -0
- package/index.html +12 -0
- package/lib/CurvyTraceSolver.ts +775 -0
- package/lib/geometry/getObstacleOuterSegments.ts +25 -0
- package/lib/geometry/index.ts +8 -0
- package/lib/index.ts +2 -0
- package/lib/problem-generator/countChordCrossings.ts +119 -0
- package/lib/problem-generator/createRng.ts +13 -0
- package/lib/problem-generator/generateRandomProblem.ts +225 -0
- package/lib/problem-generator/index.ts +1 -0
- package/lib/problem-generator/randomBoundaryPoint.ts +30 -0
- package/lib/problem-generator/wouldCrossAny.ts +16 -0
- package/lib/sampleTraceIntoSegments.ts +62 -0
- package/lib/scoreOutputCost.ts +116 -0
- package/lib/types.ts +35 -0
- package/lib/visualization-utils/index.ts +14 -0
- package/lib/visualization-utils/visualizeCurvyTraceProblem.ts +66 -0
- package/package.json +27 -0
- package/scripts/benchmarks/run-benchmark.ts +85 -0
- package/tests/__snapshots__/svg.snap.svg +3 -0
- package/tests/basics/__snapshots__/basics01.snap.svg +44 -0
- package/tests/basics/basics01.test.ts +12 -0
- package/tests/fixtures/preload.ts +1 -0
- package/tests/svg.test.ts +12 -0
- package/tsconfig.json +35 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1643 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// node_modules/is-buffer/index.js
|
|
28
|
+
var require_is_buffer = __commonJS({
|
|
29
|
+
"node_modules/is-buffer/index.js"(exports, module) {
|
|
30
|
+
"use strict";
|
|
31
|
+
module.exports = function(obj) {
|
|
32
|
+
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer);
|
|
33
|
+
};
|
|
34
|
+
function isBuffer(obj) {
|
|
35
|
+
return !!obj.constructor && typeof obj.constructor.isBuffer === "function" && obj.constructor.isBuffer(obj);
|
|
36
|
+
}
|
|
37
|
+
function isSlowBuffer(obj) {
|
|
38
|
+
return typeof obj.readFloatLE === "function" && typeof obj.slice === "function" && isBuffer(obj.slice(0, 0));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// node_modules/kind-of/index.js
|
|
44
|
+
var require_kind_of = __commonJS({
|
|
45
|
+
"node_modules/kind-of/index.js"(exports, module) {
|
|
46
|
+
"use strict";
|
|
47
|
+
var isBuffer = require_is_buffer();
|
|
48
|
+
var toString = Object.prototype.toString;
|
|
49
|
+
module.exports = function kindOf(val) {
|
|
50
|
+
if (typeof val === "undefined") {
|
|
51
|
+
return "undefined";
|
|
52
|
+
}
|
|
53
|
+
if (val === null) {
|
|
54
|
+
return "null";
|
|
55
|
+
}
|
|
56
|
+
if (val === true || val === false || val instanceof Boolean) {
|
|
57
|
+
return "boolean";
|
|
58
|
+
}
|
|
59
|
+
if (typeof val === "string" || val instanceof String) {
|
|
60
|
+
return "string";
|
|
61
|
+
}
|
|
62
|
+
if (typeof val === "number" || val instanceof Number) {
|
|
63
|
+
return "number";
|
|
64
|
+
}
|
|
65
|
+
if (typeof val === "function" || val instanceof Function) {
|
|
66
|
+
return "function";
|
|
67
|
+
}
|
|
68
|
+
if (typeof Array.isArray !== "undefined" && Array.isArray(val)) {
|
|
69
|
+
return "array";
|
|
70
|
+
}
|
|
71
|
+
if (val instanceof RegExp) {
|
|
72
|
+
return "regexp";
|
|
73
|
+
}
|
|
74
|
+
if (val instanceof Date) {
|
|
75
|
+
return "date";
|
|
76
|
+
}
|
|
77
|
+
var type = toString.call(val);
|
|
78
|
+
if (type === "[object RegExp]") {
|
|
79
|
+
return "regexp";
|
|
80
|
+
}
|
|
81
|
+
if (type === "[object Date]") {
|
|
82
|
+
return "date";
|
|
83
|
+
}
|
|
84
|
+
if (type === "[object Arguments]") {
|
|
85
|
+
return "arguments";
|
|
86
|
+
}
|
|
87
|
+
if (type === "[object Error]") {
|
|
88
|
+
return "error";
|
|
89
|
+
}
|
|
90
|
+
if (isBuffer(val)) {
|
|
91
|
+
return "buffer";
|
|
92
|
+
}
|
|
93
|
+
if (type === "[object Set]") {
|
|
94
|
+
return "set";
|
|
95
|
+
}
|
|
96
|
+
if (type === "[object WeakSet]") {
|
|
97
|
+
return "weakset";
|
|
98
|
+
}
|
|
99
|
+
if (type === "[object Map]") {
|
|
100
|
+
return "map";
|
|
101
|
+
}
|
|
102
|
+
if (type === "[object WeakMap]") {
|
|
103
|
+
return "weakmap";
|
|
104
|
+
}
|
|
105
|
+
if (type === "[object Symbol]") {
|
|
106
|
+
return "symbol";
|
|
107
|
+
}
|
|
108
|
+
if (type === "[object Int8Array]") {
|
|
109
|
+
return "int8array";
|
|
110
|
+
}
|
|
111
|
+
if (type === "[object Uint8Array]") {
|
|
112
|
+
return "uint8array";
|
|
113
|
+
}
|
|
114
|
+
if (type === "[object Uint8ClampedArray]") {
|
|
115
|
+
return "uint8clampedarray";
|
|
116
|
+
}
|
|
117
|
+
if (type === "[object Int16Array]") {
|
|
118
|
+
return "int16array";
|
|
119
|
+
}
|
|
120
|
+
if (type === "[object Uint16Array]") {
|
|
121
|
+
return "uint16array";
|
|
122
|
+
}
|
|
123
|
+
if (type === "[object Int32Array]") {
|
|
124
|
+
return "int32array";
|
|
125
|
+
}
|
|
126
|
+
if (type === "[object Uint32Array]") {
|
|
127
|
+
return "uint32array";
|
|
128
|
+
}
|
|
129
|
+
if (type === "[object Float32Array]") {
|
|
130
|
+
return "float32array";
|
|
131
|
+
}
|
|
132
|
+
if (type === "[object Float64Array]") {
|
|
133
|
+
return "float64array";
|
|
134
|
+
}
|
|
135
|
+
return "object";
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// node_modules/rename-keys/index.js
|
|
141
|
+
var require_rename_keys = __commonJS({
|
|
142
|
+
"node_modules/rename-keys/index.js"(exports, module) {
|
|
143
|
+
"use strict";
|
|
144
|
+
(function() {
|
|
145
|
+
"use strict";
|
|
146
|
+
function rename2(obj, fn) {
|
|
147
|
+
if (typeof fn !== "function") {
|
|
148
|
+
return obj;
|
|
149
|
+
}
|
|
150
|
+
var res = {};
|
|
151
|
+
for (var key in obj) {
|
|
152
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
153
|
+
res[fn(key, obj[key]) || key] = obj[key];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return res;
|
|
157
|
+
}
|
|
158
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
159
|
+
module.exports = rename2;
|
|
160
|
+
} else {
|
|
161
|
+
if (typeof define === "function" && define.amd) {
|
|
162
|
+
define([], function() {
|
|
163
|
+
return rename2;
|
|
164
|
+
});
|
|
165
|
+
} else {
|
|
166
|
+
window.rename = rename2;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
})();
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// node_modules/deep-rename-keys/index.js
|
|
174
|
+
var require_deep_rename_keys = __commonJS({
|
|
175
|
+
"node_modules/deep-rename-keys/index.js"(exports, module) {
|
|
176
|
+
"use strict";
|
|
177
|
+
var typeOf = require_kind_of();
|
|
178
|
+
var rename2 = require_rename_keys();
|
|
179
|
+
module.exports = function renameDeep(obj, cb) {
|
|
180
|
+
var type = typeOf(obj);
|
|
181
|
+
if (type !== "object" && type !== "array") {
|
|
182
|
+
throw new Error("expected an object");
|
|
183
|
+
}
|
|
184
|
+
var res = [];
|
|
185
|
+
if (type === "object") {
|
|
186
|
+
obj = rename2(obj, cb);
|
|
187
|
+
res = {};
|
|
188
|
+
}
|
|
189
|
+
for (var key in obj) {
|
|
190
|
+
if (obj.hasOwnProperty(key)) {
|
|
191
|
+
var val = obj[key];
|
|
192
|
+
if (typeOf(val) === "object" || typeOf(val) === "array") {
|
|
193
|
+
res[key] = renameDeep(val, cb);
|
|
194
|
+
} else {
|
|
195
|
+
res[key] = val;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return res;
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// node_modules/xml-reader/node_modules/eventemitter3/index.js
|
|
205
|
+
var require_eventemitter3 = __commonJS({
|
|
206
|
+
"node_modules/xml-reader/node_modules/eventemitter3/index.js"(exports, module) {
|
|
207
|
+
"use strict";
|
|
208
|
+
var has = Object.prototype.hasOwnProperty;
|
|
209
|
+
var prefix = "~";
|
|
210
|
+
function Events() {
|
|
211
|
+
}
|
|
212
|
+
if (Object.create) {
|
|
213
|
+
Events.prototype = /* @__PURE__ */ Object.create(null);
|
|
214
|
+
if (!new Events().__proto__) prefix = false;
|
|
215
|
+
}
|
|
216
|
+
function EE(fn, context, once) {
|
|
217
|
+
this.fn = fn;
|
|
218
|
+
this.context = context;
|
|
219
|
+
this.once = once || false;
|
|
220
|
+
}
|
|
221
|
+
function EventEmitter() {
|
|
222
|
+
this._events = new Events();
|
|
223
|
+
this._eventsCount = 0;
|
|
224
|
+
}
|
|
225
|
+
EventEmitter.prototype.eventNames = function eventNames() {
|
|
226
|
+
var names = [], events, name;
|
|
227
|
+
if (this._eventsCount === 0) return names;
|
|
228
|
+
for (name in events = this._events) {
|
|
229
|
+
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
|
230
|
+
}
|
|
231
|
+
if (Object.getOwnPropertySymbols) {
|
|
232
|
+
return names.concat(Object.getOwnPropertySymbols(events));
|
|
233
|
+
}
|
|
234
|
+
return names;
|
|
235
|
+
};
|
|
236
|
+
EventEmitter.prototype.listeners = function listeners(event, exists) {
|
|
237
|
+
var evt = prefix ? prefix + event : event, available = this._events[evt];
|
|
238
|
+
if (exists) return !!available;
|
|
239
|
+
if (!available) return [];
|
|
240
|
+
if (available.fn) return [available.fn];
|
|
241
|
+
for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) {
|
|
242
|
+
ee[i] = available[i].fn;
|
|
243
|
+
}
|
|
244
|
+
return ee;
|
|
245
|
+
};
|
|
246
|
+
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
|
247
|
+
var evt = prefix ? prefix + event : event;
|
|
248
|
+
if (!this._events[evt]) return false;
|
|
249
|
+
var listeners = this._events[evt], len = arguments.length, args, i;
|
|
250
|
+
if (listeners.fn) {
|
|
251
|
+
if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
|
|
252
|
+
switch (len) {
|
|
253
|
+
case 1:
|
|
254
|
+
return listeners.fn.call(listeners.context), true;
|
|
255
|
+
case 2:
|
|
256
|
+
return listeners.fn.call(listeners.context, a1), true;
|
|
257
|
+
case 3:
|
|
258
|
+
return listeners.fn.call(listeners.context, a1, a2), true;
|
|
259
|
+
case 4:
|
|
260
|
+
return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
|
261
|
+
case 5:
|
|
262
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
|
263
|
+
case 6:
|
|
264
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
|
265
|
+
}
|
|
266
|
+
for (i = 1, args = new Array(len - 1); i < len; i++) {
|
|
267
|
+
args[i - 1] = arguments[i];
|
|
268
|
+
}
|
|
269
|
+
listeners.fn.apply(listeners.context, args);
|
|
270
|
+
} else {
|
|
271
|
+
var length = listeners.length, j;
|
|
272
|
+
for (i = 0; i < length; i++) {
|
|
273
|
+
if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true);
|
|
274
|
+
switch (len) {
|
|
275
|
+
case 1:
|
|
276
|
+
listeners[i].fn.call(listeners[i].context);
|
|
277
|
+
break;
|
|
278
|
+
case 2:
|
|
279
|
+
listeners[i].fn.call(listeners[i].context, a1);
|
|
280
|
+
break;
|
|
281
|
+
case 3:
|
|
282
|
+
listeners[i].fn.call(listeners[i].context, a1, a2);
|
|
283
|
+
break;
|
|
284
|
+
case 4:
|
|
285
|
+
listeners[i].fn.call(listeners[i].context, a1, a2, a3);
|
|
286
|
+
break;
|
|
287
|
+
default:
|
|
288
|
+
if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
|
|
289
|
+
args[j - 1] = arguments[j];
|
|
290
|
+
}
|
|
291
|
+
listeners[i].fn.apply(listeners[i].context, args);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
296
|
+
};
|
|
297
|
+
EventEmitter.prototype.on = function on(event, fn, context) {
|
|
298
|
+
var listener = new EE(fn, context || this), evt = prefix ? prefix + event : event;
|
|
299
|
+
if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++;
|
|
300
|
+
else if (!this._events[evt].fn) this._events[evt].push(listener);
|
|
301
|
+
else this._events[evt] = [this._events[evt], listener];
|
|
302
|
+
return this;
|
|
303
|
+
};
|
|
304
|
+
EventEmitter.prototype.once = function once(event, fn, context) {
|
|
305
|
+
var listener = new EE(fn, context || this, true), evt = prefix ? prefix + event : event;
|
|
306
|
+
if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++;
|
|
307
|
+
else if (!this._events[evt].fn) this._events[evt].push(listener);
|
|
308
|
+
else this._events[evt] = [this._events[evt], listener];
|
|
309
|
+
return this;
|
|
310
|
+
};
|
|
311
|
+
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
|
312
|
+
var evt = prefix ? prefix + event : event;
|
|
313
|
+
if (!this._events[evt]) return this;
|
|
314
|
+
if (!fn) {
|
|
315
|
+
if (--this._eventsCount === 0) this._events = new Events();
|
|
316
|
+
else delete this._events[evt];
|
|
317
|
+
return this;
|
|
318
|
+
}
|
|
319
|
+
var listeners = this._events[evt];
|
|
320
|
+
if (listeners.fn) {
|
|
321
|
+
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
|
|
322
|
+
if (--this._eventsCount === 0) this._events = new Events();
|
|
323
|
+
else delete this._events[evt];
|
|
324
|
+
}
|
|
325
|
+
} else {
|
|
326
|
+
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
|
327
|
+
if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
|
|
328
|
+
events.push(listeners[i]);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
|
|
332
|
+
else if (--this._eventsCount === 0) this._events = new Events();
|
|
333
|
+
else delete this._events[evt];
|
|
334
|
+
}
|
|
335
|
+
return this;
|
|
336
|
+
};
|
|
337
|
+
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
|
338
|
+
var evt;
|
|
339
|
+
if (event) {
|
|
340
|
+
evt = prefix ? prefix + event : event;
|
|
341
|
+
if (this._events[evt]) {
|
|
342
|
+
if (--this._eventsCount === 0) this._events = new Events();
|
|
343
|
+
else delete this._events[evt];
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
this._events = new Events();
|
|
347
|
+
this._eventsCount = 0;
|
|
348
|
+
}
|
|
349
|
+
return this;
|
|
350
|
+
};
|
|
351
|
+
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
352
|
+
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
353
|
+
EventEmitter.prototype.setMaxListeners = function setMaxListeners() {
|
|
354
|
+
return this;
|
|
355
|
+
};
|
|
356
|
+
EventEmitter.prefixed = prefix;
|
|
357
|
+
EventEmitter.EventEmitter = EventEmitter;
|
|
358
|
+
if ("undefined" !== typeof module) {
|
|
359
|
+
module.exports = EventEmitter;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// node_modules/xml-lexer/node_modules/eventemitter3/index.js
|
|
365
|
+
var require_eventemitter32 = __commonJS({
|
|
366
|
+
"node_modules/xml-lexer/node_modules/eventemitter3/index.js"(exports, module) {
|
|
367
|
+
"use strict";
|
|
368
|
+
var has = Object.prototype.hasOwnProperty;
|
|
369
|
+
var prefix = "~";
|
|
370
|
+
function Events() {
|
|
371
|
+
}
|
|
372
|
+
if (Object.create) {
|
|
373
|
+
Events.prototype = /* @__PURE__ */ Object.create(null);
|
|
374
|
+
if (!new Events().__proto__) prefix = false;
|
|
375
|
+
}
|
|
376
|
+
function EE(fn, context, once) {
|
|
377
|
+
this.fn = fn;
|
|
378
|
+
this.context = context;
|
|
379
|
+
this.once = once || false;
|
|
380
|
+
}
|
|
381
|
+
function EventEmitter() {
|
|
382
|
+
this._events = new Events();
|
|
383
|
+
this._eventsCount = 0;
|
|
384
|
+
}
|
|
385
|
+
EventEmitter.prototype.eventNames = function eventNames() {
|
|
386
|
+
var names = [], events, name;
|
|
387
|
+
if (this._eventsCount === 0) return names;
|
|
388
|
+
for (name in events = this._events) {
|
|
389
|
+
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
|
390
|
+
}
|
|
391
|
+
if (Object.getOwnPropertySymbols) {
|
|
392
|
+
return names.concat(Object.getOwnPropertySymbols(events));
|
|
393
|
+
}
|
|
394
|
+
return names;
|
|
395
|
+
};
|
|
396
|
+
EventEmitter.prototype.listeners = function listeners(event, exists) {
|
|
397
|
+
var evt = prefix ? prefix + event : event, available = this._events[evt];
|
|
398
|
+
if (exists) return !!available;
|
|
399
|
+
if (!available) return [];
|
|
400
|
+
if (available.fn) return [available.fn];
|
|
401
|
+
for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) {
|
|
402
|
+
ee[i] = available[i].fn;
|
|
403
|
+
}
|
|
404
|
+
return ee;
|
|
405
|
+
};
|
|
406
|
+
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
|
407
|
+
var evt = prefix ? prefix + event : event;
|
|
408
|
+
if (!this._events[evt]) return false;
|
|
409
|
+
var listeners = this._events[evt], len = arguments.length, args, i;
|
|
410
|
+
if (listeners.fn) {
|
|
411
|
+
if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
|
|
412
|
+
switch (len) {
|
|
413
|
+
case 1:
|
|
414
|
+
return listeners.fn.call(listeners.context), true;
|
|
415
|
+
case 2:
|
|
416
|
+
return listeners.fn.call(listeners.context, a1), true;
|
|
417
|
+
case 3:
|
|
418
|
+
return listeners.fn.call(listeners.context, a1, a2), true;
|
|
419
|
+
case 4:
|
|
420
|
+
return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
|
421
|
+
case 5:
|
|
422
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
|
423
|
+
case 6:
|
|
424
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
|
425
|
+
}
|
|
426
|
+
for (i = 1, args = new Array(len - 1); i < len; i++) {
|
|
427
|
+
args[i - 1] = arguments[i];
|
|
428
|
+
}
|
|
429
|
+
listeners.fn.apply(listeners.context, args);
|
|
430
|
+
} else {
|
|
431
|
+
var length = listeners.length, j;
|
|
432
|
+
for (i = 0; i < length; i++) {
|
|
433
|
+
if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true);
|
|
434
|
+
switch (len) {
|
|
435
|
+
case 1:
|
|
436
|
+
listeners[i].fn.call(listeners[i].context);
|
|
437
|
+
break;
|
|
438
|
+
case 2:
|
|
439
|
+
listeners[i].fn.call(listeners[i].context, a1);
|
|
440
|
+
break;
|
|
441
|
+
case 3:
|
|
442
|
+
listeners[i].fn.call(listeners[i].context, a1, a2);
|
|
443
|
+
break;
|
|
444
|
+
case 4:
|
|
445
|
+
listeners[i].fn.call(listeners[i].context, a1, a2, a3);
|
|
446
|
+
break;
|
|
447
|
+
default:
|
|
448
|
+
if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
|
|
449
|
+
args[j - 1] = arguments[j];
|
|
450
|
+
}
|
|
451
|
+
listeners[i].fn.apply(listeners[i].context, args);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return true;
|
|
456
|
+
};
|
|
457
|
+
EventEmitter.prototype.on = function on(event, fn, context) {
|
|
458
|
+
var listener = new EE(fn, context || this), evt = prefix ? prefix + event : event;
|
|
459
|
+
if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++;
|
|
460
|
+
else if (!this._events[evt].fn) this._events[evt].push(listener);
|
|
461
|
+
else this._events[evt] = [this._events[evt], listener];
|
|
462
|
+
return this;
|
|
463
|
+
};
|
|
464
|
+
EventEmitter.prototype.once = function once(event, fn, context) {
|
|
465
|
+
var listener = new EE(fn, context || this, true), evt = prefix ? prefix + event : event;
|
|
466
|
+
if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++;
|
|
467
|
+
else if (!this._events[evt].fn) this._events[evt].push(listener);
|
|
468
|
+
else this._events[evt] = [this._events[evt], listener];
|
|
469
|
+
return this;
|
|
470
|
+
};
|
|
471
|
+
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
|
472
|
+
var evt = prefix ? prefix + event : event;
|
|
473
|
+
if (!this._events[evt]) return this;
|
|
474
|
+
if (!fn) {
|
|
475
|
+
if (--this._eventsCount === 0) this._events = new Events();
|
|
476
|
+
else delete this._events[evt];
|
|
477
|
+
return this;
|
|
478
|
+
}
|
|
479
|
+
var listeners = this._events[evt];
|
|
480
|
+
if (listeners.fn) {
|
|
481
|
+
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
|
|
482
|
+
if (--this._eventsCount === 0) this._events = new Events();
|
|
483
|
+
else delete this._events[evt];
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
|
487
|
+
if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
|
|
488
|
+
events.push(listeners[i]);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
|
|
492
|
+
else if (--this._eventsCount === 0) this._events = new Events();
|
|
493
|
+
else delete this._events[evt];
|
|
494
|
+
}
|
|
495
|
+
return this;
|
|
496
|
+
};
|
|
497
|
+
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
|
498
|
+
var evt;
|
|
499
|
+
if (event) {
|
|
500
|
+
evt = prefix ? prefix + event : event;
|
|
501
|
+
if (this._events[evt]) {
|
|
502
|
+
if (--this._eventsCount === 0) this._events = new Events();
|
|
503
|
+
else delete this._events[evt];
|
|
504
|
+
}
|
|
505
|
+
} else {
|
|
506
|
+
this._events = new Events();
|
|
507
|
+
this._eventsCount = 0;
|
|
508
|
+
}
|
|
509
|
+
return this;
|
|
510
|
+
};
|
|
511
|
+
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
512
|
+
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
513
|
+
EventEmitter.prototype.setMaxListeners = function setMaxListeners() {
|
|
514
|
+
return this;
|
|
515
|
+
};
|
|
516
|
+
EventEmitter.prefixed = prefix;
|
|
517
|
+
EventEmitter.EventEmitter = EventEmitter;
|
|
518
|
+
if ("undefined" !== typeof module) {
|
|
519
|
+
module.exports = EventEmitter;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// node_modules/xml-lexer/dist/lexer.js
|
|
525
|
+
var require_lexer = __commonJS({
|
|
526
|
+
"node_modules/xml-lexer/dist/lexer.js"(exports, module) {
|
|
527
|
+
"use strict";
|
|
528
|
+
function _defineProperty(obj, key, value) {
|
|
529
|
+
if (key in obj) {
|
|
530
|
+
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
|
|
531
|
+
} else {
|
|
532
|
+
obj[key] = value;
|
|
533
|
+
}
|
|
534
|
+
return obj;
|
|
535
|
+
}
|
|
536
|
+
var EventEmitter = require_eventemitter32();
|
|
537
|
+
var noop = function noop2() {
|
|
538
|
+
};
|
|
539
|
+
var State = {
|
|
540
|
+
data: "state-data",
|
|
541
|
+
cdata: "state-cdata",
|
|
542
|
+
tagBegin: "state-tag-begin",
|
|
543
|
+
tagName: "state-tag-name",
|
|
544
|
+
tagEnd: "state-tag-end",
|
|
545
|
+
attributeNameStart: "state-attribute-name-start",
|
|
546
|
+
attributeName: "state-attribute-name",
|
|
547
|
+
attributeNameEnd: "state-attribute-name-end",
|
|
548
|
+
attributeValueBegin: "state-attribute-value-begin",
|
|
549
|
+
attributeValue: "state-attribute-value"
|
|
550
|
+
};
|
|
551
|
+
var Action = {
|
|
552
|
+
lt: "action-lt",
|
|
553
|
+
gt: "action-gt",
|
|
554
|
+
space: "action-space",
|
|
555
|
+
equal: "action-equal",
|
|
556
|
+
quote: "action-quote",
|
|
557
|
+
slash: "action-slash",
|
|
558
|
+
char: "action-char",
|
|
559
|
+
error: "action-error"
|
|
560
|
+
};
|
|
561
|
+
var Type = {
|
|
562
|
+
text: "text",
|
|
563
|
+
openTag: "open-tag",
|
|
564
|
+
closeTag: "close-tag",
|
|
565
|
+
attributeName: "attribute-name",
|
|
566
|
+
attributeValue: "attribute-value"
|
|
567
|
+
};
|
|
568
|
+
var charToAction = {
|
|
569
|
+
" ": Action.space,
|
|
570
|
+
" ": Action.space,
|
|
571
|
+
"\n": Action.space,
|
|
572
|
+
"\r": Action.space,
|
|
573
|
+
"<": Action.lt,
|
|
574
|
+
">": Action.gt,
|
|
575
|
+
'"': Action.quote,
|
|
576
|
+
"'": Action.quote,
|
|
577
|
+
"=": Action.equal,
|
|
578
|
+
"/": Action.slash
|
|
579
|
+
};
|
|
580
|
+
var getAction = function getAction2(char) {
|
|
581
|
+
return charToAction[char] || Action.char;
|
|
582
|
+
};
|
|
583
|
+
var create = function create2(options) {
|
|
584
|
+
var _State$data, _State$tagBegin, _State$tagName, _State$tagEnd, _State$attributeNameS, _State$attributeName, _State$attributeNameE, _State$attributeValue, _State$attributeValue2, _lexer$stateMachine;
|
|
585
|
+
options = Object.assign({ debug: false }, options);
|
|
586
|
+
var lexer = new EventEmitter();
|
|
587
|
+
var state = State.data;
|
|
588
|
+
var data = "";
|
|
589
|
+
var tagName = "";
|
|
590
|
+
var attrName = "";
|
|
591
|
+
var attrValue = "";
|
|
592
|
+
var isClosing = "";
|
|
593
|
+
var openingQuote = "";
|
|
594
|
+
var emit = function emit2(type, value) {
|
|
595
|
+
if (tagName[0] === "?" || tagName[0] === "!") {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
var event = { type, value };
|
|
599
|
+
if (options.debug) {
|
|
600
|
+
console.log("emit:", event);
|
|
601
|
+
}
|
|
602
|
+
lexer.emit("data", event);
|
|
603
|
+
};
|
|
604
|
+
lexer.stateMachine = (_lexer$stateMachine = {}, _defineProperty(_lexer$stateMachine, State.data, (_State$data = {}, _defineProperty(_State$data, Action.lt, function() {
|
|
605
|
+
if (data.trim()) {
|
|
606
|
+
emit(Type.text, data);
|
|
607
|
+
}
|
|
608
|
+
tagName = "";
|
|
609
|
+
isClosing = false;
|
|
610
|
+
state = State.tagBegin;
|
|
611
|
+
}), _defineProperty(_State$data, Action.char, function(char) {
|
|
612
|
+
data += char;
|
|
613
|
+
}), _State$data)), _defineProperty(_lexer$stateMachine, State.cdata, _defineProperty({}, Action.char, function(char) {
|
|
614
|
+
data += char;
|
|
615
|
+
if (data.substr(-3) === "]]>") {
|
|
616
|
+
emit(Type.text, data.slice(0, -3));
|
|
617
|
+
data = "";
|
|
618
|
+
state = State.data;
|
|
619
|
+
}
|
|
620
|
+
})), _defineProperty(_lexer$stateMachine, State.tagBegin, (_State$tagBegin = {}, _defineProperty(_State$tagBegin, Action.space, noop), _defineProperty(_State$tagBegin, Action.char, function(char) {
|
|
621
|
+
tagName = char;
|
|
622
|
+
state = State.tagName;
|
|
623
|
+
}), _defineProperty(_State$tagBegin, Action.slash, function() {
|
|
624
|
+
tagName = "";
|
|
625
|
+
isClosing = true;
|
|
626
|
+
}), _State$tagBegin)), _defineProperty(_lexer$stateMachine, State.tagName, (_State$tagName = {}, _defineProperty(_State$tagName, Action.space, function() {
|
|
627
|
+
if (isClosing) {
|
|
628
|
+
state = State.tagEnd;
|
|
629
|
+
} else {
|
|
630
|
+
state = State.attributeNameStart;
|
|
631
|
+
emit(Type.openTag, tagName);
|
|
632
|
+
}
|
|
633
|
+
}), _defineProperty(_State$tagName, Action.gt, function() {
|
|
634
|
+
if (isClosing) {
|
|
635
|
+
emit(Type.closeTag, tagName);
|
|
636
|
+
} else {
|
|
637
|
+
emit(Type.openTag, tagName);
|
|
638
|
+
}
|
|
639
|
+
data = "";
|
|
640
|
+
state = State.data;
|
|
641
|
+
}), _defineProperty(_State$tagName, Action.slash, function() {
|
|
642
|
+
state = State.tagEnd;
|
|
643
|
+
emit(Type.openTag, tagName);
|
|
644
|
+
}), _defineProperty(_State$tagName, Action.char, function(char) {
|
|
645
|
+
tagName += char;
|
|
646
|
+
if (tagName === "![CDATA[") {
|
|
647
|
+
state = State.cdata;
|
|
648
|
+
data = "";
|
|
649
|
+
tagName = "";
|
|
650
|
+
}
|
|
651
|
+
}), _State$tagName)), _defineProperty(_lexer$stateMachine, State.tagEnd, (_State$tagEnd = {}, _defineProperty(_State$tagEnd, Action.gt, function() {
|
|
652
|
+
emit(Type.closeTag, tagName);
|
|
653
|
+
data = "";
|
|
654
|
+
state = State.data;
|
|
655
|
+
}), _defineProperty(_State$tagEnd, Action.char, noop), _State$tagEnd)), _defineProperty(_lexer$stateMachine, State.attributeNameStart, (_State$attributeNameS = {}, _defineProperty(_State$attributeNameS, Action.char, function(char) {
|
|
656
|
+
attrName = char;
|
|
657
|
+
state = State.attributeName;
|
|
658
|
+
}), _defineProperty(_State$attributeNameS, Action.gt, function() {
|
|
659
|
+
data = "";
|
|
660
|
+
state = State.data;
|
|
661
|
+
}), _defineProperty(_State$attributeNameS, Action.space, noop), _defineProperty(_State$attributeNameS, Action.slash, function() {
|
|
662
|
+
isClosing = true;
|
|
663
|
+
state = State.tagEnd;
|
|
664
|
+
}), _State$attributeNameS)), _defineProperty(_lexer$stateMachine, State.attributeName, (_State$attributeName = {}, _defineProperty(_State$attributeName, Action.space, function() {
|
|
665
|
+
state = State.attributeNameEnd;
|
|
666
|
+
}), _defineProperty(_State$attributeName, Action.equal, function() {
|
|
667
|
+
emit(Type.attributeName, attrName);
|
|
668
|
+
state = State.attributeValueBegin;
|
|
669
|
+
}), _defineProperty(_State$attributeName, Action.gt, function() {
|
|
670
|
+
attrValue = "";
|
|
671
|
+
emit(Type.attributeName, attrName);
|
|
672
|
+
emit(Type.attributeValue, attrValue);
|
|
673
|
+
data = "";
|
|
674
|
+
state = State.data;
|
|
675
|
+
}), _defineProperty(_State$attributeName, Action.slash, function() {
|
|
676
|
+
isClosing = true;
|
|
677
|
+
attrValue = "";
|
|
678
|
+
emit(Type.attributeName, attrName);
|
|
679
|
+
emit(Type.attributeValue, attrValue);
|
|
680
|
+
state = State.tagEnd;
|
|
681
|
+
}), _defineProperty(_State$attributeName, Action.char, function(char) {
|
|
682
|
+
attrName += char;
|
|
683
|
+
}), _State$attributeName)), _defineProperty(_lexer$stateMachine, State.attributeNameEnd, (_State$attributeNameE = {}, _defineProperty(_State$attributeNameE, Action.space, noop), _defineProperty(_State$attributeNameE, Action.equal, function() {
|
|
684
|
+
emit(Type.attributeName, attrName);
|
|
685
|
+
state = State.attributeValueBegin;
|
|
686
|
+
}), _defineProperty(_State$attributeNameE, Action.gt, function() {
|
|
687
|
+
attrValue = "";
|
|
688
|
+
emit(Type.attributeName, attrName);
|
|
689
|
+
emit(Type.attributeValue, attrValue);
|
|
690
|
+
data = "";
|
|
691
|
+
state = State.data;
|
|
692
|
+
}), _defineProperty(_State$attributeNameE, Action.char, function(char) {
|
|
693
|
+
attrValue = "";
|
|
694
|
+
emit(Type.attributeName, attrName);
|
|
695
|
+
emit(Type.attributeValue, attrValue);
|
|
696
|
+
attrName = char;
|
|
697
|
+
state = State.attributeName;
|
|
698
|
+
}), _State$attributeNameE)), _defineProperty(_lexer$stateMachine, State.attributeValueBegin, (_State$attributeValue = {}, _defineProperty(_State$attributeValue, Action.space, noop), _defineProperty(_State$attributeValue, Action.quote, function(char) {
|
|
699
|
+
openingQuote = char;
|
|
700
|
+
attrValue = "";
|
|
701
|
+
state = State.attributeValue;
|
|
702
|
+
}), _defineProperty(_State$attributeValue, Action.gt, function() {
|
|
703
|
+
attrValue = "";
|
|
704
|
+
emit(Type.attributeValue, attrValue);
|
|
705
|
+
data = "";
|
|
706
|
+
state = State.data;
|
|
707
|
+
}), _defineProperty(_State$attributeValue, Action.char, function(char) {
|
|
708
|
+
openingQuote = "";
|
|
709
|
+
attrValue = char;
|
|
710
|
+
state = State.attributeValue;
|
|
711
|
+
}), _State$attributeValue)), _defineProperty(_lexer$stateMachine, State.attributeValue, (_State$attributeValue2 = {}, _defineProperty(_State$attributeValue2, Action.space, function(char) {
|
|
712
|
+
if (openingQuote) {
|
|
713
|
+
attrValue += char;
|
|
714
|
+
} else {
|
|
715
|
+
emit(Type.attributeValue, attrValue);
|
|
716
|
+
state = State.attributeNameStart;
|
|
717
|
+
}
|
|
718
|
+
}), _defineProperty(_State$attributeValue2, Action.quote, function(char) {
|
|
719
|
+
if (openingQuote === char) {
|
|
720
|
+
emit(Type.attributeValue, attrValue);
|
|
721
|
+
state = State.attributeNameStart;
|
|
722
|
+
} else {
|
|
723
|
+
attrValue += char;
|
|
724
|
+
}
|
|
725
|
+
}), _defineProperty(_State$attributeValue2, Action.gt, function(char) {
|
|
726
|
+
if (openingQuote) {
|
|
727
|
+
attrValue += char;
|
|
728
|
+
} else {
|
|
729
|
+
emit(Type.attributeValue, attrValue);
|
|
730
|
+
data = "";
|
|
731
|
+
state = State.data;
|
|
732
|
+
}
|
|
733
|
+
}), _defineProperty(_State$attributeValue2, Action.slash, function(char) {
|
|
734
|
+
if (openingQuote) {
|
|
735
|
+
attrValue += char;
|
|
736
|
+
} else {
|
|
737
|
+
emit(Type.attributeValue, attrValue);
|
|
738
|
+
isClosing = true;
|
|
739
|
+
state = State.tagEnd;
|
|
740
|
+
}
|
|
741
|
+
}), _defineProperty(_State$attributeValue2, Action.char, function(char) {
|
|
742
|
+
attrValue += char;
|
|
743
|
+
}), _State$attributeValue2)), _lexer$stateMachine);
|
|
744
|
+
var step = function step2(char) {
|
|
745
|
+
if (options.debug) {
|
|
746
|
+
console.log(state, char);
|
|
747
|
+
}
|
|
748
|
+
var actions = lexer.stateMachine[state];
|
|
749
|
+
var action = actions[getAction(char)] || actions[Action.error] || actions[Action.char];
|
|
750
|
+
action(char);
|
|
751
|
+
};
|
|
752
|
+
lexer.write = function(str) {
|
|
753
|
+
var len = str.length;
|
|
754
|
+
for (var i = 0; i < len; i++) {
|
|
755
|
+
step(str[i]);
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
return lexer;
|
|
759
|
+
};
|
|
760
|
+
module.exports = {
|
|
761
|
+
State,
|
|
762
|
+
Action,
|
|
763
|
+
Type,
|
|
764
|
+
create
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
// node_modules/xml-reader/dist/reader.js
|
|
770
|
+
var require_reader = __commonJS({
|
|
771
|
+
"node_modules/xml-reader/dist/reader.js"(exports, module) {
|
|
772
|
+
"use strict";
|
|
773
|
+
var EventEmitter = require_eventemitter3();
|
|
774
|
+
var Lexer = require_lexer();
|
|
775
|
+
var Type = Lexer.Type;
|
|
776
|
+
var NodeType = {
|
|
777
|
+
element: "element",
|
|
778
|
+
text: "text"
|
|
779
|
+
};
|
|
780
|
+
var createNode = function createNode2(params) {
|
|
781
|
+
return Object.assign({
|
|
782
|
+
name: "",
|
|
783
|
+
type: NodeType.element,
|
|
784
|
+
value: "",
|
|
785
|
+
parent: null,
|
|
786
|
+
attributes: {},
|
|
787
|
+
children: []
|
|
788
|
+
}, params);
|
|
789
|
+
};
|
|
790
|
+
var create = function create2(options) {
|
|
791
|
+
options = Object.assign({
|
|
792
|
+
stream: false,
|
|
793
|
+
parentNodes: true,
|
|
794
|
+
doneEvent: "done",
|
|
795
|
+
tagPrefix: "tag:",
|
|
796
|
+
emitTopLevelOnly: false,
|
|
797
|
+
debug: false
|
|
798
|
+
}, options);
|
|
799
|
+
var lexer = void 0, rootNode = void 0, current = void 0, attrName = void 0;
|
|
800
|
+
var reader = new EventEmitter();
|
|
801
|
+
var handleLexerData = function handleLexerData2(data) {
|
|
802
|
+
switch (data.type) {
|
|
803
|
+
case Type.openTag:
|
|
804
|
+
if (current === null) {
|
|
805
|
+
current = rootNode;
|
|
806
|
+
current.name = data.value;
|
|
807
|
+
} else {
|
|
808
|
+
var node = createNode({
|
|
809
|
+
name: data.value,
|
|
810
|
+
parent: current
|
|
811
|
+
});
|
|
812
|
+
current.children.push(node);
|
|
813
|
+
current = node;
|
|
814
|
+
}
|
|
815
|
+
break;
|
|
816
|
+
case Type.closeTag:
|
|
817
|
+
var parent = current.parent;
|
|
818
|
+
if (!options.parentNodes) {
|
|
819
|
+
current.parent = null;
|
|
820
|
+
}
|
|
821
|
+
if (current.name !== data.value) {
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
if (options.stream && parent === rootNode) {
|
|
825
|
+
rootNode.children = [];
|
|
826
|
+
current.parent = null;
|
|
827
|
+
}
|
|
828
|
+
if (!options.emitTopLevelOnly || parent === rootNode) {
|
|
829
|
+
reader.emit(options.tagPrefix + current.name, current);
|
|
830
|
+
reader.emit("tag", current.name, current);
|
|
831
|
+
}
|
|
832
|
+
if (current === rootNode) {
|
|
833
|
+
lexer.removeAllListeners("data");
|
|
834
|
+
reader.emit(options.doneEvent, current);
|
|
835
|
+
rootNode = null;
|
|
836
|
+
}
|
|
837
|
+
current = parent;
|
|
838
|
+
break;
|
|
839
|
+
case Type.text:
|
|
840
|
+
if (current) {
|
|
841
|
+
current.children.push(createNode({
|
|
842
|
+
type: NodeType.text,
|
|
843
|
+
value: data.value,
|
|
844
|
+
parent: options.parentNodes ? current : null
|
|
845
|
+
}));
|
|
846
|
+
}
|
|
847
|
+
break;
|
|
848
|
+
case Type.attributeName:
|
|
849
|
+
attrName = data.value;
|
|
850
|
+
current.attributes[attrName] = "";
|
|
851
|
+
break;
|
|
852
|
+
case Type.attributeValue:
|
|
853
|
+
current.attributes[attrName] = data.value;
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
reader.reset = function() {
|
|
858
|
+
lexer = Lexer.create({ debug: options.debug });
|
|
859
|
+
lexer.on("data", handleLexerData);
|
|
860
|
+
rootNode = createNode();
|
|
861
|
+
current = null;
|
|
862
|
+
attrName = "";
|
|
863
|
+
reader.parse = lexer.write;
|
|
864
|
+
};
|
|
865
|
+
reader.reset();
|
|
866
|
+
return reader;
|
|
867
|
+
};
|
|
868
|
+
var parseSync2 = function parseSync3(xml, options) {
|
|
869
|
+
options = Object.assign({}, options, { stream: false, tagPrefix: ":" });
|
|
870
|
+
var reader = create(options);
|
|
871
|
+
var res = void 0;
|
|
872
|
+
reader.on("done", function(ast) {
|
|
873
|
+
res = ast;
|
|
874
|
+
});
|
|
875
|
+
reader.parse(xml);
|
|
876
|
+
return res;
|
|
877
|
+
};
|
|
878
|
+
module.exports = {
|
|
879
|
+
parseSync: parseSync2,
|
|
880
|
+
create,
|
|
881
|
+
NodeType
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
// node_modules/transformation-matrix/src/rotate.js
|
|
887
|
+
var { cos, sin, PI } = Math;
|
|
888
|
+
|
|
889
|
+
// node_modules/transformation-matrix/src/skew.js
|
|
890
|
+
var { tan } = Math;
|
|
891
|
+
|
|
892
|
+
// node_modules/svgson/dist/svgson.esm.js
|
|
893
|
+
var import_deep_rename_keys = __toESM(require_deep_rename_keys());
|
|
894
|
+
var import_xml_reader = __toESM(require_reader());
|
|
895
|
+
|
|
896
|
+
// node_modules/@tscircuit/solver-utils/dist/index.js
|
|
897
|
+
var BaseSolver = class {
|
|
898
|
+
MAX_ITERATIONS = 1e5;
|
|
899
|
+
solved = false;
|
|
900
|
+
failed = false;
|
|
901
|
+
iterations = 0;
|
|
902
|
+
progress = 0;
|
|
903
|
+
error = null;
|
|
904
|
+
activeSubSolver;
|
|
905
|
+
failedSubSolvers;
|
|
906
|
+
timeToSolve;
|
|
907
|
+
stats = {};
|
|
908
|
+
_setupDone = false;
|
|
909
|
+
setup() {
|
|
910
|
+
if (this._setupDone) return;
|
|
911
|
+
this._setup();
|
|
912
|
+
this._setupDone = true;
|
|
913
|
+
}
|
|
914
|
+
/** Override this method to perform setup logic */
|
|
915
|
+
_setup() {
|
|
916
|
+
}
|
|
917
|
+
/** DO NOT OVERRIDE! Override _step() instead */
|
|
918
|
+
step() {
|
|
919
|
+
if (!this._setupDone) {
|
|
920
|
+
this.setup();
|
|
921
|
+
}
|
|
922
|
+
if (this.solved) return;
|
|
923
|
+
if (this.failed) return;
|
|
924
|
+
this.iterations++;
|
|
925
|
+
try {
|
|
926
|
+
this._step();
|
|
927
|
+
} catch (e) {
|
|
928
|
+
this.error = `${this.constructor.name} error: ${e}`;
|
|
929
|
+
this.failed = true;
|
|
930
|
+
throw e;
|
|
931
|
+
}
|
|
932
|
+
if (!this.solved && this.iterations >= this.MAX_ITERATIONS) {
|
|
933
|
+
this.tryFinalAcceptance();
|
|
934
|
+
}
|
|
935
|
+
if (!this.solved && this.iterations >= this.MAX_ITERATIONS) {
|
|
936
|
+
this.error = `${this.constructor.name} ran out of iterations`;
|
|
937
|
+
this.failed = true;
|
|
938
|
+
}
|
|
939
|
+
if ("computeProgress" in this) {
|
|
940
|
+
this.progress = this.computeProgress();
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
/** Override this method to implement solver logic */
|
|
944
|
+
_step() {
|
|
945
|
+
}
|
|
946
|
+
getConstructorParams() {
|
|
947
|
+
throw new Error("getConstructorParams not implemented");
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Override this method to return the standardized output of the solver.
|
|
951
|
+
* This method should only be called after the solver has completed successfully.
|
|
952
|
+
* Returns null by default - solvers with outputs should override this method.
|
|
953
|
+
*/
|
|
954
|
+
getOutput() {
|
|
955
|
+
return null;
|
|
956
|
+
}
|
|
957
|
+
solve() {
|
|
958
|
+
const startTime = Date.now();
|
|
959
|
+
while (!this.solved && !this.failed) {
|
|
960
|
+
this.step();
|
|
961
|
+
}
|
|
962
|
+
const endTime = Date.now();
|
|
963
|
+
this.timeToSolve = endTime - startTime;
|
|
964
|
+
}
|
|
965
|
+
visualize() {
|
|
966
|
+
return {
|
|
967
|
+
lines: [],
|
|
968
|
+
points: [],
|
|
969
|
+
rects: [],
|
|
970
|
+
circles: []
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Called when the solver is about to fail, but we want to see if we have an
|
|
975
|
+
* "acceptable" or "passable" solution. Mostly used for optimizers that
|
|
976
|
+
* have an aggressive early stopping criterion.
|
|
977
|
+
*/
|
|
978
|
+
tryFinalAcceptance() {
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* A lightweight version of the visualize method that can be used to stream
|
|
982
|
+
* progress
|
|
983
|
+
*/
|
|
984
|
+
preview() {
|
|
985
|
+
return {
|
|
986
|
+
lines: [],
|
|
987
|
+
points: [],
|
|
988
|
+
rects: [],
|
|
989
|
+
circles: []
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
// lib/visualization-utils/visualizeCurvyTraceProblem.ts
|
|
995
|
+
var visualizeCurvyTraceProblem = (problem, outputTraces = []) => {
|
|
996
|
+
const graphics = {
|
|
997
|
+
arrows: [],
|
|
998
|
+
circles: [],
|
|
999
|
+
lines: [],
|
|
1000
|
+
rects: [],
|
|
1001
|
+
coordinateSystem: "cartesian",
|
|
1002
|
+
points: [],
|
|
1003
|
+
texts: [],
|
|
1004
|
+
title: "Curvy Trace Problem"
|
|
1005
|
+
};
|
|
1006
|
+
graphics.lines.push({
|
|
1007
|
+
points: [
|
|
1008
|
+
{ x: problem.bounds.minX, y: problem.bounds.minY },
|
|
1009
|
+
{ x: problem.bounds.maxX, y: problem.bounds.minY },
|
|
1010
|
+
{ x: problem.bounds.maxX, y: problem.bounds.maxY },
|
|
1011
|
+
{ x: problem.bounds.minX, y: problem.bounds.maxY },
|
|
1012
|
+
{ x: problem.bounds.minX, y: problem.bounds.minY }
|
|
1013
|
+
],
|
|
1014
|
+
strokeColor: "rgba(0, 0, 0, 0.1)"
|
|
1015
|
+
});
|
|
1016
|
+
for (const waypointPair of problem.waypointPairs) {
|
|
1017
|
+
graphics.points.push({
|
|
1018
|
+
...waypointPair.start,
|
|
1019
|
+
label: `start ${waypointPair.networkId ?? ""}`,
|
|
1020
|
+
color: getColorForNetworkId(waypointPair.networkId)
|
|
1021
|
+
});
|
|
1022
|
+
graphics.points.push({
|
|
1023
|
+
...waypointPair.end,
|
|
1024
|
+
label: `end ${waypointPair.networkId ?? ""}`,
|
|
1025
|
+
color: getColorForNetworkId(waypointPair.networkId)
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
for (const obstacle of problem.obstacles) {
|
|
1029
|
+
graphics.rects.push({
|
|
1030
|
+
center: obstacle.center,
|
|
1031
|
+
width: obstacle.maxX - obstacle.minX,
|
|
1032
|
+
height: obstacle.maxY - obstacle.minY,
|
|
1033
|
+
fill: "rgba(128, 128, 128, 0.3)",
|
|
1034
|
+
stroke: "rgba(128, 128, 128, 0.8)"
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
for (const trace of outputTraces) {
|
|
1038
|
+
graphics.lines.push({
|
|
1039
|
+
points: trace.points,
|
|
1040
|
+
strokeColor: getColorForNetworkId(trace.networkId)
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
return graphics;
|
|
1044
|
+
};
|
|
1045
|
+
|
|
1046
|
+
// lib/visualization-utils/index.ts
|
|
1047
|
+
var hashString = (str) => {
|
|
1048
|
+
let hash = 0;
|
|
1049
|
+
for (let i = 0; i < str.length; i++) {
|
|
1050
|
+
hash = str.charCodeAt(i) * 779 + ((hash << 5) - hash);
|
|
1051
|
+
}
|
|
1052
|
+
return hash;
|
|
1053
|
+
};
|
|
1054
|
+
var getColorForNetworkId = (networkId) => {
|
|
1055
|
+
if (!networkId) return "rgba(0, 0, 0, 0.5)";
|
|
1056
|
+
return `hsl(${hashString(networkId) % 360}, 100%, 50%)`;
|
|
1057
|
+
};
|
|
1058
|
+
|
|
1059
|
+
// lib/geometry/getObstacleOuterSegments.ts
|
|
1060
|
+
var getObstacleOuterSegments = (obstacle) => {
|
|
1061
|
+
const segments = [
|
|
1062
|
+
[
|
|
1063
|
+
{ x: obstacle.minX, y: obstacle.minY },
|
|
1064
|
+
{ x: obstacle.maxX, y: obstacle.minY }
|
|
1065
|
+
],
|
|
1066
|
+
[
|
|
1067
|
+
{ x: obstacle.maxX, y: obstacle.minY },
|
|
1068
|
+
{ x: obstacle.maxX, y: obstacle.maxY }
|
|
1069
|
+
],
|
|
1070
|
+
[
|
|
1071
|
+
{ x: obstacle.maxX, y: obstacle.maxY },
|
|
1072
|
+
{ x: obstacle.minX, y: obstacle.maxY }
|
|
1073
|
+
],
|
|
1074
|
+
[
|
|
1075
|
+
{ x: obstacle.minX, y: obstacle.maxY },
|
|
1076
|
+
{ x: obstacle.minX, y: obstacle.minY }
|
|
1077
|
+
]
|
|
1078
|
+
];
|
|
1079
|
+
return segments;
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
// lib/CurvyTraceSolver.ts
|
|
1083
|
+
function getPerimeterT(p, bounds) {
|
|
1084
|
+
const { minX, maxX, minY, maxY } = bounds;
|
|
1085
|
+
const W = maxX - minX;
|
|
1086
|
+
const H = maxY - minY;
|
|
1087
|
+
const eps = 1e-6;
|
|
1088
|
+
if (Math.abs(p.y - maxY) < eps) return p.x - minX;
|
|
1089
|
+
if (Math.abs(p.x - maxX) < eps) return W + (maxY - p.y);
|
|
1090
|
+
if (Math.abs(p.y - minY) < eps) return W + H + (maxX - p.x);
|
|
1091
|
+
if (Math.abs(p.x - minX) < eps) return 2 * W + H + (p.y - minY);
|
|
1092
|
+
return 0;
|
|
1093
|
+
}
|
|
1094
|
+
function getPerimeterPoint(t, bounds) {
|
|
1095
|
+
const { minX, maxX, minY, maxY } = bounds;
|
|
1096
|
+
const W = maxX - minX;
|
|
1097
|
+
const H = maxY - minY;
|
|
1098
|
+
const perimeter = 2 * W + 2 * H;
|
|
1099
|
+
t = (t % perimeter + perimeter) % perimeter;
|
|
1100
|
+
if (t <= W) return { x: minX + t, y: maxY };
|
|
1101
|
+
if (t <= W + H) return { x: maxX, y: maxY - (t - W) };
|
|
1102
|
+
if (t <= 2 * W + H) return { x: maxX - (t - W - H), y: minY };
|
|
1103
|
+
return { x: minX, y: minY + (t - 2 * W - H) };
|
|
1104
|
+
}
|
|
1105
|
+
function sampleCubicBezierInline(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, points, numSamples) {
|
|
1106
|
+
for (let i = 0; i <= numSamples; i++) {
|
|
1107
|
+
const t = i / numSamples;
|
|
1108
|
+
const mt = 1 - t;
|
|
1109
|
+
const mt2 = mt * mt;
|
|
1110
|
+
const mt3 = mt2 * mt;
|
|
1111
|
+
const t2 = t * t;
|
|
1112
|
+
const t3 = t2 * t;
|
|
1113
|
+
const idx = i * 2;
|
|
1114
|
+
points[idx] = mt3 * p0x + 3 * mt2 * t * p1x + 3 * mt * t2 * p2x + t3 * p3x;
|
|
1115
|
+
points[idx + 1] = mt3 * p0y + 3 * mt2 * t * p1y + 3 * mt * t2 * p2y + t3 * p3y;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
function sampleCubicBezier(p0, p1, p2, p3, numSamples) {
|
|
1119
|
+
const points = [];
|
|
1120
|
+
for (let i = 0; i <= numSamples; i++) {
|
|
1121
|
+
const t = i / numSamples;
|
|
1122
|
+
const mt = 1 - t;
|
|
1123
|
+
const mt2 = mt * mt;
|
|
1124
|
+
const mt3 = mt2 * mt;
|
|
1125
|
+
const t2 = t * t;
|
|
1126
|
+
const t3 = t2 * t;
|
|
1127
|
+
points.push({
|
|
1128
|
+
x: mt3 * p0.x + 3 * mt2 * t * p1.x + 3 * mt * t2 * p2.x + t3 * p3.x,
|
|
1129
|
+
y: mt3 * p0.y + 3 * mt2 * t * p1.y + 3 * mt * t2 * p2.y + t3 * p3.y
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
return points;
|
|
1133
|
+
}
|
|
1134
|
+
function ptSegDistSq(px, py, sx, sy, ex, ey) {
|
|
1135
|
+
const dx = ex - sx;
|
|
1136
|
+
const dy = ey - sy;
|
|
1137
|
+
const lenSq = dx * dx + dy * dy;
|
|
1138
|
+
if (lenSq === 0) {
|
|
1139
|
+
const dpx2 = px - sx;
|
|
1140
|
+
const dpy2 = py - sy;
|
|
1141
|
+
return dpx2 * dpx2 + dpy2 * dpy2;
|
|
1142
|
+
}
|
|
1143
|
+
const t = Math.max(0, Math.min(1, ((px - sx) * dx + (py - sy) * dy) / lenSq));
|
|
1144
|
+
const projX = sx + t * dx;
|
|
1145
|
+
const projY = sy + t * dy;
|
|
1146
|
+
const dpx = px - projX;
|
|
1147
|
+
const dpy = py - projY;
|
|
1148
|
+
return dpx * dpx + dpy * dpy;
|
|
1149
|
+
}
|
|
1150
|
+
function segmentDistSq(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) {
|
|
1151
|
+
const d1 = (b2x - b1x) * (a1y - b1y) - (b2y - b1y) * (a1x - b1x);
|
|
1152
|
+
const d2 = (b2x - b1x) * (a2y - b1y) - (b2y - b1y) * (a2x - b1x);
|
|
1153
|
+
const d3 = (a2x - a1x) * (b1y - a1y) - (a2y - a1y) * (b1x - a1x);
|
|
1154
|
+
const d4 = (a2x - a1x) * (b2y - a1y) - (a2y - a1y) * (b2x - a1x);
|
|
1155
|
+
if ((d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0)) {
|
|
1156
|
+
return 0;
|
|
1157
|
+
}
|
|
1158
|
+
return Math.min(
|
|
1159
|
+
ptSegDistSq(a1x, a1y, b1x, b1y, b2x, b2y),
|
|
1160
|
+
ptSegDistSq(a2x, a2y, b1x, b1y, b2x, b2y),
|
|
1161
|
+
ptSegDistSq(b1x, b1y, a1x, a1y, a2x, a2y),
|
|
1162
|
+
ptSegDistSq(b2x, b2y, a1x, a1y, a2x, a2y)
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
function chordContains(aT1, aT2, bT1, bT2, perimeter) {
|
|
1166
|
+
const normalize = (t) => (t % perimeter + perimeter) % perimeter;
|
|
1167
|
+
const a1 = normalize(aT1), a2 = normalize(aT2);
|
|
1168
|
+
const b1 = normalize(bT1), b2 = normalize(bT2);
|
|
1169
|
+
const [aMin, aMax] = a1 < a2 ? [a1, a2] : [a2, a1];
|
|
1170
|
+
return b1 > aMin && b1 < aMax && b2 > aMin && b2 < aMax;
|
|
1171
|
+
}
|
|
1172
|
+
function getBoundsCenter(bounds) {
|
|
1173
|
+
return {
|
|
1174
|
+
x: (bounds.minX + bounds.maxX) / 2,
|
|
1175
|
+
y: (bounds.minY + bounds.maxY) / 2
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
function computeTraceBounds(points, numPoints) {
|
|
1179
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
1180
|
+
for (let i = 0; i < numPoints; i++) {
|
|
1181
|
+
const x = points[i * 2], y = points[i * 2 + 1];
|
|
1182
|
+
if (x < minX) minX = x;
|
|
1183
|
+
if (x > maxX) maxX = x;
|
|
1184
|
+
if (y < minY) minY = y;
|
|
1185
|
+
if (y > maxY) maxY = y;
|
|
1186
|
+
}
|
|
1187
|
+
return { minX, maxX, minY, maxY };
|
|
1188
|
+
}
|
|
1189
|
+
var OPT_SAMPLES = 5;
|
|
1190
|
+
var OUTPUT_SAMPLES = 20;
|
|
1191
|
+
var CurvyTraceSolver = class extends BaseSolver {
|
|
1192
|
+
constructor(problem) {
|
|
1193
|
+
super();
|
|
1194
|
+
this.problem = problem;
|
|
1195
|
+
for (const obstacle of this.problem.obstacles) {
|
|
1196
|
+
obstacle.outerSegments = getObstacleOuterSegments(obstacle);
|
|
1197
|
+
}
|
|
1198
|
+
this.precomputeObstacles();
|
|
1199
|
+
}
|
|
1200
|
+
outputTraces = [];
|
|
1201
|
+
traces = [];
|
|
1202
|
+
optimizationStep = 0;
|
|
1203
|
+
maxOptimizationSteps = 100;
|
|
1204
|
+
// Typed arrays for faster sampling
|
|
1205
|
+
sampledPoints = [];
|
|
1206
|
+
traceBounds = [];
|
|
1207
|
+
// Pre-computed obstacle segments as flat arrays
|
|
1208
|
+
obstacleSegments = new Float64Array(0);
|
|
1209
|
+
obstacleNetworkIds = [];
|
|
1210
|
+
numObstacleSegments = 0;
|
|
1211
|
+
// Collision pairs cache - which traces can possibly collide
|
|
1212
|
+
collisionPairs = [];
|
|
1213
|
+
lastCost = Infinity;
|
|
1214
|
+
stagnantSteps = 0;
|
|
1215
|
+
getConstructorParams() {
|
|
1216
|
+
return this.problem;
|
|
1217
|
+
}
|
|
1218
|
+
precomputeObstacles() {
|
|
1219
|
+
const { obstacles } = this.problem;
|
|
1220
|
+
let totalSegments = 0;
|
|
1221
|
+
for (const obs of obstacles) {
|
|
1222
|
+
if (obs.outerSegments) totalSegments += obs.outerSegments.length;
|
|
1223
|
+
}
|
|
1224
|
+
this.obstacleSegments = new Float64Array(totalSegments * 4);
|
|
1225
|
+
this.obstacleNetworkIds = [];
|
|
1226
|
+
this.numObstacleSegments = totalSegments;
|
|
1227
|
+
let idx = 0;
|
|
1228
|
+
for (const obs of obstacles) {
|
|
1229
|
+
if (obs.outerSegments) {
|
|
1230
|
+
for (const seg of obs.outerSegments) {
|
|
1231
|
+
this.obstacleSegments[idx++] = seg[0].x;
|
|
1232
|
+
this.obstacleSegments[idx++] = seg[0].y;
|
|
1233
|
+
this.obstacleSegments[idx++] = seg[1].x;
|
|
1234
|
+
this.obstacleSegments[idx++] = seg[1].y;
|
|
1235
|
+
this.obstacleNetworkIds.push(obs.networkId);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
initializeTraces() {
|
|
1241
|
+
const { bounds, waypointPairs } = this.problem;
|
|
1242
|
+
const { minX, maxX, minY, maxY } = bounds;
|
|
1243
|
+
const W = maxX - minX;
|
|
1244
|
+
const H = maxY - minY;
|
|
1245
|
+
const perimeter = 2 * W + 2 * H;
|
|
1246
|
+
const center = getBoundsCenter(bounds);
|
|
1247
|
+
const tracesWithT = waypointPairs.map((pair, idx) => ({
|
|
1248
|
+
pair,
|
|
1249
|
+
t1: getPerimeterT(pair.start, bounds),
|
|
1250
|
+
t2: getPerimeterT(pair.end, bounds),
|
|
1251
|
+
idx
|
|
1252
|
+
}));
|
|
1253
|
+
const nestingDepth = /* @__PURE__ */ new Map();
|
|
1254
|
+
for (const trace of tracesWithT) {
|
|
1255
|
+
let depth = 0;
|
|
1256
|
+
for (const other of tracesWithT) {
|
|
1257
|
+
if (trace.idx !== other.idx && chordContains(other.t1, other.t2, trace.t1, trace.t2, perimeter)) {
|
|
1258
|
+
depth++;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
nestingDepth.set(trace.idx, depth);
|
|
1262
|
+
}
|
|
1263
|
+
const maxDepth = Math.max(...Array.from(nestingDepth.values()), 1);
|
|
1264
|
+
this.traces = tracesWithT.map(({ pair, t1, t2, idx }) => {
|
|
1265
|
+
let dt = t2 - t1;
|
|
1266
|
+
if (dt > perimeter / 2) dt -= perimeter;
|
|
1267
|
+
if (dt < -perimeter / 2) dt += perimeter;
|
|
1268
|
+
const tCtrl1 = t1 + dt * 0.33;
|
|
1269
|
+
const tCtrl2 = t1 + dt * 0.67;
|
|
1270
|
+
const pPerim1 = getPerimeterPoint(tCtrl1, bounds);
|
|
1271
|
+
const pPerim2 = getPerimeterPoint(tCtrl2, bounds);
|
|
1272
|
+
const pLinear1 = {
|
|
1273
|
+
x: pair.start.x + (pair.end.x - pair.start.x) * 0.33,
|
|
1274
|
+
y: pair.start.y + (pair.end.y - pair.start.y) * 0.33
|
|
1275
|
+
};
|
|
1276
|
+
const pLinear2 = {
|
|
1277
|
+
x: pair.start.x + (pair.end.x - pair.start.x) * 0.67,
|
|
1278
|
+
y: pair.start.y + (pair.end.y - pair.start.y) * 0.67
|
|
1279
|
+
};
|
|
1280
|
+
const midPoint = {
|
|
1281
|
+
x: (pair.start.x + pair.end.x) / 2,
|
|
1282
|
+
y: (pair.start.y + pair.end.y) / 2
|
|
1283
|
+
};
|
|
1284
|
+
const distToCenter = Math.hypot(
|
|
1285
|
+
midPoint.x - center.x,
|
|
1286
|
+
midPoint.y - center.y
|
|
1287
|
+
);
|
|
1288
|
+
const maxDist = Math.hypot(W / 2, H / 2);
|
|
1289
|
+
const spatialDepth = 1 - distToCenter / maxDist;
|
|
1290
|
+
const depth = nestingDepth.get(idx) || 0;
|
|
1291
|
+
const normalizedDepth = depth / maxDepth;
|
|
1292
|
+
const basePull = 0.3 + spatialDepth * 0.4;
|
|
1293
|
+
const pullAmount = Math.max(0.05, basePull - normalizedDepth * 0.2);
|
|
1294
|
+
return {
|
|
1295
|
+
waypointPair: pair,
|
|
1296
|
+
ctrl1: {
|
|
1297
|
+
x: pLinear1.x * (1 - pullAmount) + pPerim1.x * pullAmount,
|
|
1298
|
+
y: pLinear1.y * (1 - pullAmount) + pPerim1.y * pullAmount
|
|
1299
|
+
},
|
|
1300
|
+
ctrl2: {
|
|
1301
|
+
x: pLinear2.x * (1 - pullAmount) + pPerim2.x * pullAmount,
|
|
1302
|
+
y: pLinear2.y * (1 - pullAmount) + pPerim2.y * pullAmount
|
|
1303
|
+
},
|
|
1304
|
+
networkId: pair.networkId,
|
|
1305
|
+
t1,
|
|
1306
|
+
t2
|
|
1307
|
+
};
|
|
1308
|
+
});
|
|
1309
|
+
this.sampledPoints = this.traces.map(
|
|
1310
|
+
() => new Float64Array((OPT_SAMPLES + 1) * 2)
|
|
1311
|
+
);
|
|
1312
|
+
this.traceBounds = this.traces.map(() => ({
|
|
1313
|
+
minX: 0,
|
|
1314
|
+
maxX: 0,
|
|
1315
|
+
minY: 0,
|
|
1316
|
+
maxY: 0
|
|
1317
|
+
}));
|
|
1318
|
+
this.updateSampledTraces();
|
|
1319
|
+
this.updateCollisionPairs();
|
|
1320
|
+
}
|
|
1321
|
+
updateSampledTraces() {
|
|
1322
|
+
for (let i = 0; i < this.traces.length; i++) {
|
|
1323
|
+
const trace = this.traces[i];
|
|
1324
|
+
sampleCubicBezierInline(
|
|
1325
|
+
trace.waypointPair.start.x,
|
|
1326
|
+
trace.waypointPair.start.y,
|
|
1327
|
+
trace.ctrl1.x,
|
|
1328
|
+
trace.ctrl1.y,
|
|
1329
|
+
trace.ctrl2.x,
|
|
1330
|
+
trace.ctrl2.y,
|
|
1331
|
+
trace.waypointPair.end.x,
|
|
1332
|
+
trace.waypointPair.end.y,
|
|
1333
|
+
this.sampledPoints[i],
|
|
1334
|
+
OPT_SAMPLES
|
|
1335
|
+
);
|
|
1336
|
+
this.traceBounds[i] = computeTraceBounds(
|
|
1337
|
+
this.sampledPoints[i],
|
|
1338
|
+
OPT_SAMPLES + 1
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
updateSingleTraceSample(i) {
|
|
1343
|
+
const trace = this.traces[i];
|
|
1344
|
+
sampleCubicBezierInline(
|
|
1345
|
+
trace.waypointPair.start.x,
|
|
1346
|
+
trace.waypointPair.start.y,
|
|
1347
|
+
trace.ctrl1.x,
|
|
1348
|
+
trace.ctrl1.y,
|
|
1349
|
+
trace.ctrl2.x,
|
|
1350
|
+
trace.ctrl2.y,
|
|
1351
|
+
trace.waypointPair.end.x,
|
|
1352
|
+
trace.waypointPair.end.y,
|
|
1353
|
+
this.sampledPoints[i],
|
|
1354
|
+
OPT_SAMPLES
|
|
1355
|
+
);
|
|
1356
|
+
this.traceBounds[i] = computeTraceBounds(
|
|
1357
|
+
this.sampledPoints[i],
|
|
1358
|
+
OPT_SAMPLES + 1
|
|
1359
|
+
);
|
|
1360
|
+
}
|
|
1361
|
+
// Determine which trace pairs could possibly collide based on bounding boxes
|
|
1362
|
+
updateCollisionPairs() {
|
|
1363
|
+
const { preferredSpacing } = this.problem;
|
|
1364
|
+
this.collisionPairs = [];
|
|
1365
|
+
for (let i = 0; i < this.traces.length; i++) {
|
|
1366
|
+
for (let j = i + 1; j < this.traces.length; j++) {
|
|
1367
|
+
const ti = this.traces[i], tj = this.traces[j];
|
|
1368
|
+
if (ti.networkId && tj.networkId && ti.networkId === tj.networkId)
|
|
1369
|
+
continue;
|
|
1370
|
+
const bi = this.traceBounds[i], bj = this.traceBounds[j];
|
|
1371
|
+
if (bi.maxX + preferredSpacing >= bj.minX && bj.maxX + preferredSpacing >= bi.minX && bi.maxY + preferredSpacing >= bj.minY && bj.maxY + preferredSpacing >= bi.minY) {
|
|
1372
|
+
this.collisionPairs.push([i, j]);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
computeTotalCost() {
|
|
1378
|
+
const { preferredSpacing } = this.problem;
|
|
1379
|
+
const spacingSq = preferredSpacing * preferredSpacing;
|
|
1380
|
+
let cost = 0;
|
|
1381
|
+
for (const [i, j] of this.collisionPairs) {
|
|
1382
|
+
const pi = this.sampledPoints[i], pj = this.sampledPoints[j];
|
|
1383
|
+
for (let a = 0; a < OPT_SAMPLES; a++) {
|
|
1384
|
+
const a1x = pi[a * 2], a1y = pi[a * 2 + 1];
|
|
1385
|
+
const a2x = pi[(a + 1) * 2], a2y = pi[(a + 1) * 2 + 1];
|
|
1386
|
+
for (let b = 0; b < OPT_SAMPLES; b++) {
|
|
1387
|
+
const b1x = pj[b * 2], b1y = pj[b * 2 + 1];
|
|
1388
|
+
const b2x = pj[(b + 1) * 2], b2y = pj[(b + 1) * 2 + 1];
|
|
1389
|
+
const distSq = segmentDistSq(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y);
|
|
1390
|
+
if (distSq < spacingSq) {
|
|
1391
|
+
const dist = Math.sqrt(distSq);
|
|
1392
|
+
cost += (preferredSpacing - dist) ** 2;
|
|
1393
|
+
if (distSq < 1e-18) cost += 20 * spacingSq;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
for (let i = 0; i < this.traces.length; i++) {
|
|
1399
|
+
const trace = this.traces[i];
|
|
1400
|
+
const pi = this.sampledPoints[i];
|
|
1401
|
+
const bi = this.traceBounds[i];
|
|
1402
|
+
for (let obsIdx = 0; obsIdx < this.numObstacleSegments; obsIdx++) {
|
|
1403
|
+
if (trace.networkId && this.obstacleNetworkIds[obsIdx] && trace.networkId === this.obstacleNetworkIds[obsIdx])
|
|
1404
|
+
continue;
|
|
1405
|
+
const obsBase = obsIdx * 4;
|
|
1406
|
+
const ox1 = this.obstacleSegments[obsBase];
|
|
1407
|
+
const oy1 = this.obstacleSegments[obsBase + 1];
|
|
1408
|
+
const ox2 = this.obstacleSegments[obsBase + 2];
|
|
1409
|
+
const oy2 = this.obstacleSegments[obsBase + 3];
|
|
1410
|
+
const obsMinX = Math.min(ox1, ox2), obsMaxX = Math.max(ox1, ox2);
|
|
1411
|
+
const obsMinY = Math.min(oy1, oy2), obsMaxY = Math.max(oy1, oy2);
|
|
1412
|
+
if (bi.maxX + preferredSpacing < obsMinX || obsMaxX + preferredSpacing < bi.minX || bi.maxY + preferredSpacing < obsMinY || obsMaxY + preferredSpacing < bi.minY)
|
|
1413
|
+
continue;
|
|
1414
|
+
for (let a = 0; a < OPT_SAMPLES; a++) {
|
|
1415
|
+
const a1x = pi[a * 2], a1y = pi[a * 2 + 1];
|
|
1416
|
+
const a2x = pi[(a + 1) * 2], a2y = pi[(a + 1) * 2 + 1];
|
|
1417
|
+
const distSq = segmentDistSq(a1x, a1y, a2x, a2y, ox1, oy1, ox2, oy2);
|
|
1418
|
+
if (distSq < spacingSq) {
|
|
1419
|
+
const dist = Math.sqrt(distSq);
|
|
1420
|
+
cost += (preferredSpacing - dist) ** 2;
|
|
1421
|
+
if (distSq < 1e-18) cost += 20 * spacingSq;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
return cost;
|
|
1427
|
+
}
|
|
1428
|
+
computeCostForTrace(traceIdx) {
|
|
1429
|
+
const { preferredSpacing } = this.problem;
|
|
1430
|
+
const spacingSq = preferredSpacing * preferredSpacing;
|
|
1431
|
+
const trace = this.traces[traceIdx];
|
|
1432
|
+
const pi = this.sampledPoints[traceIdx];
|
|
1433
|
+
const bi = this.traceBounds[traceIdx];
|
|
1434
|
+
let cost = 0;
|
|
1435
|
+
for (let j = 0; j < this.traces.length; j++) {
|
|
1436
|
+
if (j === traceIdx) continue;
|
|
1437
|
+
const other = this.traces[j];
|
|
1438
|
+
if (trace.networkId && other.networkId && trace.networkId === other.networkId)
|
|
1439
|
+
continue;
|
|
1440
|
+
const bj = this.traceBounds[j];
|
|
1441
|
+
if (bi.maxX + preferredSpacing < bj.minX || bj.maxX + preferredSpacing < bi.minX || bi.maxY + preferredSpacing < bj.minY || bj.maxY + preferredSpacing < bi.minY)
|
|
1442
|
+
continue;
|
|
1443
|
+
const pj = this.sampledPoints[j];
|
|
1444
|
+
for (let a = 0; a < OPT_SAMPLES; a++) {
|
|
1445
|
+
const a1x = pi[a * 2], a1y = pi[a * 2 + 1];
|
|
1446
|
+
const a2x = pi[(a + 1) * 2], a2y = pi[(a + 1) * 2 + 1];
|
|
1447
|
+
for (let b = 0; b < OPT_SAMPLES; b++) {
|
|
1448
|
+
const b1x = pj[b * 2], b1y = pj[b * 2 + 1];
|
|
1449
|
+
const b2x = pj[(b + 1) * 2], b2y = pj[(b + 1) * 2 + 1];
|
|
1450
|
+
const distSq = segmentDistSq(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y);
|
|
1451
|
+
if (distSq < spacingSq) {
|
|
1452
|
+
const dist = Math.sqrt(distSq);
|
|
1453
|
+
cost += (preferredSpacing - dist) ** 2;
|
|
1454
|
+
if (distSq < 1e-18) cost += 20 * spacingSq;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
for (let obsIdx = 0; obsIdx < this.numObstacleSegments; obsIdx++) {
|
|
1460
|
+
if (trace.networkId && this.obstacleNetworkIds[obsIdx] && trace.networkId === this.obstacleNetworkIds[obsIdx])
|
|
1461
|
+
continue;
|
|
1462
|
+
const obsBase = obsIdx * 4;
|
|
1463
|
+
const ox1 = this.obstacleSegments[obsBase];
|
|
1464
|
+
const oy1 = this.obstacleSegments[obsBase + 1];
|
|
1465
|
+
const ox2 = this.obstacleSegments[obsBase + 2];
|
|
1466
|
+
const oy2 = this.obstacleSegments[obsBase + 3];
|
|
1467
|
+
const obsMinX = Math.min(ox1, ox2), obsMaxX = Math.max(ox1, ox2);
|
|
1468
|
+
const obsMinY = Math.min(oy1, oy2), obsMaxY = Math.max(oy1, oy2);
|
|
1469
|
+
if (bi.maxX + preferredSpacing < obsMinX || obsMaxX + preferredSpacing < bi.minX || bi.maxY + preferredSpacing < obsMinY || obsMaxY + preferredSpacing < bi.minY)
|
|
1470
|
+
continue;
|
|
1471
|
+
for (let a = 0; a < OPT_SAMPLES; a++) {
|
|
1472
|
+
const a1x = pi[a * 2], a1y = pi[a * 2 + 1];
|
|
1473
|
+
const a2x = pi[(a + 1) * 2], a2y = pi[(a + 1) * 2 + 1];
|
|
1474
|
+
const distSq = segmentDistSq(a1x, a1y, a2x, a2y, ox1, oy1, ox2, oy2);
|
|
1475
|
+
if (distSq < spacingSq) {
|
|
1476
|
+
const dist = Math.sqrt(distSq);
|
|
1477
|
+
cost += (preferredSpacing - dist) ** 2;
|
|
1478
|
+
if (distSq < 1e-18) cost += 20 * spacingSq;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
return cost;
|
|
1483
|
+
}
|
|
1484
|
+
optimizeStep() {
|
|
1485
|
+
const { bounds } = this.problem;
|
|
1486
|
+
const { minX, maxX, minY, maxY } = bounds;
|
|
1487
|
+
const progress = this.optimizationStep / this.maxOptimizationSteps;
|
|
1488
|
+
const baseStep = 3.5 * (1 - progress) + 0.5;
|
|
1489
|
+
const SQRT1_2 = Math.SQRT1_2;
|
|
1490
|
+
const traceCosts = [];
|
|
1491
|
+
for (let i = 0; i < this.traces.length; i++) {
|
|
1492
|
+
traceCosts.push({ idx: i, cost: this.computeCostForTrace(i) });
|
|
1493
|
+
}
|
|
1494
|
+
traceCosts.sort((a, b) => b.cost - a.cost);
|
|
1495
|
+
for (const { idx: i, cost: currentCost } of traceCosts) {
|
|
1496
|
+
if (currentCost === 0) continue;
|
|
1497
|
+
const trace = this.traces[i];
|
|
1498
|
+
const steps = [baseStep, baseStep * 1.5, baseStep * 0.5];
|
|
1499
|
+
for (const step of steps) {
|
|
1500
|
+
const directions = [
|
|
1501
|
+
{ dx: step, dy: 0 },
|
|
1502
|
+
{ dx: -step, dy: 0 },
|
|
1503
|
+
{ dx: 0, dy: step },
|
|
1504
|
+
{ dx: 0, dy: -step },
|
|
1505
|
+
{ dx: step * SQRT1_2, dy: step * SQRT1_2 },
|
|
1506
|
+
{ dx: -step * SQRT1_2, dy: -step * SQRT1_2 },
|
|
1507
|
+
{ dx: step * SQRT1_2, dy: -step * SQRT1_2 },
|
|
1508
|
+
{ dx: -step * SQRT1_2, dy: step * SQRT1_2 }
|
|
1509
|
+
];
|
|
1510
|
+
let bestCost = this.computeCostForTrace(i);
|
|
1511
|
+
let bestCtrl1x = trace.ctrl1.x;
|
|
1512
|
+
let bestCtrl1y = trace.ctrl1.y;
|
|
1513
|
+
let bestCtrl2x = trace.ctrl2.x;
|
|
1514
|
+
let bestCtrl2y = trace.ctrl2.y;
|
|
1515
|
+
const origCtrl1x = trace.ctrl1.x;
|
|
1516
|
+
const origCtrl1y = trace.ctrl1.y;
|
|
1517
|
+
const origCtrl2x = trace.ctrl2.x;
|
|
1518
|
+
const origCtrl2y = trace.ctrl2.y;
|
|
1519
|
+
for (const dir of directions) {
|
|
1520
|
+
trace.ctrl1.x = Math.max(minX, Math.min(maxX, origCtrl1x + dir.dx));
|
|
1521
|
+
trace.ctrl1.y = Math.max(minY, Math.min(maxY, origCtrl1y + dir.dy));
|
|
1522
|
+
this.updateSingleTraceSample(i);
|
|
1523
|
+
const cost1 = this.computeCostForTrace(i);
|
|
1524
|
+
if (cost1 < bestCost) {
|
|
1525
|
+
bestCost = cost1;
|
|
1526
|
+
bestCtrl1x = trace.ctrl1.x;
|
|
1527
|
+
bestCtrl1y = trace.ctrl1.y;
|
|
1528
|
+
bestCtrl2x = origCtrl2x;
|
|
1529
|
+
bestCtrl2y = origCtrl2y;
|
|
1530
|
+
}
|
|
1531
|
+
trace.ctrl1.x = origCtrl1x;
|
|
1532
|
+
trace.ctrl1.y = origCtrl1y;
|
|
1533
|
+
trace.ctrl2.x = Math.max(minX, Math.min(maxX, origCtrl2x + dir.dx));
|
|
1534
|
+
trace.ctrl2.y = Math.max(minY, Math.min(maxY, origCtrl2y + dir.dy));
|
|
1535
|
+
this.updateSingleTraceSample(i);
|
|
1536
|
+
const cost2 = this.computeCostForTrace(i);
|
|
1537
|
+
if (cost2 < bestCost) {
|
|
1538
|
+
bestCost = cost2;
|
|
1539
|
+
bestCtrl1x = origCtrl1x;
|
|
1540
|
+
bestCtrl1y = origCtrl1y;
|
|
1541
|
+
bestCtrl2x = trace.ctrl2.x;
|
|
1542
|
+
bestCtrl2y = trace.ctrl2.y;
|
|
1543
|
+
}
|
|
1544
|
+
trace.ctrl2.x = origCtrl2x;
|
|
1545
|
+
trace.ctrl2.y = origCtrl2y;
|
|
1546
|
+
trace.ctrl1.x = Math.max(minX, Math.min(maxX, origCtrl1x + dir.dx));
|
|
1547
|
+
trace.ctrl1.y = Math.max(minY, Math.min(maxY, origCtrl1y + dir.dy));
|
|
1548
|
+
trace.ctrl2.x = Math.max(minX, Math.min(maxX, origCtrl2x + dir.dx));
|
|
1549
|
+
trace.ctrl2.y = Math.max(minY, Math.min(maxY, origCtrl2y + dir.dy));
|
|
1550
|
+
this.updateSingleTraceSample(i);
|
|
1551
|
+
const cost3 = this.computeCostForTrace(i);
|
|
1552
|
+
if (cost3 < bestCost) {
|
|
1553
|
+
bestCost = cost3;
|
|
1554
|
+
bestCtrl1x = trace.ctrl1.x;
|
|
1555
|
+
bestCtrl1y = trace.ctrl1.y;
|
|
1556
|
+
bestCtrl2x = trace.ctrl2.x;
|
|
1557
|
+
bestCtrl2y = trace.ctrl2.y;
|
|
1558
|
+
}
|
|
1559
|
+
trace.ctrl1.x = origCtrl1x;
|
|
1560
|
+
trace.ctrl1.y = origCtrl1y;
|
|
1561
|
+
trace.ctrl2.x = origCtrl2x;
|
|
1562
|
+
trace.ctrl2.y = origCtrl2y;
|
|
1563
|
+
}
|
|
1564
|
+
trace.ctrl1.x = bestCtrl1x;
|
|
1565
|
+
trace.ctrl1.y = bestCtrl1y;
|
|
1566
|
+
trace.ctrl2.x = bestCtrl2x;
|
|
1567
|
+
trace.ctrl2.y = bestCtrl2y;
|
|
1568
|
+
this.updateSingleTraceSample(i);
|
|
1569
|
+
if (bestCost < currentCost * 0.9) break;
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
if (this.optimizationStep % 10 === 0) {
|
|
1573
|
+
this.updateCollisionPairs();
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
buildOutputTraces() {
|
|
1577
|
+
this.outputTraces = this.traces.map((trace) => ({
|
|
1578
|
+
waypointPair: trace.waypointPair,
|
|
1579
|
+
points: sampleCubicBezier(
|
|
1580
|
+
trace.waypointPair.start,
|
|
1581
|
+
trace.ctrl1,
|
|
1582
|
+
trace.ctrl2,
|
|
1583
|
+
trace.waypointPair.end,
|
|
1584
|
+
OUTPUT_SAMPLES
|
|
1585
|
+
),
|
|
1586
|
+
networkId: trace.networkId
|
|
1587
|
+
}));
|
|
1588
|
+
}
|
|
1589
|
+
_step() {
|
|
1590
|
+
if (this.traces.length === 0) {
|
|
1591
|
+
this.initializeTraces();
|
|
1592
|
+
this.lastCost = this.computeTotalCost();
|
|
1593
|
+
this.stagnantSteps = 0;
|
|
1594
|
+
}
|
|
1595
|
+
if (this.optimizationStep < this.maxOptimizationSteps) {
|
|
1596
|
+
this.optimizeStep();
|
|
1597
|
+
this.optimizationStep++;
|
|
1598
|
+
const currentCost = this.computeTotalCost();
|
|
1599
|
+
if (currentCost === 0) {
|
|
1600
|
+
this.optimizationStep = this.maxOptimizationSteps;
|
|
1601
|
+
} else if (currentCost >= this.lastCost * 0.99) {
|
|
1602
|
+
this.stagnantSteps++;
|
|
1603
|
+
if (this.stagnantSteps > 15) {
|
|
1604
|
+
this.optimizationStep = this.maxOptimizationSteps;
|
|
1605
|
+
}
|
|
1606
|
+
} else {
|
|
1607
|
+
this.stagnantSteps = 0;
|
|
1608
|
+
}
|
|
1609
|
+
this.lastCost = currentCost;
|
|
1610
|
+
}
|
|
1611
|
+
if (this.optimizationStep >= this.maxOptimizationSteps) {
|
|
1612
|
+
this.buildOutputTraces();
|
|
1613
|
+
this.solved = true;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
visualize() {
|
|
1617
|
+
if (this.traces.length > 0) {
|
|
1618
|
+
this.buildOutputTraces();
|
|
1619
|
+
}
|
|
1620
|
+
return visualizeCurvyTraceProblem(this.problem, this.outputTraces);
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
export {
|
|
1624
|
+
CurvyTraceSolver
|
|
1625
|
+
};
|
|
1626
|
+
/*! Bundled license information:
|
|
1627
|
+
|
|
1628
|
+
is-buffer/index.js:
|
|
1629
|
+
(*!
|
|
1630
|
+
* Determine if an object is a Buffer
|
|
1631
|
+
*
|
|
1632
|
+
* @author Feross Aboukhadijeh <https://feross.org>
|
|
1633
|
+
* @license MIT
|
|
1634
|
+
*)
|
|
1635
|
+
|
|
1636
|
+
deep-rename-keys/index.js:
|
|
1637
|
+
(*!
|
|
1638
|
+
* deep-rename-keys <https://github.com/jonschlinkert/deep-rename-keys>
|
|
1639
|
+
*
|
|
1640
|
+
* Copyright (c) 2015 Jon Schlinkert, contributors.
|
|
1641
|
+
* Licensed under the MIT license.
|
|
1642
|
+
*)
|
|
1643
|
+
*/
|