@playcanvas/splat-transform 1.9.0 → 1.9.2

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/dist/cli.mjs CHANGED
@@ -11854,6 +11854,16 @@ class Progress {
11854
11854
  if (!quiet)
11855
11855
  impl.onProgress(this.currentNode);
11856
11856
  }
11857
+ /**
11858
+ * Cancel the current progress node, popping it from the stack without
11859
+ * completing remaining steps. Use this before early exits (e.g. break)
11860
+ * to keep the progress stack balanced.
11861
+ */
11862
+ cancel() {
11863
+ if (!this.currentNode)
11864
+ return;
11865
+ this.currentNode = this.currentNode.parent;
11866
+ }
11857
11867
  /**
11858
11868
  * Advance to the next step. Auto-increments the step counter.
11859
11869
  * Auto-ends when all steps are complete.
@@ -12041,33 +12051,74 @@ const sortMortonOrder = (dataTable, indices) => {
12041
12051
  generate(indices);
12042
12052
  };
12043
12053
 
12054
+ const nthElement = (arr, lo, hi, k, values) => {
12055
+ while (lo < hi) {
12056
+ const mid = (lo + hi) >> 1;
12057
+ const va = values[arr[lo]], vb = values[arr[mid]], vc = values[arr[hi]];
12058
+ let pivotIdx;
12059
+ if ((vb - va) * (vc - vb) >= 0)
12060
+ pivotIdx = mid;
12061
+ else if ((va - vb) * (vc - va) >= 0)
12062
+ pivotIdx = lo;
12063
+ else
12064
+ pivotIdx = hi;
12065
+ const pivotVal = values[arr[pivotIdx]];
12066
+ let tmp = arr[pivotIdx];
12067
+ arr[pivotIdx] = arr[hi];
12068
+ arr[hi] = tmp;
12069
+ let store = lo;
12070
+ for (let i = lo; i < hi; i++) {
12071
+ if (values[arr[i]] < pivotVal) {
12072
+ tmp = arr[i];
12073
+ arr[i] = arr[store];
12074
+ arr[store] = tmp;
12075
+ store++;
12076
+ }
12077
+ }
12078
+ tmp = arr[store];
12079
+ arr[store] = arr[hi];
12080
+ arr[hi] = tmp;
12081
+ if (store === k)
12082
+ return;
12083
+ else if (store < k)
12084
+ lo = store + 1;
12085
+ else
12086
+ hi = store - 1;
12087
+ }
12088
+ };
12044
12089
  class KdTree {
12045
12090
  centroids;
12046
12091
  root;
12092
+ colData;
12047
12093
  constructor(centroids) {
12048
- const build = (indices, depth) => {
12049
- const { centroids } = this;
12050
- const values = centroids.columns[depth % centroids.numColumns].data;
12051
- indices.sort((a, b) => values[a] - values[b]);
12052
- if (indices.length === 1) {
12053
- return {
12054
- index: indices[0],
12055
- count: 1
12056
- };
12094
+ const numCols = centroids.numColumns;
12095
+ const colData = centroids.columns.map(c => c.data);
12096
+ const indices = new Uint32Array(centroids.numRows);
12097
+ for (let i = 0; i < indices.length; ++i) {
12098
+ indices[i] = i;
12099
+ }
12100
+ const build = (lo, hi, depth) => {
12101
+ const count = hi - lo + 1;
12102
+ if (count === 1) {
12103
+ return { index: indices[lo], count: 1 };
12057
12104
  }
12058
- else if (indices.length === 2) {
12105
+ const values = colData[depth % numCols];
12106
+ if (count === 2) {
12107
+ if (values[indices[lo]] > values[indices[hi]]) {
12108
+ const tmp = indices[lo];
12109
+ indices[lo] = indices[hi];
12110
+ indices[hi] = tmp;
12111
+ }
12059
12112
  return {
12060
- index: indices[0],
12113
+ index: indices[lo],
12061
12114
  count: 2,
12062
- right: {
12063
- index: indices[1],
12064
- count: 1
12065
- }
12115
+ right: { index: indices[hi], count: 1 }
12066
12116
  };
12067
12117
  }
12068
- const mid = indices.length >> 1;
12069
- const left = build(indices.subarray(0, mid), depth + 1);
12070
- const right = build(indices.subarray(mid + 1), depth + 1);
12118
+ const mid = lo + (count >> 1);
12119
+ nthElement(indices, lo, hi, mid, values);
12120
+ const left = build(lo, mid - 1, depth + 1);
12121
+ const right = build(mid + 1, hi, depth + 1);
12071
12122
  return {
12072
12123
  index: indices[mid],
12073
12124
  count: 1 + left.count + right.count,
@@ -12075,48 +12126,39 @@ class KdTree {
12075
12126
  right
12076
12127
  };
12077
12128
  };
12078
- const indices = new Uint32Array(centroids.numRows);
12079
- for (let i = 0; i < indices.length; ++i) {
12080
- indices[i] = i;
12081
- }
12082
12129
  this.centroids = centroids;
12083
- this.root = build(indices, 0);
12130
+ this.colData = colData;
12131
+ this.root = build(0, indices.length - 1, 0);
12084
12132
  }
12085
12133
  findNearest(point, filterFunc) {
12086
- const { centroids } = this;
12087
- const { numColumns } = centroids;
12088
- const calcDistance = (index) => {
12089
- let l = 0;
12090
- for (let i = 0; i < numColumns; ++i) {
12091
- const v = centroids.columns[i].data[index] - point[i];
12092
- l += v * v;
12093
- }
12094
- return l;
12095
- };
12134
+ const colData = this.colData;
12135
+ const numCols = colData.length;
12096
12136
  let mind = Infinity;
12097
12137
  let mini = -1;
12098
12138
  let cnt = 0;
12099
- const recurse = (node, depth) => {
12100
- const axis = depth % numColumns;
12101
- const distance = point[axis] - centroids.columns[axis].data[node.index];
12139
+ const recurse = (node, axis) => {
12140
+ const distance = point[axis] - colData[axis][node.index];
12102
12141
  const next = (distance > 0) ? node.right : node.left;
12142
+ const nextAxis = axis + 1 < numCols ? axis + 1 : 0;
12103
12143
  cnt++;
12104
12144
  if (next) {
12105
- recurse(next, depth + 1);
12145
+ recurse(next, nextAxis);
12106
12146
  }
12107
- // check index
12108
12147
  if (!filterFunc || filterFunc(node.index)) {
12109
- const thisd = calcDistance(node.index);
12148
+ let thisd = 0;
12149
+ for (let c = 0; c < numCols; c++) {
12150
+ const v = colData[c][node.index] - point[c];
12151
+ thisd += v * v;
12152
+ }
12110
12153
  if (thisd < mind) {
12111
12154
  mind = thisd;
12112
12155
  mini = node.index;
12113
12156
  }
12114
12157
  }
12115
- // check the other side
12116
12158
  if (distance * distance < mind) {
12117
12159
  const other = next === node.right ? node.left : node.right;
12118
12160
  if (other) {
12119
- recurse(other, depth + 1);
12161
+ recurse(other, nextAxis);
12120
12162
  }
12121
12163
  }
12122
12164
  };
@@ -12128,16 +12170,8 @@ class KdTree {
12128
12170
  return { indices: new Int32Array(0), distances: new Float32Array(0) };
12129
12171
  }
12130
12172
  k = Math.min(k, this.centroids.numRows);
12131
- const { centroids } = this;
12132
- const { numColumns } = centroids;
12133
- const calcDistance = (index) => {
12134
- let l = 0;
12135
- for (let i = 0; i < numColumns; ++i) {
12136
- const v = centroids.columns[i].data[index] - point[i];
12137
- l += v * v;
12138
- }
12139
- return l;
12140
- };
12173
+ const colData = this.colData;
12174
+ const numCols = colData.length;
12141
12175
  // Bounded max-heap: stores (distance, index) pairs sorted so the
12142
12176
  // farthest element is at position 0, enabling O(1) pruning bound.
12143
12177
  const heapDist = new Float32Array(k).fill(Infinity);
@@ -12145,14 +12179,12 @@ class KdTree {
12145
12179
  let heapSize = 0;
12146
12180
  const heapPush = (dist, idx) => {
12147
12181
  if (heapSize < k) {
12148
- // Heap not full yet -- insert via sift-up
12149
12182
  let pos = heapSize++;
12150
12183
  heapDist[pos] = dist;
12151
12184
  heapIdx[pos] = idx;
12152
12185
  while (pos > 0) {
12153
12186
  const parent = (pos - 1) >> 1;
12154
12187
  if (heapDist[parent] < heapDist[pos]) {
12155
- // swap
12156
12188
  const td = heapDist[parent];
12157
12189
  heapDist[parent] = heapDist[pos];
12158
12190
  heapDist[pos] = td;
@@ -12167,7 +12199,6 @@ class KdTree {
12167
12199
  }
12168
12200
  }
12169
12201
  else if (dist < heapDist[0]) {
12170
- // Replace root (farthest) and sift-down
12171
12202
  heapDist[0] = dist;
12172
12203
  heapIdx[0] = idx;
12173
12204
  let pos = 0;
@@ -12191,22 +12222,26 @@ class KdTree {
12191
12222
  }
12192
12223
  }
12193
12224
  };
12194
- const recurse = (node, depth) => {
12195
- const axis = depth % numColumns;
12196
- const distance = point[axis] - centroids.columns[axis].data[node.index];
12225
+ const recurse = (node, axis) => {
12226
+ const distance = point[axis] - colData[axis][node.index];
12197
12227
  const next = (distance > 0) ? node.right : node.left;
12228
+ const nextAxis = axis + 1 < numCols ? axis + 1 : 0;
12198
12229
  if (next) {
12199
- recurse(next, depth + 1);
12230
+ recurse(next, nextAxis);
12200
12231
  }
12201
12232
  if (!filterFunc || filterFunc(node.index)) {
12202
- const thisd = calcDistance(node.index);
12233
+ let thisd = 0;
12234
+ for (let c = 0; c < numCols; c++) {
12235
+ const v = colData[c][node.index] - point[c];
12236
+ thisd += v * v;
12237
+ }
12203
12238
  heapPush(thisd, node.index);
12204
12239
  }
12205
12240
  const bound = heapSize < k ? Infinity : heapDist[0];
12206
12241
  if (distance * distance < bound) {
12207
12242
  const other = next === node.right ? node.left : node.right;
12208
12243
  if (other) {
12209
- recurse(other, depth + 1);
12244
+ recurse(other, nextAxis);
12210
12245
  }
12211
12246
  }
12212
12247
  };
@@ -12241,6 +12276,54 @@ const OPACITY_PRUNE_THRESHOLD = 0.1;
12241
12276
  const KNN_K = 16;
12242
12277
  const MC_SAMPLES = 1;
12243
12278
  const EPS_COV = 1e-8;
12279
+ const PROGRESS_TICKS = 100;
12280
+ // Radix sort edge indices by their Float32 costs.
12281
+ // Converts floats to sortable uint32 keys (preserving order), then does
12282
+ // 4-pass LSD radix sort with 8-bit radix. Returns the number of valid
12283
+ // (finite-cost) edges written to `out`.
12284
+ const radixSortIndicesByFloat = (out, count, keys) => {
12285
+ const keyBits = new Uint32Array(keys.buffer, keys.byteOffset, keys.length);
12286
+ const sortKeys = new Uint32Array(count);
12287
+ let validCount = 0;
12288
+ for (let i = 0; i < count; i++) {
12289
+ const bits = keyBits[i];
12290
+ if ((bits & 0x7F800000) === 0x7F800000)
12291
+ continue;
12292
+ sortKeys[validCount] = (bits & 0x80000000) ? ~bits >>> 0 : (bits | 0x80000000) >>> 0;
12293
+ out[validCount] = i;
12294
+ validCount++;
12295
+ }
12296
+ if (validCount <= 1)
12297
+ return validCount;
12298
+ const n = validCount;
12299
+ const temp = new Uint32Array(n);
12300
+ const tempKeys = new Uint32Array(n);
12301
+ const counts = new Uint32Array(256);
12302
+ for (let pass = 0; pass < 4; pass++) {
12303
+ const shift = pass << 3;
12304
+ const srcIdx = (pass & 1) ? temp : out;
12305
+ const dstIdx = (pass & 1) ? out : temp;
12306
+ const srcK = (pass & 1) ? tempKeys : sortKeys;
12307
+ const dstK = (pass & 1) ? sortKeys : tempKeys;
12308
+ counts.fill(0);
12309
+ for (let i = 0; i < n; i++) {
12310
+ counts[(srcK[i] >>> shift) & 0xFF]++;
12311
+ }
12312
+ let sum = 0;
12313
+ for (let b = 0; b < 256; b++) {
12314
+ const c = counts[b];
12315
+ counts[b] = sum;
12316
+ sum += c;
12317
+ }
12318
+ for (let i = 0; i < n; i++) {
12319
+ const bucket = (srcK[i] >>> shift) & 0xFF;
12320
+ const pos = counts[bucket]++;
12321
+ dstIdx[pos] = srcIdx[i];
12322
+ dstK[pos] = srcK[i];
12323
+ }
12324
+ }
12325
+ return validCount;
12326
+ };
12244
12327
  // ---------- sigmoid / logit ----------
12245
12328
  const sigmoid$1 = (x) => 1 / (1 + Math.exp(-x));
12246
12329
  const logit = (p) => {
@@ -12728,7 +12811,6 @@ const simplifyGaussians = (dataTable, targetCount) => {
12728
12811
  let current;
12729
12812
  if (keptIndices.length < N && keptIndices.length > targetCount) {
12730
12813
  current = dataTable.permuteRows(keptIndices);
12731
- logger.debug(`opacity pruning: ${N} -> ${current.numRows} splats (threshold=${pruneThreshold.toFixed(4)})`);
12732
12814
  }
12733
12815
  else {
12734
12816
  current = dataTable;
@@ -12739,7 +12821,8 @@ const simplifyGaussians = (dataTable, targetCount) => {
12739
12821
  while (current.numRows > targetCount) {
12740
12822
  const n = current.numRows;
12741
12823
  const kEff = Math.min(Math.max(1, KNN_K), Math.max(1, n - 1));
12742
- logger.debug(`merging iteration: ${n} -> ${targetCount} splats`);
12824
+ logger.progress.begin(5);
12825
+ logger.progress.step('Building KD-tree');
12743
12826
  const cx = current.getColumnByName('x').data;
12744
12827
  const cy = current.getColumnByName('y').data;
12745
12828
  const cz = current.getColumnByName('z').data;
@@ -12752,16 +12835,21 @@ const simplifyGaussians = (dataTable, targetCount) => {
12752
12835
  const cr2 = current.getColumnByName('rot_2').data;
12753
12836
  const cr3 = current.getColumnByName('rot_3').data;
12754
12837
  const cache = buildPerSplatCache(n, cx, cy, cz, cop, cs0, cs1, cs2, cr0, cr1, cr2, cr3);
12755
- // Build KNN graph
12756
12838
  const posTable = new DataTable([
12757
12839
  new Column('x', cx instanceof Float32Array ? cx : new Float32Array(cx)),
12758
12840
  new Column('y', cy instanceof Float32Array ? cy : new Float32Array(cy)),
12759
12841
  new Column('z', cz instanceof Float32Array ? cz : new Float32Array(cz))
12760
12842
  ]);
12761
12843
  const kdTree = new KdTree(posTable);
12762
- const edgeSet = new Set();
12763
- const edges = [];
12844
+ logger.progress.step('Finding nearest neighbors');
12845
+ let edgeCapacity = Math.ceil(n * kEff / 2);
12846
+ let edgeU = new Uint32Array(edgeCapacity);
12847
+ let edgeV = new Uint32Array(edgeCapacity);
12848
+ let edgeCount = 0;
12764
12849
  const queryPoint = new Float32Array(3);
12850
+ const knnInterval = Math.max(1, Math.ceil(n / PROGRESS_TICKS));
12851
+ const knnTicks = Math.ceil(n / knnInterval);
12852
+ logger.progress.begin(knnTicks);
12765
12853
  for (let i = 0; i < n; i++) {
12766
12854
  queryPoint[0] = cx[i];
12767
12855
  queryPoint[1] = cy[i];
@@ -12769,46 +12857,58 @@ const simplifyGaussians = (dataTable, targetCount) => {
12769
12857
  const knn = kdTree.findKNearest(queryPoint, kEff + 1);
12770
12858
  for (let ki = 0; ki < knn.indices.length; ki++) {
12771
12859
  const j = knn.indices[ki];
12772
- if (j === i || j < 0)
12860
+ if (j <= i)
12773
12861
  continue;
12774
- const u = Math.min(i, j);
12775
- const v = Math.max(i, j);
12776
- const key = `${u},${v}`;
12777
- if (!edgeSet.has(key)) {
12778
- edgeSet.add(key);
12779
- edges.push([u, v]);
12862
+ if (edgeCount === edgeCapacity) {
12863
+ edgeCapacity *= 2;
12864
+ const newU = new Uint32Array(edgeCapacity);
12865
+ const newV = new Uint32Array(edgeCapacity);
12866
+ newU.set(edgeU);
12867
+ newV.set(edgeV);
12868
+ edgeU = newU;
12869
+ edgeV = newV;
12780
12870
  }
12871
+ edgeU[edgeCount] = i;
12872
+ edgeV[edgeCount] = j;
12873
+ edgeCount++;
12781
12874
  }
12875
+ if ((i + 1) % knnInterval === 0)
12876
+ logger.progress.step();
12782
12877
  }
12783
- if (edges.length === 0)
12878
+ if (n % knnInterval !== 0)
12879
+ logger.progress.step();
12880
+ if (edgeCount === 0) {
12881
+ logger.progress.cancel();
12784
12882
  break;
12785
- // Compute edge costs
12883
+ }
12884
+ logger.progress.step('Computing edge costs');
12786
12885
  const appData = [];
12787
12886
  for (let ai = 0; ai < allAppearanceCols.length; ai++) {
12788
12887
  const col = current.getColumnByName(allAppearanceCols[ai]);
12789
12888
  if (col)
12790
12889
  appData.push(col.data);
12791
12890
  }
12792
- const costs = new Float32Array(edges.length);
12793
- for (let e = 0; e < edges.length; e++) {
12794
- costs[e] = computeEdgeCost(edges[e][0], edges[e][1], cx, cy, cz, cache, Z, appData, appData.length);
12795
- }
12796
- // Greedy disjoint pair selection
12797
- const valid = [];
12798
- for (let i = 0; i < edges.length; i++) {
12799
- if (Number.isFinite(costs[i]))
12800
- valid.push(i);
12801
- }
12802
- valid.sort((a, b) => {
12803
- const d = costs[a] - costs[b];
12804
- return d !== 0 ? d : a - b;
12805
- });
12806
12891
  const mergesNeeded = n - targetCount;
12892
+ const costs = new Float32Array(edgeCount);
12893
+ const costInterval = Math.max(1, Math.ceil(edgeCount / PROGRESS_TICKS));
12894
+ const costTicks = Math.ceil(edgeCount / costInterval);
12895
+ logger.progress.begin(costTicks);
12896
+ for (let e = 0; e < edgeCount; e++) {
12897
+ costs[e] = computeEdgeCost(edgeU[e], edgeV[e], cx, cy, cz, cache, Z, appData, appData.length);
12898
+ if ((e + 1) % costInterval === 0)
12899
+ logger.progress.step();
12900
+ }
12901
+ if (edgeCount % costInterval !== 0)
12902
+ logger.progress.step();
12903
+ logger.progress.step('Merging splats');
12904
+ // Sort and greedy disjoint pair selection
12905
+ const sorted = new Uint32Array(edgeCount);
12906
+ const validCount = radixSortIndicesByFloat(sorted, edgeCount, costs);
12807
12907
  const used = new Uint8Array(n);
12808
12908
  const pairs = [];
12809
- for (let t = 0; t < valid.length; t++) {
12810
- const e = valid[t];
12811
- const u = edges[e][0], v = edges[e][1];
12909
+ for (let t = 0; t < validCount; t++) {
12910
+ const e = sorted[t];
12911
+ const u = edgeU[e], v = edgeV[e];
12812
12912
  if (used[u] || used[v])
12813
12913
  continue;
12814
12914
  used[u] = 1;
@@ -12817,9 +12917,10 @@ const simplifyGaussians = (dataTable, targetCount) => {
12817
12917
  if (pairs.length >= mergesNeeded)
12818
12918
  break;
12819
12919
  }
12820
- if (pairs.length === 0)
12920
+ if (pairs.length === 0) {
12921
+ logger.progress.cancel();
12821
12922
  break;
12822
- logger.debug(`selected ${pairs.length} merge pairs from ${edges.length} edges`);
12923
+ }
12823
12924
  // Mark which indices are consumed by merging
12824
12925
  const usedSet = new Uint8Array(n);
12825
12926
  for (let p = 0; p < pairs.length; p++) {
@@ -12847,7 +12948,7 @@ const simplifyGaussians = (dataTable, targetCount) => {
12847
12948
  newTable.columns[c].data[dst] = cols[c].data[src];
12848
12949
  }
12849
12950
  }
12850
- // Merge pairs -- cache column refs and handled set once
12951
+ // Merge pairs
12851
12952
  const mergeOut = {
12852
12953
  mu: new Float64Array(3),
12853
12954
  sc: new Float64Array(3),
@@ -12875,6 +12976,9 @@ const simplifyGaussians = (dataTable, targetCount) => {
12875
12976
  .filter(col => !handledCols.has(col.name))
12876
12977
  .map(col => ({ src: col, dst: newTable.getColumnByName(col.name) }))
12877
12978
  .filter(pair => pair.dst);
12979
+ const mergeInterval = Math.max(1, Math.ceil(pairs.length / PROGRESS_TICKS));
12980
+ const mergeTicks = Math.ceil(pairs.length / mergeInterval);
12981
+ logger.progress.begin(mergeTicks);
12878
12982
  for (let p = 0; p < pairs.length; p++, dst++) {
12879
12983
  const pi = pairs[p][0], pj = pairs[p][1];
12880
12984
  momentMatch(pi, pj, cx, cy, cz, cop, cs0, cs1, cs2, cr0, cr1, cr2, cr3, mergeOut, appData, appData.length);
@@ -12897,7 +13001,12 @@ const simplifyGaussians = (dataTable, targetCount) => {
12897
13001
  for (let u = 0; u < unhandledColPairs.length; u++) {
12898
13002
  unhandledColPairs[u].dst.data[dst] = unhandledColPairs[u].src.data[dominant];
12899
13003
  }
13004
+ if ((p + 1) % mergeInterval === 0)
13005
+ logger.progress.step();
12900
13006
  }
13007
+ if (pairs.length % mergeInterval !== 0)
13008
+ logger.progress.step();
13009
+ logger.progress.step('Finalizing');
12901
13010
  current = newTable;
12902
13011
  }
12903
13012
  return current;
@@ -16330,7 +16439,7 @@ class CompressedChunk {
16330
16439
  }
16331
16440
  }
16332
16441
 
16333
- var version = "1.9.0";
16442
+ var version = "1.9.2";
16334
16443
 
16335
16444
  const generatedByString = `Generated by splat-transform ${version}`;
16336
16445
  const chunkProps = [
@@ -18377,6 +18486,746 @@ const writePly = async (options, fs) => {
18377
18486
  await writer.close();
18378
18487
  };
18379
18488
 
18489
+ // This file is part of meshoptimizer library and is distributed under the terms of MIT License.
18490
+ // Copyright (C) 2016-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
18491
+ var MeshoptSimplifier = (function () {
18492
+ // Built with clang version 19.1.5-wasi-sdk
18493
+ // Built from meshoptimizer 1.0
18494
+ var wasm =
18495
+ 'b9H79Tebbbe:6eO9Geueu9Geub9Gbb9Gsuuuuuuuuuuuu99uueu9Gvuuuuub9Gruuuuuuub9Gouuuuuue999Gvuuuuueu9Gzuuuuuuuuuuu99uuuub9Gquuuuuuu99uueu9GPuuuuuuuuuuu99uueu9Gquuuuuuuu99ueu9Gruuuuuu99eu9Gwuuuuuu99ueu9Giuuue999Gluuuueu9Gluuuub9GiuuueuiLQdilvorlwDiqkxmPszbHHbelve9Weiiviebeoweuec:G:Pdkr:Bdxo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bbz9TW79O9V9Wt9F79P9T9W29P9M95bw8E9TW79O9V9Wt9F79P9T9W29P9M959x9Pt9OcttV9P9I91tW7bD8A9TW79O9V9Wt9F79P9T9W29P9M959x9Pt9O9v9W9K9HtWbqQ9TW79O9V9Wt9F79P9T9W29P9M959t29V9W9W95bkX9TW79O9V9Wt9F79P9T9W29P9M959qV919UWbxQ9TW79O9V9Wt9F79P9T9W29P9M959q9V9P9Ut7bmX9TW79O9V9Wt9F79P9T9W29P9M959t9J9H2WbPa9TW79O9V9Wt9F9V9Wt9P9T9P96W9wWVtW94SWt9J9O9sW9T9H9Wbs59TW79O9V9Wt9F9NW9UWV9HtW9q9V79Pt9P9V9U9sW9T9H9Wbzl79IV9RbHDwebcekdCXqM;YeQdbk;A1er3ue99euE99Que9:r998Jjjjjbcj;sb9Rgs8Kjjjjbcbhzasc:Cefcbc;Kbz:tjjjb8AdnabaeSmbabaeadcdtzMjjjb8AkdnamcdGTmbalcrfci4cbyd1:jjjbHjjjjbbhHasc:Cefasyd;8egecdtfaHBdbasaecefBd;8ecbhlcbhednadTmbabheadhOinaHaeydbci4fcb86bbaeclfheaOcufgOmbkcbhlabheadhOinaHaeydbgAci4fgCaCRbbgCceaAcrGgAtV86bbaCcu7aA4ceGalfhlaeclfheaOcufgOmbkcualcdtalcFFFFi0Ehekaecbyd1:jjjbHjjjjbbhzasc:Cefasyd;8egecdtfazBdbasaecefBd;8ealcd4alfhOcehHinaHgecethHaeaO6mbkcbhXcuaecdtgOaecFFFFi0Ecbyd1:jjjbHjjjjbbhHasc:Cefasyd;8egAcdtfaHBdbasaAcefBd;8eaHcFeaOz:tjjjbhQdnadTmbaecufhLcbhKindndnaQabaXcdtfgYydbgAc:v;t;h;Ev2aLGgOcdtfgCydbgHcuSmbceheinazaHcdtfydbaASmdaOaefhHaecefheaQaHaLGgOcdtfgCydbgHcu9hmbkkazaKcdtfaABdbaCaKBdbaKhHaKcefhKkaYaHBdbaXcefgXad9hmbkkaQcbyd:m:jjjbH:bjjjbbasasyd;8ecufBd;8ekcbh8AcualcefgecdtaecFFFFi0Ecbyd1:jjjbHjjjjbbhXasc:Cefasyd;8egecdtfaXBdbasaXBdNeasaecefBd;8ecuadcitadcFFFFe0Ecbyd1:jjjbHjjjjbbhEasc:Cefasyd;8egecdtfaEBdbasaEBd:yeasaecefBd;8eascNefabadalcbz:cjjjbcualcdtgealcFFFFi0Eg3cbyd1:jjjbHjjjjbbhAasc:Cefasyd;8egHcdtfaABdbasaHcefBd;8ea3cbyd1:jjjbHjjjjbbhKasc:Cefasyd;8egHcdtfaKBdbasaHcefBd;8eaAaKaialavazasc:Cefz:djjjbalcbyd1:jjjbHjjjjbbh5asc:Cefasyd;8egHcdtfa5BdbasaHcefBd;8ea3cbyd1:jjjbHjjjjbbhHasc:Cefasyd;8egOcdtfaHBdbasaOcefBd;8ea3cbyd1:jjjbHjjjjbbhOasc:Cefasyd;8egCcdtfaOBdbasaCcefBd;8eaHcFeaez:tjjjbh8EaOcFeaez:tjjjbh8FdnalTmbaEcwfhaindnaXa8AgOcefg8AcdtfydbgCaXaOcdtgefydbgHSmbaCaH9RhhaEaHcitfhga8Faefh8Ja8Eaefh8KcbhQindndnagaQcitfydbgLaO9hmba8KaOBdba8JaOBdbxekdnaXaLcdtg8LfgeclfydbgHaeydbgeSmbaEaecitgCfydbaOSmeaHae9Rh8Maecu7aHfhYaaaCfhHcbheinaYaeSmeaecefheaHydbhCaHcwfhHaCaO9hmbkaea8M6meka8Fa8LfgeaOaLaeydbcuSEBdba8KaLaOa8KydbcuSEBdbkaQcefgQah9hmbkka8Aal9hmbkaAhHaKhOa8FhCa8EhQcbheindndnaeaHydbgL9hmbdnaeaOydbgL9hmbaQydbhLdnaCydbgYcu9hmbaLcu9hmba5aefcb86bbxikdnaYcuSmbaLcuSmbaeaYSmbaAaYcdtfydbaAaLcdtfydb9hmba5aefcd86bbxika5aefh8KdnaeaYSmbaeaLSmba8Kce86bbxika8Kcl86bbxdkdnaeaKaLcdtgYfydb9hmbdnaCydbg8KcuSmbaea8KSmbaQydbghcuSmbaeahSmba8FaYfydbggcuSmbagaLSmba8EaYfydbgYcuSmbaYaLSmbdnaAa8KcdtfydbgLaAaYcdtfydb9hmbaLaAahcdtfydbgYSmbaYaAagcdtfydb9hmba5aefcd86bbxlka5aefcl86bbxika5aefcl86bbxdka5aefcl86bbxeka5aefa5aLfRbb86bbkaHclfhHaOclfhOaCclfhCaQclfhQalaecefge9hmbkdnamcaGTmbaEcwfh8Jcbh8Nindndna5a8NfgyRbbg8Pc9:fPibebekdndndnaAa8Ncdtfydbgea8N9hmbdnaqmbcbhgxdkdnazTmbcbhga8NheinagaqazaecdtgefydbfRbbcdGce4VhgaKaefydbgea8N9hmbxikkcbhga8NheinagaqaefRbbcdGce4VhgaKaecdtfydbgea8N9hmbxdkka5aefRbbhexeka8NheindnaXaecdtgafgeclfydbgHaeydbgeSmbaHae9Rh8AaEaecitfh8MaAaafh8Lcbh8Kina8Ma8KcitfydbgYhednindnaXaecdtgLfgeclfydbgHaeydbgeSmbdnaAaEaecitgOfydbcdtfydba8LydbgQ9hmbcehexikaHae9Rhhaecu7aHfhCa8JaOfhHcbheinaCaeSmeaecefheaHydbhOaHcwfhHaAaOcdtfydbaQ9hmbkaeah6hexdkaKaLfydbgeaY9hmbkcbhekagaece7Vhga8Kcefg8Ka8A9hmbkkaKaafydbgea8N9hmbka8PciagceGEhekayae86bbka8Ncefg8Nal9hmbkkdnaqTmbdndnazTmbazheaAhHalhOindnaqaeydbfRbbceGTmba5aHydbfcl86bbkaeclfheaHclfhHaOcufgOmbxdkkaqheaAhHalhOindnaeRbbceGTmba5aHydbfcl86bbkaecefheaHclfhHaOcufgOmbkkaAhealhOa5hHindna5aeydbfRbbcl9hmbaHcl86bbkaeclfheaHcefhHaOcufgOmbkkamceGTmba5healhHindnaeRbbce9hmbaecl86bbkaecefheaHcufgHmbkkcbhIcualcx2alc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbhaasc:Cefasyd;8egecdtfaaBdbasaecefBd;8easc:qefcbBdbas9cb83i1eaaaialavazasc1efz:ejjjbh8RdndnaDmbcbhycbhCxekcbhCawhecbhHindnaeIdbJbbbb9ETmbasaCcdtfaHBdbaCcefhCkaeclfheaDaHcefgH9hmbkcuaCal2gecdtaecFFFFi0Ecbyd1:jjjbHjjjjbbhyasc:Cefasyd;8egecdtfayBdbasaecefBd;8ealTmbdnaCmbcbhCxekarcd4h8KdnazTmbaCcdthhcbhXayhYinaoazaXcdtfydba8K2cdtfhLasheaYhHaChOinaHaLaeydbcdtgQfIdbawaQfIdbNUdbaeclfheaHclfhHaOcufgOmbkaYahfhYaXcefgXal9hmbxdkkaCcdthhcbhXayhYinaoaXa8K2cdtfhLasheaYhHaChOinaHaLaeydbcdtgQfIdbawaQfIdbNUdbaeclfheaHclfhHaOcufgOmbkaYahfhYaXcefgXal9hmbkkcualc8S2gHalc;D;O;f8U0EgQcbyd1:jjjbHjjjjbbheasc:Cefasyd;8egOcdtfaeBdbasaOcefBd;8eaecbaHz:tjjjbh8ScbhDcbh8KdnaCTmbcbhIaQcbyd1:jjjbHjjjjbbh8Kasc:Cefasyd;8egecdtfa8KBdbasaecefBd;8ea8KcbaHz:tjjjb8AcuaCal2gecltgHaecFFFFb0Ecbyd1:jjjbHjjjjbbhDasc:Cefasyd;8egecdtfaDBdbasaecefBd;8eaDcbaHz:tjjjb8AamcjjjjdGTmbcualcltgealcFFFFb0Ecbyd1:jjjbHjjjjbbhIasc:Cefasyd;8egHcdtfaIBdbasaHcefBd;8eaIcbaez:tjjjb8AkdnadTmbcbhLabhHinaaaHclfydbgXcx2fgeIdbaaaHydbgYcx2fgOIdbgR:tg8UaaaHcwfydbghcx2fgQIdlaOIdlg8V:tg8WNaQIdbaR:tg8XaeIdla8V:tg8YN:tg8Zh80aeIdwaOIdwg81:tgBa8XNaQIdwa81:tg83a8UN:tgUh8Xa8Ya83Na8WaBN:tg8Yh8Udna8Za8ZNa8Ya8YNaUaUNMM:rgBJbbbb9EgOTmba8ZaB:vh80aUaB:vh8Xa8YaB:vh8Uka8SaAaYcdtfydbgQc8S2fgea8UaB:rg8Wa8UNNg85aeIdbMUdbaea8Xa8Wa8XNg86Ng87aeIdlMUdlaea80a8Wa80Ng83Ng88aeIdwMUdwaea86a8UNg86aeIdxMUdxaea83a8UNg89aeIdzMUdzaea83a8XNg8:aeIdCMUdCaea8Ua8Wa80a81Na8UaRNa8Va8XNMM:mgZNg83Ng8UaeIdKMUdKaea8Xa83Ng8XaeId3MUd3aea80a83Ng80aeIdaMUdaaea83aZNg83aeId8KMUd8Kaea8WaeIdyMUdya8SaAaXcdtfydbgXc8S2fgea85aeIdbMUdbaea87aeIdlMUdlaea88aeIdwMUdwaea86aeIdxMUdxaea89aeIdzMUdzaea8:aeIdCMUdCaea8UaeIdKMUdKaea8XaeId3MUd3aea80aeIdaMUdaaea83aeId8KMUd8Kaea8WaeIdyMUdya8SaAahcdtfydbgYc8S2fgea85aeIdbMUdbaea87aeIdlMUdlaea88aeIdwMUdwaea86aeIdxMUdxaea89aeIdzMUdzaea8:aeIdCMUdCaea8UaeIdKMUdKaea8XaeId3MUd3aea80aeIdaMUdaaea83aeId8KMUd8Kaea8WaeIdyMUdydnaITmbdnaOTmba8ZaB:vh8ZaUaB:vhUa8YaB:vh8YkaIaQcltfgeaBJbbbZNg8UaUNg8WaeIdlMUdlaea8Ua8ZNg8XaeIdwMUdwaea8Ua8YNg80aeIdbMUdbaea8UaR:ma8YNaUa8VN:ta81a8ZN:tNg8UaeIdxMUdxaIaXcltfgea8WaeIdlMUdlaea8XaeIdwMUdwaea80aeIdbMUdbaea8UaeIdxMUdxaIaYcltfgea8WaeIdlMUdlaea8XaeIdwMUdwaea80aeIdbMUdbaea8UaeIdxMUdxkaHcxfhHaLcifgLad6mbkkdnalTmbJ;n;m;m89J:v:;;w8ZamczGEh8YcbhOaAhQaahHa8SheindnaOaQydb9hmbaecxfgLaLIdbJbbbbMUdbaeczfgLaLIdbJbbbbMUdbaecCfgLaLIdbJbbbbMUdbaea8YaecyfgLIdbg8ZNg8UaeIdbMUdbaeclfgXa8UaXIdbMUdbaecwfgXa8UaXIdbMUdbaecKfgXaXIdbaHIdbg8Xa8UN:tUdbaHcwfIdbh8Waec3fgXaXIdba8UaHclfIdbg80N:tUdbaecafgXaXIdba8Ua8WN:tUdbaec8KfgXIdbhUaLa8Za8UMUdbaXaUa8Ua8Wa8WNa8Xa8XNa80a80NMMNMUdbkaQclfhQaHcxfhHaec8SfhealaOcefgO9hmbkkdnadTmbcbhhabhYinabahcdtfhXcbhHina5aXaHc:G1jjbfydbcdtfydbgOfRbbhedndna5aYaHfydbgQfRbbgLc99fcFeGcpe0mbaec99fcFeGc;:e6mekdnaLcufcFeGce0mba8EaQcdtfydbaO9hmekdnaecufcFeGce0mba8FaOcdtfydbaQ9hmekJbbacJbbacJbbbZaecFeGceSEaLcFeGceSEh88aaaOcx2fgeIdwaaaQcx2fgLIdwgB:tg80:mh86aeIdlaLIdlg83:tg8Z:mh89aeIdbaLIdbgR:tgU:mh8:dnaaaXaHc:K1jjbfydbcdtfydbcx2fgeIdwaB:tg8Va80a80NaUaUNa8Za8ZNMMg8YNa8Va80NaeIdbaR:tg81aUNa8ZaeIdla83:tg85NMMg8Wa80N:tg8Xa8XNa81a8YNa8WaUN:tg8Ua8UNa85a8YNa8Wa8ZN:tg8Wa8WNMM:rg87Jbbbb9ETmba8Xa87:vh8Xa8Wa87:vh8Wa8Ua87:vh8Uka88a8Y:rNg8Ya8XaBNa8UaRNa83a8WNMM:mgZNg87aZNhZa8Xa87Nhna8Wa87Nhca8Ua87Nh9ca8Ya8XNg87a8WNhJa87a8UNh9ea8Ya8WNgTa8UNhSa8Xa87Nh87a8WaTNhTa8Ua8Ya8UNNh9hdnaUa85Na81a89NMg8Xa8XNa8Za8VNa85a86NMg8Ua8UNa80a81Na8Va8:NMg8Wa8WNMM:rg80Jbbbb9ETmba8Xa80:vh8Xa8Wa80:vh8Wa8Ua80:vh8Uka8SaAaQcdtfydbc8S2fgeaeIdba9ha8Ua88a80:rNg80a8UNNMgUMUdbaeaTa8Wa80a8WNg8VNMg81aeIdlMUdlaea87a8Xa80a8XNg8ZNMg85aeIdwMUdwaeaSa8Va8UNMg8VaeIdxMUdxaea9ea8Za8UNMg87aeIdzMUdzaeaJa8Za8WNMg8ZaeIdCMUdCaea9ca8Ua80a8XaBNa8UaRNa83a8WNMMgB:mNg80NMg8UaeIdKMUdKaeaca8Wa80NMg8WaeId3MUd3aeana8Xa80NMg8XaeIdaMUdaaeaZaBa80N:tg80aeId8KMUd8Kaea8YJbbbbMg8YaeIdyMUdya8SaAaOcdtfydbc8S2fgeaUaeIdbMUdbaea81aeIdlMUdlaea85aeIdwMUdwaea8VaeIdxMUdxaea87aeIdzMUdzaea8ZaeIdCMUdCaea8UaeIdKMUdKaea8WaeId3MUd3aea8XaeIdaMUdaaea80aeId8KMUd8Kaea8YaeIdyMUdykaHclfgHcx9hmbkaYcxfhYahcifghad6mbkaCTmbcbhYinJbbbbh8YaaabaYcdtfgeclfydbghcx2fgHIdwaaaeydbggcx2fgOIdwg81:tg8Wa8WNaHIdbaOIdbg85:tg8Xa8XNaHIdlaOIdlg87:tg80a80NMMgRaaaecwfydbgEcx2fgeIdwa81:tg8ZNa8Wa8Wa8ZNa8XaeIdba85:tgUNa80aeIdla87:tgBNMMg8UN:tJbbbbJbbjZaRa8Za8ZNaUaUNaBaBNMMg8VNa8Ua8UN:tg83:va83Jbbbb9BEg83Nh89a8Va8WNa8Za8UN:ta83Nh8:aRaBNa80a8UN:ta83NhZa8Va80NaBa8UN:ta83NhnaRaUNa8Xa8UN:ta83Nhca8Va8XNaUa8UN:ta83Nh9ca8XaBNaUa80N:tg8Ua8UNa80a8ZNaBa8WN:tg8Ua8UNa8WaUNa8Za8XN:tg8Ua8UNMM:rJbbbZNh8UayagaC2g8LcdtfhHayaEaC2g8JcdtfhOayahaC2g8AcdtfhQa81:mhJa87:mh9ea85:mhTcbhLaChXJbbbbhBJbbbbh83JbbbbhRJbbbbh8VJbbbbh81Jbbbbh85Jbbbbh87Jbbbbh88Jbbbbh86inascjdfaLfgecwfa8Ua8:aQIdbaHIdbg8Z:tg80Na89aOIdba8Z:tgUNMg8WNUdbaeclfa8Uana80NaZaUNMg8XNUdbaea8Ua9ca80NacaUNMg80NUdbaecxfa8UaJa8WNa9ea8XNa8ZaTa80NMMMg8ZNUdba8Ua8Wa8XNNa8VMh8Va8Ua8Wa80NNa81Mh81a8Ua8Xa80NNa85Mh85a8Ua8Za8ZNNa8YMh8Ya8Ua8Wa8ZNNaBMhBa8Ua8Xa8ZNNa83Mh83a8Ua80a8ZNNaRMhRa8Ua8Wa8WNNa87Mh87a8Ua8Xa8XNNa88Mh88a8Ua80a80NNa86Mh86aHclfhHaQclfhQaOclfhOaLczfhLaXcufgXmbka8Kagc8S2fgea86aeIdbMUdbaea88aeIdlMUdlaea87aeIdwMUdwaea85aeIdxMUdxaea81aeIdzMUdzaea8VaeIdCMUdCaeaRaeIdKMUdKaea83aeId3MUd3aeaBaeIdaMUdaaea8YaeId8KMUd8Kaea8UaeIdyMUdya8Kahc8S2fgea86aeIdbMUdbaea88aeIdlMUdlaea87aeIdwMUdwaea85aeIdxMUdxaea81aeIdzMUdzaea8VaeIdCMUdCaeaRaeIdKMUdKaea83aeId3MUd3aeaBaeIdaMUdaaea8YaeId8KMUd8Kaea8UaeIdyMUdya8KaEc8S2fgea86aeIdbMUdbaea88aeIdlMUdlaea87aeIdwMUdwaea85aeIdxMUdxaea81aeIdzMUdzaea8VaeIdCMUdCaeaRaeIdKMUdKaea83aeId3MUd3aeaBaeIdaMUdaaea8YaeId8KMUd8Kaea8UaeIdyMUdyaDa8LcltfhXcbhHaChQinaXaHfgeascjdfaHfgOIdbaeIdbMUdbaeclfgLaOclfIdbaLIdbMUdbaecwfgLaOcwfIdbaLIdbMUdbaecxfgeaOcxfIdbaeIdbMUdbaHczfhHaQcufgQmbkaDa8AcltfhXcbhHaChQinaXaHfgeascjdfaHfgOIdbaeIdbMUdbaeclfgLaOclfIdbaLIdbMUdbaecwfgLaOcwfIdbaLIdbMUdbaecxfgeaOcxfIdbaeIdbMUdbaHczfhHaQcufgQmbkaDa8JcltfhXcbhHaChQinaXaHfgeascjdfaHfgOIdbaeIdbMUdbaeclfgLaOclfIdbaLIdbMUdbaecwfgLaOcwfIdbaLIdbMUdbaecxfgeaOcxfIdbaeIdbMUdbaHczfhHaQcufgQmbkaYcifgYad6mbkkcbhOdndnamcwGg9imbJbbbbhRcbh6cbh9kcbh0xekcbh6a3cbyd1:jjjbHjjjjbbh0asc:Cefasyd;8egecdtfa0BdbasaecefBd;8ecua0alabadaAz:fjjjbgQcltaQcjjjjiGEcbyd1:jjjbHjjjjbbh9kasc:Cefasyd;8egecdtfa9kBdbasaecefBd;8ea9kaQa0aaalz:gjjjbJFFuuhRaQTmba9kheaQhHinaeIdbg8UaRaRa8U9EEhRaeclfheaHcufgHmbkaQh6kasydNeh9mdnalTmba9mclfhea9mydbhQa5hHalhLcbhOincbaeydbgXaQ9RaHRbbcpeGEaOfhOaHcefhHaeclfheaXhQaLcufgLmbkaOce4hOkcuadaO9Rcifg9ncx2a9nc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbh9oasc:Cefasyd;8egecdtfa9oBdbasaecefBd;8ecua9ncdta9ncFFFFi0Ecbyd1:jjjbHjjjjbbh9pasc:Cefasyd;8egecdtfa9pBdbasaecefBd;8ea3cbyd1:jjjbHjjjjbbh8Pasc:Cefasyd;8egecdtfa8PBdbasaecefBd;8ealcbyd1:jjjbHjjjjbbh9qasc:Cefasyd;8egecdtfa9qBdbasaecefBd;8eaxaxNa8RJbbjZamclGEgnanN:vh88Jbbbbh86dnadak9nmbdna9nci6mbasyd:yeh9raCclth9sa9ocwfh9tJbbbbh87Jbbbbh86inascNefabadalaAz:cjjjbabhgcbh8Ncbh3inaba3cdtfh8LcbheindnaAagaefydbgOcdtghfydbgQaAa8Laec:W1jjbfydbcdtfydbgHcdtgEfydbgLSmba5aHfRbbgYcv2a5aOfRbbgXfc;a1jjbfRbbg8AaXcv2aYfg8Jc;a1jjbfRbbg8MVcFeGTmbdnaLaQ9nmba8Jc;G1jjbfRbbcFeGmekdnaXcufcFeGce0mbaYTmba8EahfydbaH9hmekdnaXTmbaYcufcFeGce0mba8FaEfydbaO9hmeka9oa8Ncx2fgQaHaOa8McFeGgLEBdlaQaOaHaLEBdbaQaLa8AGcb9hBdwa8Ncefh8Nkaeclfgecx9hmbkdna3cifg3ad9pmbagcxfhga8Ncifa9n9nmekka8NTmdcbh8Jina8SaAa9oa8Jcx2fghydbgLcdtgQfydbggc8S2fgeIdwaaahydlgXcx2fgHIdwg8XNaeIdzaHIdbg80NaeIdaMg8Ua8UMMa8XNaeIdlaHIdlg8ZNaeIdCa8XNaeId3Mg8Ua8UMMa8ZNaeIdba80NaeIdxa8ZNaeIdKMg8Ua8UMMa80NaeId8KMMM:lh8UJbbbbJbbjZaeIdyg8W:va8WJbbbb9BEh8Wdndnahydwg8LmbJFFuuh83xekJbbbbJbbjZa8SaAaXcdtfydbc8S2fgeIdygU:vaUJbbbb9BEaeIdwaaaLcx2fgHIdwgUNaeIdzaHIdbg8YNaeIdaMgBaBMMaUNaeIdlaHIdlgBNaeIdCaUNaeId3MgUaUMMaBNaeIdba8YNaeIdxaBNaeIdKMgUaUMMa8YNaeId8KMMM:lNh83ka8Wa8UNhBdnaCTmba8KaLc8S2fgOIdwa8XNaOIdza80NaOIdaMg8Ua8UMMa8XNaOIdla8ZNaOIdCa8XNaOId3Mg8Ua8UMMa8ZNaOIdba80NaOIdxa8ZNaOIdKMg8Ua8UMMa80NaOId8KMMMh8UayaXaC2gYcdtfhHaDaLaC2gEcltfheaOIdyhUaChOinaHIdbg8Wa8WaUNaecxfIdba8XaecwfIdbNa80aeIdbNa8ZaeclfIdbNMMMg8Wa8WM:tNa8UMh8UaHclfhHaeczfheaOcufgOmbkdndna8LmbJbbbbh8Wxeka8KaXc8S2fgOIdwaaaLcx2fgeIdwg80NaOIdzaeIdbg8ZNaOIdaMg8Wa8WMMa80NaOIdlaeIdlgUNaOIdCa80NaOId3Mg8Wa8WMMaUNaOIdba8ZNaOIdxaUNaOIdKMg8Wa8WMMa8ZNaOId8KMMMh8WayaEcdtfhHaDaYcltfheaOIdyh8YaChOinaHIdbg8Xa8Xa8YNaecxfIdba80aecwfIdbNa8ZaeIdbNaUaeclfIdbNMMMg8Xa8XM:tNa8WMh8WaHclfhHaeczfheaOcufgOmbka8W:lh8WkaBa8U:lMhBa83a8WMh83dndndna5aLfRbbc9:fPddbekaKaQfydbgQaLSmbaAaXcdtfydbhEindndna8EaQcdtgYfydbgecuSmbaAaecdtfydbaESmekdna8FaYfydbgecuSmbaAaecdtfydbaESmekaXheka8KaQc8S2fgOIdwaaaecx2fgHIdwg8XNaOIdzaHIdbg80NaOIdaMg8Ua8UMMa8XNaOIdlaHIdlg8ZNaOIdCa8XNaOId3Mg8Ua8UMMa8ZNaOIdba80NaOIdxa8ZNaOIdKMg8Ua8UMMa80NaOId8KMMMh8UayaeaC2cdtfhHaDaQaC2cltfheaOIdyhUaChOinaHIdbg8Wa8WaUNaecxfIdba8XaecwfIdbNa80aeIdbNa8ZaeclfIdbNMMMg8Wa8WM:tNa8UMh8UaHclfhHaeczfheaOcufgOmbkaBa8U:lMhBaKaYfydbgQaL9hmbkka5aXfRbbci9hmea8LTmeaKaXcdtfydbgQaXSmeindndna8EaQcdtgYfydbgecuSmbaAaecdtfydbagSmekdna8FaYfydbgecuSmbaAaecdtfydbagSmekaLheka8KaQc8S2fgOIdwaaaecx2fgHIdwg8XNaOIdzaHIdbg80NaOIdaMg8Ua8UMMa8XNaOIdlaHIdlg8ZNaOIdCa8XNaOId3Mg8Ua8UMMa8ZNaOIdba80NaOIdxa8ZNaOIdKMg8Ua8UMMa80NaOId8KMMMh8UayaeaC2cdtfhHaDaQaC2cltfheaOIdyhUaChOinaHIdbg8Wa8WaUNaecxfIdba8XaecwfIdbNa80aeIdbNa8ZaeclfIdbNMMMg8Wa8WM:tNa8UMh8UaHclfhHaeczfheaOcufgOmbka83a8U:lMh83aKaYfydbgQaX9hmbxdkkdna8Fa8Ea8EaQfydbaXSEaKaQfydbgYcdtfydbgQcu9hmbaKaXcdtfydbhQka8KaYc8S2fgOIdwaaaQcx2fgeIdwg8XNaOIdzaeIdbg80NaOIdaMg8Ua8UMMa8XNaOIdlaeIdlg8ZNaOIdCa8XNaOId3Mg8Ua8UMMa8ZNaOIdba80NaOIdxa8ZNaOIdKMg8Ua8UMMa80NaOId8KMMMh8UayaQaC2ggcdtfhHaDaYaC2gEcltfheaOIdyhUaChOinaHIdbg8Wa8WaUNaecxfIdba8XaecwfIdbNa80aeIdbNa8ZaeclfIdbNMMMg8Wa8WM:tNa8UMh8UaHclfhHaeczfheaOcufgOmbkdndna8LmbJbbbbh8Wxeka8KaQc8S2fgOIdwaaaYcx2fgeIdwg80NaOIdzaeIdbg8ZNaOIdaMg8Wa8WMMa80NaOIdlaeIdlgUNaOIdCa80NaOId3Mg8Wa8WMMaUNaOIdba8ZNaOIdxaUNaOIdKMg8Wa8WMMa8ZNaOId8KMMMh8WayaEcdtfhHaDagcltfheaOIdyh8YaChOinaHIdbg8Xa8Xa8YNaecxfIdba80aecwfIdbNa8ZaeIdbNaUaeclfIdbNMMMg8Xa8XM:tNa8WMh8WaHclfhHaeczfheaOcufgOmbka8W:lh8WkaBa8U:lMhBa83a8WMh83kaha83aBa83aB9DgeEUdwahaLaXaea8Lcb9hGgeEBdlahaXaLaeEBdba8Jcefg8Ja8N9hmbkascjdfcbcj;qbz:tjjjb8Aa9thea8NhHinascjdfaeydbcA4cF8FGgOcFAaOcFA6EcdtfgOaOydbcefBdbaecxfheaHcufgHmbkcbhecbhHinascjdfaefgOydbhQaOaHBdbaQaHfhHaeclfgecj;qb9hmbkcbhea9thHinascjdfaHydbcA4cF8FGgOcFAaOcFA6EcdtfgOaOydbgOcefBdba9paOcdtfaeBdbaHcxfhHa8Naecefge9hmbkadak9RgOci9Uh9udnalTmbcbhea8PhHinaHaeBdbaHclfhHalaecefge9hmbkkcbh9va9qcbalz:tjjjbh9waOcO9Uh9xa9uce4h9ycbh3cbh8Adnina9oa9pa8Acdtfydbcx2fg8JIdwg8Ua889Emea3a9u9pmeJFFuuh8Wdna9ya8N9pmba9oa9pa9ycdtfydbcx2fIdwJbb;aZNh8Wkdna8Ua8W9ETmba8Ua869ETmba3a9x0mdkdna9waAa8Jydlg8Mcdtg9zfgEydbgQfg9ARbba9waAa8Jydbggcdtg9Bfydbgefg9CRbbVmba5agfRbbh9Ddna9maecdtfgHclfydbgOaHydbgHSmbaOaH9RhLaaaQcx2fhYaaaecx2fhha9raHcitfhecbhHceh8Ldnindna8PaeydbcdtfydbgOaQSmba8PaeclfydbcdtfydbgXaQSmbaOaXSmbaaaXcx2fgXIdbaaaOcx2fgOIdbg8X:tg8UahIdlaOIdlg80:tg8YNahIdba8X:tgBaXIdla80:tg8WN:tg8Za8UaYIdla80:tg83NaYIdba8X:tg8Va8WN:tg80Na8WahIdwaOIdwgU:tg81Na8YaXIdwaU:tg8XN:tg8Ya8WaYIdwaU:tg85Na83a8XN:tg8WNa8XaBNa81a8UN:tgUa8Xa8VNa85a8UN:tg8UNMMa8Za8ZNa8Ya8YNaUaUNMMa80a80Na8Wa8WNa8Ua8UNMMN:rJbbj8:N9FmdkaecwfheaHcefgHaL6h8LaLaH9hmbkka8LceGTmba9ycefh9yxekdndndndna9Dc9:fPdebdkagheinaEydbhOdndna8EaecdtgHfydbgecuSmbaAaecdtfydbaOSmekdna8FaHfydbgecuSmbaAaecdtfydbaOSmeka8Mheka8PaHfaeBdbaKaHfydbgeag9hmbxikkdna8Fa8Ea8Ea9Bfydba8MSEaKa9Bfydbggcdtfydbgecu9hmbaKa9zfydbheka8Pa9Bfa8MBdbaeh8Mka8Pagcdtfa8MBdbka9Cce86bba9Ace86bba8JIdwg8Ua86a86a8U9DEh86a9vcefh9vcecda9DceSEa3fh3ka8Acefg8Aa8N9hmbkka9vTmddnalTmbcbhXcbhhindna8PahcdtgefydbgOahSmbaAaOcdtfydbhgdnahaAaefydb9hgEmba8Sagc8S2fgea8Sahc8S2fgHIdbaeIdbMUdbaeaHIdlaeIdlMUdlaeaHIdwaeIdwMUdwaeaHIdxaeIdxMUdxaeaHIdzaeIdzMUdzaeaHIdCaeIdCMUdCaeaHIdKaeIdKMUdKaeaHId3aeId3MUd3aeaHIdaaeIdaMUdaaeaHId8KaeId8KMUd8KaeaHIdyaeIdyMUdyaITmbaIagcltfgeaIahcltfgHIdbaeIdbMUdbaeaHIdlaeIdlMUdlaeaHIdwaeIdwMUdwaeaHIdxaeIdxMUdxkaCTmba8KaOc8S2fgea8Kahc8S2g8LfgHIdbaeIdbMUdbaeaHIdlaeIdlMUdlaeaHIdwaeIdwMUdwaeaHIdxaeIdxMUdxaeaHIdzaeIdzMUdzaeaHIdCaeIdCMUdCaeaHIdKaeIdKMUdKaeaHId3aeId3MUd3aeaHIdaaeIdaMUdaaeaHId8KaeId8KMUd8KaeaHIdyaeIdyMUdya9saO2hYaDhHaChQinaHaYfgeaHaXfgOIdbaeIdbMUdbaeclfgLaOclfIdbaLIdbMUdbaecwfgLaOcwfIdbaLIdbMUdbaecxfgeaOcxfIdbaeIdbMUdbaHczfhHaQcufgQmbkaEmbJbbbbJbbjZa8Sa8LfgeIdyg8U:va8UJbbbb9BEaeIdwaaagcx2fgHIdwg8UNaeIdzaHIdbg8WNaeIdaMg8Xa8XMMa8UNaeIdlaHIdlg8XNaeIdCa8UNaeId3Mg8Ua8UMMa8XNaeIdba8WNaeIdxa8XNaeIdKMg8Ua8UMMa8WNaeId8KMMM:lNg8Ua87a87a8U9DEh87kaXa9sfhXahcefghal9hmbkcbhHa8EheindnaeydbgOcuSmbdnaHa8PaOcdtgQfydbgO9hmbcuhOa8EaQfydbgQcuSmba8PaQcdtfydbhOkaeaOBdbkaeclfhealaHcefgH9hmbkcbhHa8FheindnaeydbgOcuSmbdnaHa8PaOcdtgQfydbgO9hmbcuhOa8FaQfydbgQcuSmba8PaQcdtfydbhOkaeaOBdbkaeclfhealaHcefgH9hmbkka87a86aCEh87cbhHabhecbhOindnaAa8PaeydbcdtfydbgXcdtfydbgQaAa8PaeclfydbcdtfydbgYcdtfydbgLSmbaQaAa8PaecwfydbcdtfydbggcdtfydbghSmbaLahSmbabaHcdtfgQaXBdbaQcwfagBdbaQclfaYBdbaHcifhHkaecxfheaOcifgOad6mbkdndna9imbaHhdxekdnaHak0mbaHhdxekdnaRa879FmbaHhdxekJFFuuhRcbhdabhecbhOindna9ka0aeydbgQcdtfydbcdtfIdbg8Ua879ETmbaeclf8Pdbh9EabadcdtfgLaQBdbaLclfa9E83dba8UaRaRa8U9EEhRadcifhdkaecxfheaOcifgOaH6mbkkadak0mbxdkkascNefabadalaAz:cjjjbkdndnadak0mbadhhxekdna9imbadhhxekdnaRa889FmbadhhxekcehLinaRJbb;aZNg8Ua88a8Ua889DEh8XJbbbbh8Udna6Tmba9khea6hHinaeIdbg8Wa8Ua8Wa8X9FEa8Ua8Wa8U9EEh8UaeclfheaHcufgHmbkkJFFuuhRcbhhabhecbhHindna9ka0aeydbgOcdtfydbcdtfIdbg8Wa8X9ETmbaeclf8Pdbh9EabahcdtfgQaOBdbaQclfa9E83dba8WaRaRa8W9EEhRahcifhhkaecxfheaHcifgHad6mbkdnaLahad9hVceGmbadhhxdka8Ua86a86a8U9DEh86ahak9nmecbhLahhdaRa889FmbkkdnamcjjjjdGTmba9qcbalz:tjjjbh8LdnahTmbabheahhHina8LaeydbgOfce86bba8LaAaOcdtfydbfce86bbaeclfheaHcufgHmbkkascNefabahalaAz:cjjjbdndndnalTmbcbhQasyd:yehEindna8LaQfRbbTmbdna5aQfRbbgecl0mbceaetcQGmekdnaAaQcdtgXfydbgeaQSmbaaaQcx2fgHaaaecx2fge8Pdb83dbaHcwfaecwfydbBdbxeka8SaQc8S2fgLIdyg9ca9cJL:3;rUNg8UMh88aLIdwg9ha8UMhRaLIdlgxa8UMh8VaLIdbg9Fa8UMhUaLIdag9Ga8UaaaQcx2fggIdwg89N:th81aLId3g9Ha8UagIdlg8:N:th85aLIdKg9IagIdbgZa8UN:th8YJbbbbhcaLIdCg9JJbbbbMh87aLIdzg9KJbbbbMhBaLIdxgWJbbbbMh83dndnaCTmbaQhOinJbbbba88a8KaOc8S2fgHIdyg8U:va8UJbbbb9BEh8UaDaOaC2cltfheaHIdaa88Na81Mh81aHId3a88Na85Mh85aHIdKa88Na8YMh8YaHIdCa88Na87Mh87aHIdza88NaBMhBaHIdxa88Na83Mh83aHIdwa88NaRMhRaHIdla88Na8VMh8VaHIdba88NaUMhUaChHina81aecxfIdbg8ZaecwfIdbg8WNa8UN:th81a85a8ZaeclfIdbg8XNa8UN:th85a87a8Wa8XNa8UN:th87aUaeIdbg80a80Na8UN:thUa8Ya8Za80Na8UN:th8YaBa8Wa80Na8UN:thBa83a8Xa80Na8UN:th83aRa8Wa8WNa8UN:thRa8Va8Xa8XNa8UN:th8VaeczfheaHcufgHmbkaKaOcdtfydbgOaQ9hmbkaITmbaIaQcltfgeIdxhSaeIdwhJaeIdlh9eaeIdbh8UxekJbbbbhSJbbbbhJJbbbbh9eJbbbbh8UkaBaU:vg8Xa8YNa81:ta87aBa83aU:vg8WN:tg81a8Va83a8WN:tg8Z:vg80a8Wa8YNa85:tg8VN:th85aJa8Ua8XN:ta9ea8Ua8WN:tg83a80N:tg87aRaBa8XN:ta81a80N:tgB:vgR:mh81a83a8Z:vgJ:mh9ednJbbbba8Ua8UaU:vgTN:ta83aJN:ta87aRN:tg83:la88J:983:g81Ng8U9ETmba81a85Na9ea8VNaTa8YNaS:tMMa83:vhckaU:la8U9ETmba8Z:la8U9ETmbaB:la8U9ETmbaT:macNa8X:ma81acNa85aB:vMgBNa8W:ma9eacNa80:maBNa8Va8Z:vMMg87Na8Y:maU:vMMMh88a9maXfgeclfydbgHaeydbge9RhYaEaecitfhXJbbbbh8UdnaHaeSg8JmbJbbbbh8UaXheaYhOinaaaeclfydbcx2fgHIdwa89:tg8Wa8WNaHIdbaZ:tg8Wa8WNaHIdla8::tg8Wa8WNMMg8Waaaeydbcx2fgHIdwa89:tg8Xa8XNaHIdbaZ:tg8Xa8XNaHIdla8::tg8Xa8XNMMg8Xa8Ua8Ua8X9DEg8Ua8Ua8W9DEh8UaecwfheaOcufgOmbkkaBa89:tg8Wa8WNa88aZ:tg8Wa8WNa87a8::tg8Wa8WNMMa8U:rg8Ua8UN9EmbaLId8Khcdna8JmbcbhOcehLdninaaaXclfydbcx2fgeIdbaaaXydbcx2fgHIdbg8X:tg8Ua8:aHIdlg80:tg8YNaZa8X:tg83aeIdla80:tg8WN:tg8Za8Ua87a80:tgRNa88a8X:tg8Va8WN:tg80Na8Wa89aHIdwgU:tg81Na8YaeIdwaU:tg8XN:tg8Ya8WaBaU:tg85NaRa8XN:tg8WNa8Xa83Na81a8UN:tgUa8Xa8VNa85a8UN:tg8UNMMa8Za8ZNa8Ya8YNaUaUNMMa80a80Na8Wa8WNa8Ua8UNMMN:rJbbj8:N9FmeaXcwfhXaOcefgOaY6hLaYaO9hmbkkaLceGmekJbbbbJbbjZa9c:va9cJbbbb9BEg8Ua9haBNa9Ka88Na9GMg8Wa8WMMaBNaxa87Na9JaBNa9HMg8Wa8WMMa87Na9Fa88NaWa87Na9IMg8Wa8WMMa88NacMMM:lNa8Ua9ha89Na9KaZNa9GMg8Wa8WMMa89Naxa8:Na9Ja89Na9HMg8Wa8WMMa8:Na9FaZNaWa8:Na9IMg8Wa8WMMaZNacMMM:lNJbb;aZNJ:983:g81M9EmbagaBUdwaga87Udlaga88UdbkaQcefgQal9hmbkaCTmecbhLindna8LaLfRbbTmbaAaLcdtgefydbaL9hmba5aLfhEaaaLcx2fhOaKaefh8JayaLaC2cdtfh8AcbhgincuhQdnaERbbci9hmbaLhQa8JydbgeaLSmbayagcdtgHfhXa8AaHfIdbh8UaLhQinaQhHcuhQdnaXaeaC2cdtfIdba8U9CmbaHcuSmbaHhQa8Kaec8S2fIdya8KaHc8S2fIdy9ETmbaehQkaKaecdtfydbgeaL9hmbkkayagcdtfhXaDagcltfhYaLheinaXaeaC2cdtfJbbbbJbbjZa8KaeaQaQcuSEgHc8S2fIdyg8U:va8UJbbbb9BEaYaHaC2cltfgHIdwaOIdwNaHIdbaOIdbNaHIdlaOIdlNMMaHIdxMNUdbaKaecdtfydbgeaL9hmbkagcefggaC9hmbkkaLcefgLalSmixbkkaCmekcbhCkaiavaoarawaCalaaayazasa8Rasc1efa5a8Laqz:hjjjbkdnamcjjjjlGTmbazmbahTmbcbhQabheina5aeydbgAfRbbc3thLaecwfgKydbhHdndna8EaAcdtgYfydbaeclfgXydbgOSmbcbhCa8FaOcdtfydbaA9hmekcjjjj94hCkaeaLaCVaAVBdba5aOfRbbc3thLdndna8EaOcdtfydbaHSmbcbhCa8FaHcdtfydbaO9hmekcjjjj94hCkaXaLaCVaOVBdba5aHfRbbc3thCdndna8EaHcdtfydbaASmbcbhOa8FaYfydbaH9hmekcjjjj94hOkaKaCaOVaHVBdbaecxfheaQcifgQah6mbkkdnazTmbahTmbahheinabazabydbcdtfydbBdbabclfhbaecufgembkkdnaPTmbaPana86:rNUdbkasyd;8egecdtasc:Ceffc98fhHdninaeTmeaHydbcbyd:m:jjjbH:bjjjbbaHc98fhHaecufhexbkkascj;sbf8Kjjjjbahk;Yieouabydlhvabydbclfcbaicdtz:tjjjbhoadci9UhrdnadTmbdnalTmbaehwadhDinaoalawydbcdtfydbcdtfgqaqydbcefBdbawclfhwaDcufgDmbxdkkaehwadhDinaoawydbcdtfgqaqydbcefBdbawclfhwaDcufgDmbkkdnaiTmbcbhDaohwinawydbhqawaDBdbawclfhwaqaDfhDaicufgimbkkdnadci6mbinaecwfydbhwaeclfydbhDaeydbhidnalTmbalawcdtfydbhwalaDcdtfydbhDalaicdtfydbhikavaoaicdtfgqydbcitfaDBdbavaqydbcitfawBdlaqaqydbcefBdbavaoaDcdtfgqydbcitfawBdbavaqydbcitfaiBdlaqaqydbcefBdbavaoawcdtfgwydbcitfaiBdbavawydbcitfaDBdlawawydbcefBdbaecxfhearcufgrmbkkabydbcbBdbk:todDue99aicd4aifhrcehwinawgDcethwaDar6mbkcuaDcdtgraDcFFFFi0Ecbyd1:jjjbHjjjjbbhwaoaoyd9GgqcefBd9GaoaqcdtfawBdbawcFearz:tjjjbhkdnaiTmbalcd4hlaDcufhxcbhminamhDdnavTmbavamcdtfydbhDkcbadaDal2cdtfgDydlgwawcjjjj94SEgwcH4aw7c:F:b:DD2cbaDydbgwawcjjjj94SEgwcH4aw7c;D;O:B8J27cbaDydwgDaDcjjjj94SEgDcH4aD7c:3F;N8N27axGhwamcdthPdndndnavTmbakawcdtfgrydbgDcuSmeadavaPfydbal2cdtfgsIdbhzcehqinaqhrdnadavaDcdtfydbal2cdtfgqIdbaz9CmbaqIdlasIdl9CmbaqIdwasIdw9BmlkarcefhqakawarfaxGgwcdtfgrydbgDcu9hmbxdkkakawcdtfgrydbgDcuSmbadamal2cdtfgsIdbhzcehqinaqhrdnadaDal2cdtfgqIdbaz9CmbaqIdlasIdl9CmbaqIdwasIdw9BmikarcefhqakawarfaxGgwcdtfgrydbgDcu9hmbkkaramBdbamhDkabaPfaDBdbamcefgmai9hmbkkakcbyd:m:jjjbH:bjjjbbaoaoyd9GcufBd9GdnaeTmbaiTmbcbhDaehwinawaDBdbawclfhwaiaDcefgD9hmbkcbhDaehwindnaDabydbgrSmbawaearcdtfgrydbBdbaraDBdbkawclfhwabclfhbaiaDcefgD9hmbkkk:hrdvuv998Jjjjjbca9Rgoczfcwfcbyd11jjbBdbaocb8Pdj1jjb83izaocwfcbydN1jjbBdbaocb8Pd:m1jjb83ibdnadTmbaicd4hrdnabmbdnalTmbcbhwinaealawcdtfydbar2cdtfhDcbhiinaoczfaifgqaDaifIdbgkaqIdbgxaxak9EEUdbaoaifgqakaqIdbgxaxak9DEUdbaiclfgicx9hmbkawcefgwad9hmbxikkarcdthwcbhDincbhiinaoczfaifgqaeaifIdbgkaqIdbgxaxak9EEUdbaoaifgqakaqIdbgxaxak9DEUdbaiclfgicx9hmbkaeawfheaDcefgDad9hmbxdkkdnalTmbcbhwinabawcx2fgiaealawcdtfydbar2cdtfgDIdbUdbaiaDIdlUdlaiaDIdwUdwcbhiinaoczfaifgqaDaifIdbgkaqIdbgxaxak9EEUdbaoaifgqakaqIdbgxaxak9DEUdbaiclfgicx9hmbkawcefgwad9hmbxdkkarcdthlcbhwaehDinabawcx2fgiaeawar2cdtfgqIdbUdbaiaqIdlUdlaiaqIdwUdwcbhiinaoczfaifgqaDaifIdbgkaqIdbgxaxak9EEUdbaoaifgqakaqIdbgxaxak9DEUdbaiclfgicx9hmbkaDalfhDawcefgwad9hmbkkJbbbbaoIdbaoIdzgx:tgkakJbbbb9DEgkaoIdlaoIdCgm:tgPaPak9DEgkaoIdwaoIdKgP:tgsasak9DEhsdnabTmbadTmbJbbbbJbbjZas:vasJbbbb9BEhkinabakabIdbax:tNUdbabclfgoakaoIdbam:tNUdbabcwfgoakaoIdbaP:tNUdbabcxfhbadcufgdmbkkdnavTmbavaPUdwavamUdlavaxUdbkask:ZlewudnaeTmbcbhvabhoinaoavBdbaoclfhoaeavcefgv9hmbkkdnaiTmbcbhrinadarcdtfhwcbhDinalawaDcdtgvc:G1jjbfydbcdtfydbcdtfydbhodnabalawavfydbcdtfydbgqcdtfgkydbgvaqSmbinakabavgqcdtfgxydbgvBdbaxhkaqav9hmbkkdnabaocdtfgkydbgvaoSmbinakabavgocdtfgxydbgvBdbaxhkaoav9hmbkkdnaqaoSmbabaqaoaqao0Ecdtfaqaoaqao6EBdbkaDcefgDci9hmbkarcifgrai6mbkkdnaembcbskcbhxindnalaxcdtgvfydbax9hmbaxhodnabavfgDydbgvaxSmbaDhqinaqabavgocdtfgkydbgvBdbakhqaoav9hmbkkaDaoBdbkaxcefgxae9hmbkcbhvabhocbhkindndnavalydbgq9hmbdnavaoydbgq9hmbaoakBdbakcefhkxdkaoabaqcdtfydbBdbxekaoabaqcdtfydbBdbkaoclfhoalclfhlaeavcefgv9hmbkakk;Jiilud99duabcbaecltz:tjjjbhvdnalTmbadhoaihralhwinarcwfIdbhDarclfIdbhqavaoydbcltfgkarIdbakIdbMUdbakclfgxaqaxIdbMUdbakcwfgxaDaxIdbMUdbakcxfgkakIdbJbbjZMUdbaoclfhoarcxfhrawcufgwmbkkdnaeTmbavhraehkinarcxfgoIdbhDaocbBdbararIdbJbbbbJbbjZaD:vaDJbbbb9BEgDNUdbarclfgoaDaoIdbNUdbarcwfgoaDaoIdbNUdbarczfhrakcufgkmbkkdnalTmbinavadydbcltfgrcxfgkaicwfIdbarcwfIdb:tgDaDNaiIdbarIdb:tgDaDNaiclfIdbarclfIdb:tgDaDNMMgDakIdbgqaqaD9DEUdbadclfhdaicxfhialcufglmbkkdnaeTmbavcxfhrinabarIdbUdbarczfhrabclfhbaecufgembkkk:moerudnaoTmbaecd4hzdnavTmbaicd4hHavcdthOcbhAindnaPaAfRbbTmbaAhednaDTmbaDaAcdtfydbhekdnasTmbasaefRbbceGmekdnamaAfRbbclSmbabaeaz2cdtfgiaraAcx2fgCIdbakNaxIdbMUdbaiaCIdlakNaxIdlMUdlaiaCIdwakNaxIdwMUdwkadaeaH2cdtfhXaqheawhiavhCinaXaeydbcdtgQfaiIdbalaQfIdb:vUdbaeclfheaiclfhiaCcufgCmbkkawaOfhwaAcefgAao9hmbxdkkdnasmbcbheaDhiindnaPaefRbbTmbaehCdnaDTmbaiydbhCkamaefRbbclSmbabaCaz2cdtfgCarIdbakNaxIdbMUdbaCarclfIdbakNaxIdlMUdlaCarcwfIdbakNaxIdwMUdwkaiclfhiarcxfhraoaecefge9hmbxdkkdnaDTmbindnaPRbbTmbasaDydbgefRbbceGmbamRbbclSmbabaeaz2cdtfgearIdbakNaxIdbMUdbaearclfIdbakNaxIdlMUdlaearcwfIdbakNaxIdwMUdwkaPcefhPaDclfhDamcefhmarcxfhraocufgombxdkkazcdthicbheindnaPaefRbbTmbasaefRbbceGmbamaefRbbclSmbabarIdbakNaxIdbMUdbabclfarclfIdbakNaxIdlMUdbabcwfarcwfIdbakNaxIdwMUdbkarcxfhrabaifhbaoaecefge9hmbkkk8MbabaeadaialavcbcbcbcbcbaoarawaDz:bjjjbk8MbabaeadaialavaoarawaDaqakaxamaPz:bjjjbkRbababaeadaialavaoarawaDaqakaxcjjjjdVamz:bjjjbk:d8Koque99due99duq998Jjjjjbc;Wb9Rgq8Kjjjjbcbhkaqcxfcbc;Kbz:tjjjb8Aaqcualcx2alc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbgxBdxaqceBd2axaialavcbcbz:ejjjb8AaqcualcdtalcFFFFi0Egmcbyd1:jjjbHjjjjbbgiBdzaqcdBd2dndnJFF959eJbbjZawJbbjZawJbbjZ9DE:vawJ9VO:d869DEgw:lJbbb9p9DTmbaw:OhPxekcjjjj94hPkadci9Uhsarco9UhzdndnaombaPcd9imekdnalTmbaPcuf:YhwdnaoTmbcbhvaihHaxhOindndnaoavfRbbceGTmbavcjjjjlVhAxekdndnaOclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhAxekcjjjj94hAkaAcqthAdndnaOcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaAaXVhAdndnaOIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaAaXcCtVhAkaHaABdbaHclfhHaOcxfhOalavcefgv9hmbxdkkaxhvaihOalhHindndnavIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhAxekcjjjj94hAkaAcCthAdndnavclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaXcqtaAVhAdndnavcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaOaAaXVBdbavcxfhvaOclfhOaHcufgHmbkkadTmbcbhkaehvcbhOinakaiavclfydbcdtfydbgHaiavcwfydbcdtfydbgA9haiavydbcdtfydbgXaH9haXaA9hGGfhkavcxfhvaOcifgOad6mbkkarci9UhQdndnaz:Z:rJbbbZMgw:lJbbb9p9DTmbaw:Ohvxekcjjjj94hvkaQ:ZhLcbhKc:bwhzdninakaQ9pmeazaP9Rcd9imeavazcufavaz9iEaPcefavaP9kEhYdnalTmbaYcuf:YhwdnaoTmbcbhOaihHaxhvindndnaoaOfRbbceGTmbaOcjjjjlVhAxekdndnavclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhAxekcjjjj94hAkaAcqthAdndnavcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaAaXVhAdndnavIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaAaXcCtVhAkaHaABdbaHclfhHavcxfhvalaOcefgO9hmbxdkkaxhvaihOalhHindndnavIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhAxekcjjjj94hAkaAcCthAdndnavclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaXcqtaAVhAdndnavcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaOaAaXVBdbavcxfhvaOclfhOaHcufgHmbkkcbhOdnadTmbaehvcbhHinaOaiavclfydbcdtfydbgAaiavcwfydbcdtfydbgX9haiavydbcdtfydbgraA9haraX9hGGfhOavcxfhvaHcifgHad6mbkkJbbbbh8Adnas:ZgCaL:taY:Ygwaz:Y:tgENak:Zg3aO:Zg5:tNa3aL:tawaP:Y:tg8ENa5aC:tNMg8FJbbbb9BmbaCa3:ta8EaEa5aL:tNNNa8F:vh8AkdndnaOaQ0mbaOhkaYhPxekaOhsaYhzkdndnaKcl0mbdna8AawMJbbbZMgw:lJbbb9p9DTmbaw:Ohvxdkcjjjj94hvxekaPazfcd9ThvkaKcefgKcs9hmbkkdndndnakmbJbbjZhwcbhicdhvaDmexdkalcd4alfhHcehOinaOgvcethOavaH6mbkcbhOaqcuavcdtgYavcFFFFi0Ecbyd1:jjjbHjjjjbbgKBdCaqciBd2aqamcbyd1:jjjbHjjjjbbgzBdKaqclBd2dndndndnalTmbaPcuf:YhwaoTmecbhOaihAaxhHindndnaoaOfRbbceGTmbaOcjjjjlVhXxekdndnaHclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaXcqthXdndnaHcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:Ohrxekcjjjj94hrkaXarVhXdndnaHIdbawNJbbbZMgC:lJbbb9p9DTmbaC:Ohrxekcjjjj94hrkaXarcCtVhXkaAaXBdbaAclfhAaHcxfhHalaOcefgO9hmbxikkaKcFeaYz:tjjjb8AcbhPcbhvxdkaxhOaihHalhAindndnaOIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaXcCthXdndnaOclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:Ohrxekcjjjj94hrkarcqtaXVhXdndnaOcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:Ohrxekcjjjj94hrkaHaXarVBdbaOcxfhOaHclfhHaAcufgAmbkkaKcFeaYz:tjjjbhravcufhocbhPcbhYindndndnaraiaYcdtgKfydbgAcm4aA7c:v;t;h;Ev2gvcs4av7aoGgHcdtfgXydbgOcuSmbcehvinaiaOcdtgOfydbaASmdaHavfhOavcefhvaraOaoGgHcdtfgXydbgOcu9hmbkkaXaYBdbaPhvaPcefhPxekazaOfydbhvkazaKfavBdbaYcefgYal9hmbkcuaPc8S2gOaPc;D;O;f8U0Ehvkcbhraqavcbyd1:jjjbHjjjjbbgvBd3aqcvBd2avcbaOz:tjjjbhOdnadTmbaehiinJbbnnJbbjZazaiydbgAcdtfydbgvazaiclfydbgHcdtfydbgYSavazaicwfydbgXcdtfydbgKSGgoEh8EdnaxaHcx2fgHIdbaxaAcx2fgAIdbg5:tgCaxaXcx2fgXIdlaAIdlg8A:tgwNaXIdba5:tg3aHIdla8A:tg8FN:tgLaLNa8FaXIdwaAIdwgE:tgaNawaHIdwaE:tg8FN:tgwawNa8Fa3NaaaCN:tgCaCNMM:rg3Jbbbb9ETmbaLa3:vhLaCa3:vhCawa3:vhwkaOavc8S2fgvavIdbawa8Ea3:rNg3awNNg8FMUdbavaCa3aCNgaNghavIdlMUdlavaLa3aLNg8ENggavIdwMUdwavaaawNgaavIdxMUdxava8EawNg8JavIdzMUdzava8EaCNg8EavIdCMUdCavawa3aLaENawa5Na8AaCNMM:mg8ANg5NgwavIdKMUdKavaCa5NgCavId3MUd3avaLa5NgLavIdaMUdaava5a8ANg5avId8KMUd8Kava3avIdyMUdydnaombaOaYc8S2fgva8FavIdbMUdbavahavIdlMUdlavagavIdwMUdwavaaavIdxMUdxava8JavIdzMUdzava8EavIdCMUdCavawavIdKMUdKavaCavId3MUd3avaLavIdaMUdaava5avId8KMUd8Kava3avIdyMUdyaOaKc8S2fgva8FavIdbMUdbavahavIdlMUdlavagavIdwMUdwavaaavIdxMUdxava8JavIdzMUdzava8EavIdCMUdCavawavIdKMUdKavaCavId3MUd3avaLavIdaMUdaava5avId8KMUd8Kava3avIdyMUdykaicxfhiarcifgrad6mbkkcbhAaqcuaPcdtgvaPcFFFFi0Egicbyd1:jjjbHjjjjbbgHBdaaqcoBd2aqaicbyd1:jjjbHjjjjbbgiBd8KaqcrBd2aHcFeavz:tjjjbhYdnalTmbazhHinJbbbbJbbjZaOaHydbgXc8S2fgvIdygw:vawJbbbb9BEavIdwaxcwfIdbgwNavIdzaxIdbgCNavIdaMgLaLMMawNavIdlaxclfIdbgLNavIdCawNavId3MgwawMMaLNavIdbaCNavIdxaLNavIdKMgwawMMaCNavId8KMMM:lNhwdndnaYaXcdtgvfgXydbcuSmbaiavfIdbaw9ETmekaXaABdbaiavfawUdbkaHclfhHaxcxfhxalaAcefgA9hmbkkJbbbbhwdnaPTmbinaiIdbgCawawaC9DEhwaiclfhiaPcufgPmbkkakcd4akfhOcehiinaigvcethiavaO6mbkcbhiaqcuavcdtgOavcFFFFi0Ecbyd1:jjjbHjjjjbbgHBdyaHcFeaOz:tjjjbhXdnadTmbavcufhrcbhPcbhxindnazaeaxcdtfgvydbcdtfydbgiazavclfydbcdtfydbgOSmbaiazavcwfydbcdtfydbgvSmbaOavSmbaYavcdtfydbhAdndnaYaOcdtfydbgvaYaicdtfydbgi9pmbavaA9pmbaAhlaihoavhAxekdnaAai9pmbaAav9pmbaihlavhoxekavhlaAhoaihAkabaPcx2fgvaABdbavcwfaoBdbavclfalBdbdnaXaoc:3F;N8N2alc:F:b:DD27aAc;D;O:B8J27arGgOcdtfgvydbgicuSmbcehHinaHhvdnabaicx2fgiydbaA9hmbaiydlal9hmbaiydwaoSmikavcefhHaXaOavfarGgOcdtfgvydbgicu9hmbkkavaPBdbaPcefhPkaxcifgxad6mbkaPci2hikdnaDmbcwhvxdkaw:rhwcwhvkaDawUdbkavcdthvdninavTmeavc98fgvaqcxffydbcbyd:m:jjjbH:bjjjbbxbkkaqc;Wbf8Kjjjjbaik:2ldwue9:8Jjjjjbc;Wb9Rgr8Kjjjjbcbhwarcxfcbc;Kbz:tjjjb8AdnabaeSmbabaeadcdtzMjjjb8AkarcualcdtalcFFFFi0EgDcbyd1:jjjbHjjjjbbgqBdxarceBd2aqcbaialavcbarcxfz:djjjbcualcx2alc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbhkarcxfaryd2gxcdtgmfakBdbaraxcefgPBd2akaialavcbcbz:ejjjb8AarcxfaPcdtfaDcbyd1:jjjbHjjjjbbgvBdbaraxcdfgiBd2arcxfaicdtfcuavalaeadaqz:fjjjbgecltaecjjjjiGEcbyd1:jjjbHjjjjbbgiBdbaiaeavakalz:gjjjbdnadTmbaoaoNhocbhwabhlcbhkindnaiavalydbgecdtfydbcdtfIdbao9ETmbalclf8PdbhsabawcdtfgqaeBdbaqclfas83dbawcifhwkalcxfhlakcifgkad6mbkkaxcifhlamarcxffcwfhkdninalTmeakydbcbyd:m:jjjbH:bjjjbbakc98fhkalcufhlxbkkarc;Wbf8Kjjjjbawk:XCoDud99vue99vuo998Jjjjjbc;Wb9Rgw8KjjjjbdndnarmbcbhDxekawcxfcbc;Kbz:tjjjb8Aawcuadcx2adc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbgqBdxawceBd2aqaeadaicbcbz:ejjjb8AawcuadcdtadcFFFFi0Egkcbyd1:jjjbHjjjjbbgxBdzawcdBd2adcd4adfhmceheinaegicetheaiam6mbkcbhPawcuaicdtgsaicFFFFi0Ecbyd1:jjjbHjjjjbbgzBdCawciBd2dndnar:ZgH:rJbbbZMgO:lJbbb9p9DTmbaO:Ohexekcjjjj94hekaicufhAc:bwhDcbhCadhXcbhQinaeaDcufaeaD9iEaPcefaeaP9kEhLdndnadTmbaLcuf:YhOaqhiaxheadhmindndnaiIdbaONJbbbZMgK:lJbbb9p9DTmbaK:OhYxekcjjjj94hYkaYcCthYdndnaiclfIdbaONJbbbZMgK:lJbbb9p9DTmbaK:Oh8Axekcjjjj94h8Aka8AcqtaYVhYdndnaicwfIdbaONJbbbZMgK:lJbbb9p9DTmbaK:Oh8Axekcjjjj94h8AkaeaYa8AVBdbaicxfhiaeclfheamcufgmmbkazcFeasz:tjjjbhEcbh3cbh5indnaEaxa5cdtfydbgYcm4aY7c:v;t;h;Ev2gics4ai7aAGgmcdtfg8AydbgecuSmbaeaYSmbcehiinaEamaifaAGgmcdtfg8AydbgecuSmeaicefhiaeaY9hmbkka8AaYBdba3aecuSfh3a5cefg5ad9hmbxdkkazcFeasz:tjjjb8Acbh3kJbbbbh8EdnaX:ZgKaH:taL:YgOaD:Y:tg8FNaC:Zgaa3:Zgh:tNaaaH:taOaP:Y:tggNahaK:tNMg8JJbbbb9BmbaKaa:taga8FahaH:tNNNa8J:vh8EkaPaLa3ar0giEhPaCa3aiEhCdna3arSmbaLaDaiEgDaP9Rcd9imbdndnaQcl0mbdna8EaOMJbbbZMgO:lJbbb9p9DTmbaO:Ohexdkcjjjj94hexekaPaDfcd9Theka3aXaiEhXaQcefgQcs9hmekkdndnaCmbcihicbhDxekcbhiawakcbyd1:jjjbHjjjjbbg5BdKawclBd2aPcuf:YhKdndnadTmbaqhiaxheadhmindndnaiIdbaKNJbbbZMgO:lJbbb9p9DTmbaO:OhYxekcjjjj94hYkaYcCthYdndnaiclfIdbaKNJbbbZMgO:lJbbb9p9DTmbaO:Oh8Axekcjjjj94h8Aka8AcqtaYVhYdndnaicwfIdbaKNJbbbZMgO:lJbbb9p9DTmbaO:Oh8Axekcjjjj94h8AkaeaYa8AVBdbaicxfhiaeclfheamcufgmmbkazcFeasz:tjjjbhEcbhDcbh3indndndnaEaxa3cdtgLfydbgYcm4aY7c:v;t;h;Ev2gics4ai7aAGgmcdtfg8AydbgecuSmbcehiinaxaecdtgefydbaYSmdamaifheaicefhiaEaeaAGgmcdtfg8Aydbgecu9hmbkka8Aa3BdbaDhiaDcefhDxeka5aefydbhika5aLfaiBdba3cefg3ad9hmbkcuaDc32giaDc;j:KM;jb0EhexekazcFeasz:tjjjb8AcbhDcbhekawaecbyd1:jjjbHjjjjbbgeBd3awcvBd2aecbaiz:tjjjbh8Aavcd4hxdnadTmbdnalTmbaxcdthEa5hYaqhealhmadhAina8AaYydbc32fgiaeIdbaiIdbMUdbaiaeclfIdbaiIdlMUdlaiaecwfIdbaiIdwMUdwaiamIdbaiIdxMUdxaiamclfIdbaiIdzMUdzaiamcwfIdbaiIdCMUdCaiaiIdKJbbjZMUdKaYclfhYaecxfheamaEfhmaAcufgAmbxdkka5hmaqheadhYina8Aamydbc32fgiaeIdbaiIdbMUdbaiaeclfIdbaiIdlMUdlaiaecwfIdbaiIdwMUdwaiaiIdxJbbbbMUdxaiaiIdzJbbbbMUdzaiaiIdCJbbbbMUdCaiaiIdKJbbjZMUdKamclfhmaecxfheaYcufgYmbkkdnaDTmba8AhiaDheinaiaiIdbJbbbbJbbjZaicKfIdbgO:vaOJbbbb9BEgONUdbaiclfgmaOamIdbNUdbaicwfgmaOamIdbNUdbaicxfgmaOamIdbNUdbaiczfgmaOamIdbNUdbaicCfgmaOamIdbNUdbaic3fhiaecufgembkkcbhYawcuaDcdtgLaDcFFFFi0Egicbyd1:jjjbHjjjjbbgeBdaawcoBd2awaicbyd1:jjjbHjjjjbbgEBd8KaecFeaLz:tjjjbh3dnadTmbJbbjZJbbjZaK:vaPceSEaoNgOaONhKaxcdthxalheinaKaec;81jjbalEgmIdwa8Aa5ydbgAc32fgiIdC:tgOaONamIdbaiIdx:tgOaONamIdlaiIdz:tgOaONMMNaqcwfIdbaiIdw:tgOaONaqIdbaiIdb:tgOaONaqclfIdbaiIdl:tgOaONMMMhOdndna3aAcdtgifgmydbcuSmbaEaifIdbaO9ETmekamaYBdbaEaifaOUdbka5clfh5aqcxfhqaeaxfheadaYcefgY9hmbkkaba3aLzMjjjb8AcrhikaicdthiinaiTmeaic98fgiawcxffydbcbyd:m:jjjbH:bjjjbbxbkkawc;Wbf8KjjjjbaDk:Ydidui99ducbhi8Jjjjjbca9Rglczfcwfcbyd11jjbBdbalcb8Pdj1jjb83izalcwfcbydN1jjbBdbalcb8Pd:m1jjb83ibdndnaembJbbjFhvJbbjFhoJbbjFhrxekadcd4cdthwincbhdinalczfadfgDabadfIdbgvaDIdbgoaoav9EEUdbaladfgDavaDIdbgoaoav9DEUdbadclfgdcx9hmbkabawfhbaicefgiae9hmbkalIdwalIdK:thralIdlalIdC:thoalIdbalIdz:thvkJbbbbavavJbbbb9DEgvaoaoav9DEgvararav9DEk9DeeuabcFeaicdtz:tjjjbhlcbhbdnadTmbindnalaeydbcdtfgiydbcu9hmbaiabBdbabcefhbkaeclfheadcufgdmbkkabk;7idqui998Jjjjjbc;Wb9Rgl8Kjjjjbalcxfcbc;Kbz:tjjjb8Aadcd4adfhvcehoinaogrcethoarav6mbkalcuarcdtgoarcFFFFi0Ecbyd1:jjjbHjjjjbbgvBdxavcFeaoz:tjjjbhwdnadTmbaicd4hDarcufhqcbhkindndnawcbaeakaD2cdtfgrydlgiaicjjjj94SEgocH4ao7c:F:b:DD2cbarydbgxaxcjjjj94SEgocH4ao7c;D;O:B8J27cbarydwgmamcjjjj94SEgrcH4ar7c:3F;N8N27aqGgvcdtfgrydbgocuSmbam::hPai::hsax::hzcehiinaihrdnaeaoaD2cdtfgiIdbaz9CmbaiIdlas9CmbaiIdwaP9BmikarcefhiawavarfaqGgvcdtfgrydbgocu9hmbkkarakBdbakhokabakcdtfaoBdbakcefgkad9hmbkkcbhrdninarc98Smealcxfarfydbcbyd:m:jjjbH:bjjjbbarc98fhrxbkkalc;Wbf8Kjjjjbk9teiucbcbyd:q:jjjbgeabcifc98GfgbBd:q:jjjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaik;teeeudndnaeabVciGTmbabhixekdndnadcz9pmbabhixekabhiinaiaeydbBdbaiaeydlBdlaiaeydwBdwaiaeydxBdxaeczfheaiczfhiadc9Wfgdcs0mbkkadcl6mbinaiaeydbBdbaeclfheaiclfhiadc98fgdci0mbkkdnadTmbinaiaeRbb86bbaicefhiaecefheadcufgdmbkkabk:3eedudndnabciGTmbabhixekaecFeGc:b:c:ew2hldndnadcz9pmbabhixekabhiinaialBdxaialBdwaialBdlaialBdbaiczfhiadc9Wfgdcs0mbkkadcl6mbinaialBdbaiclfhiadc98fgdci0mbkkdnadTmbinaiae86bbaicefhiadcufgdmbkkabk9teiucbcbyd:q:jjjbgeabcrfc94GfgbBd:q:jjjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaikTeeucbabcbyd:q:jjjbge9Rcifc98GaefgbBd:q:jjjbdnabZbcztge9nmbabae9RcFFifcz4nb8Akkk:Iedbcjwk1eFFuuFFuuFFuuFFuFFFuFFFuFbbbbbbbbebbbdbbbbbbbebbbebbbdbbbbbbbbbbbeeeeebebbebbebebbbeebbbbbbbbbbbbeeeeeebebbeeebeebbbbebebbbbbbbbbbbbbbbbbbc1Dkxebbbdbbb:GNbb'; // embed! wasm
18496
+
18497
+ var wasmpack = new Uint8Array([
18498
+ 32, 0, 65, 2, 1, 106, 34, 33, 3, 128, 11, 4, 13, 64, 6, 253, 10, 7, 15, 116, 127, 5, 8, 12, 40, 16, 19, 54, 20, 9, 27, 255, 113, 17, 42, 67,
18499
+ 24, 23, 146, 148, 18, 14, 22, 45, 70, 69, 56, 114, 101, 21, 25, 63, 75, 136, 108, 28, 118, 29, 73, 115,
18500
+ ]);
18501
+
18502
+ if (typeof WebAssembly !== 'object') {
18503
+ return {
18504
+ supported: false,
18505
+ };
18506
+ }
18507
+
18508
+ var instance;
18509
+
18510
+ var ready = WebAssembly.instantiate(unpack(wasm), {}).then(function (result) {
18511
+ instance = result.instance;
18512
+ instance.exports.__wasm_call_ctors();
18513
+ });
18514
+
18515
+ function unpack(data) {
18516
+ var result = new Uint8Array(data.length);
18517
+ for (var i = 0; i < data.length; ++i) {
18518
+ var ch = data.charCodeAt(i);
18519
+ result[i] = ch > 96 ? ch - 97 : ch > 64 ? ch - 39 : ch + 4;
18520
+ }
18521
+ var write = 0;
18522
+ for (var i = 0; i < data.length; ++i) {
18523
+ result[write++] = result[i] < 60 ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i];
18524
+ }
18525
+ return result.buffer.slice(0, write);
18526
+ }
18527
+
18528
+ function assert(cond) {
18529
+ if (!cond) {
18530
+ throw new Error('Assertion failed');
18531
+ }
18532
+ }
18533
+
18534
+ function bytes(view) {
18535
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
18536
+ }
18537
+
18538
+ function genremap(fun, positions, vertices, stride) {
18539
+ var sbrk = instance.exports.sbrk;
18540
+ var rp = sbrk(vertices * 4);
18541
+ var sp = sbrk(vertices * stride * 4);
18542
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18543
+ heap.set(bytes(positions), sp);
18544
+ fun(rp, sp, vertices, stride * 4);
18545
+ // heap may have grown
18546
+ heap = new Uint8Array(instance.exports.memory.buffer);
18547
+ var remap = new Uint32Array(vertices);
18548
+ new Uint8Array(remap.buffer).set(heap.subarray(rp, rp + vertices * 4));
18549
+ sbrk(rp - sbrk(0));
18550
+ return remap;
18551
+ }
18552
+
18553
+ function reorder(fun, indices, vertices) {
18554
+ var sbrk = instance.exports.sbrk;
18555
+ var ip = sbrk(indices.length * 4);
18556
+ var rp = sbrk(vertices * 4);
18557
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18558
+ var indices8 = bytes(indices);
18559
+ heap.set(indices8, ip);
18560
+ var unique = fun(rp, ip, indices.length, vertices);
18561
+ // heap may have grown
18562
+ heap = new Uint8Array(instance.exports.memory.buffer);
18563
+ var remap = new Uint32Array(vertices);
18564
+ new Uint8Array(remap.buffer).set(heap.subarray(rp, rp + vertices * 4));
18565
+ indices8.set(heap.subarray(ip, ip + indices.length * 4));
18566
+ sbrk(ip - sbrk(0));
18567
+
18568
+ for (var i = 0; i < indices.length; ++i) indices[i] = remap[indices[i]];
18569
+
18570
+ return [remap, unique];
18571
+ }
18572
+
18573
+ function maxindex(source) {
18574
+ var result = 0;
18575
+ for (var i = 0; i < source.length; ++i) {
18576
+ var index = source[i];
18577
+ result = result < index ? index : result;
18578
+ }
18579
+ return result;
18580
+ }
18581
+
18582
+ function simplify(fun, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, options) {
18583
+ var sbrk = instance.exports.sbrk;
18584
+ var te = sbrk(4);
18585
+ var ti = sbrk(index_count * 4);
18586
+ var sp = sbrk(vertex_count * vertex_positions_stride);
18587
+ var si = sbrk(index_count * 4);
18588
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18589
+ heap.set(bytes(vertex_positions), sp);
18590
+ heap.set(bytes(indices), si);
18591
+ var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, target_index_count, target_error, options, te);
18592
+ // heap may have grown
18593
+ heap = new Uint8Array(instance.exports.memory.buffer);
18594
+ var target = new Uint32Array(result);
18595
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
18596
+ var error = new Float32Array(1);
18597
+ bytes(error).set(heap.subarray(te, te + 4));
18598
+ sbrk(te - sbrk(0));
18599
+ return [target, error[0]];
18600
+ }
18601
+
18602
+ function simplifyAttr(
18603
+ fun,
18604
+ indices,
18605
+ index_count,
18606
+ vertex_positions,
18607
+ vertex_count,
18608
+ vertex_positions_stride,
18609
+ vertex_attributes,
18610
+ vertex_attributes_stride,
18611
+ attribute_weights,
18612
+ vertex_lock,
18613
+ target_index_count,
18614
+ target_error,
18615
+ options
18616
+ ) {
18617
+ var sbrk = instance.exports.sbrk;
18618
+ var te = sbrk(4);
18619
+ var ti = sbrk(index_count * 4);
18620
+ var sp = sbrk(vertex_count * vertex_positions_stride);
18621
+ var sa = sbrk(vertex_count * vertex_attributes_stride);
18622
+ var sw = sbrk(attribute_weights.length * 4);
18623
+ var si = sbrk(index_count * 4);
18624
+ var vl = vertex_lock ? sbrk(vertex_count) : 0;
18625
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18626
+ heap.set(bytes(vertex_positions), sp);
18627
+ heap.set(bytes(vertex_attributes), sa);
18628
+ heap.set(bytes(attribute_weights), sw);
18629
+ heap.set(bytes(indices), si);
18630
+ if (vertex_lock) {
18631
+ heap.set(bytes(vertex_lock), vl);
18632
+ }
18633
+ var result = fun(
18634
+ ti,
18635
+ si,
18636
+ index_count,
18637
+ sp,
18638
+ vertex_count,
18639
+ vertex_positions_stride,
18640
+ sa,
18641
+ vertex_attributes_stride,
18642
+ sw,
18643
+ attribute_weights.length,
18644
+ vl,
18645
+ target_index_count,
18646
+ target_error,
18647
+ options,
18648
+ te
18649
+ );
18650
+ // heap may have grown
18651
+ heap = new Uint8Array(instance.exports.memory.buffer);
18652
+ var target = new Uint32Array(result);
18653
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
18654
+ var error = new Float32Array(1);
18655
+ bytes(error).set(heap.subarray(te, te + 4));
18656
+ sbrk(te - sbrk(0));
18657
+ return [target, error[0]];
18658
+ }
18659
+
18660
+ function simplifyUpdate(
18661
+ fun,
18662
+ indices,
18663
+ index_count,
18664
+ vertex_positions,
18665
+ vertex_count,
18666
+ vertex_positions_stride,
18667
+ vertex_attributes,
18668
+ vertex_attributes_stride,
18669
+ attribute_weights,
18670
+ vertex_lock,
18671
+ target_index_count,
18672
+ target_error,
18673
+ options
18674
+ ) {
18675
+ var sbrk = instance.exports.sbrk;
18676
+ var te = sbrk(4);
18677
+ var sp = sbrk(vertex_count * vertex_positions_stride);
18678
+ var sa = sbrk(vertex_count * vertex_attributes_stride);
18679
+ var sw = sbrk(attribute_weights.length * 4);
18680
+ var si = sbrk(index_count * 4);
18681
+ var vl = vertex_lock ? sbrk(vertex_count) : 0;
18682
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18683
+ heap.set(bytes(vertex_positions), sp);
18684
+ heap.set(bytes(vertex_attributes), sa);
18685
+ heap.set(bytes(attribute_weights), sw);
18686
+ heap.set(bytes(indices), si);
18687
+ if (vertex_lock) {
18688
+ heap.set(bytes(vertex_lock), vl);
18689
+ }
18690
+ var result = fun(
18691
+ si,
18692
+ index_count,
18693
+ sp,
18694
+ vertex_count,
18695
+ vertex_positions_stride,
18696
+ sa,
18697
+ vertex_attributes_stride,
18698
+ sw,
18699
+ attribute_weights.length,
18700
+ vl,
18701
+ target_index_count,
18702
+ target_error,
18703
+ options,
18704
+ te
18705
+ );
18706
+ // heap may have grown
18707
+ heap = new Uint8Array(instance.exports.memory.buffer);
18708
+ bytes(indices).set(heap.subarray(si, si + result * 4));
18709
+ bytes(vertex_positions).set(heap.subarray(sp, sp + vertex_count * vertex_positions_stride));
18710
+ bytes(vertex_attributes).set(heap.subarray(sa, sa + vertex_count * vertex_attributes_stride));
18711
+ var error = new Float32Array(1);
18712
+ bytes(error).set(heap.subarray(te, te + 4));
18713
+ sbrk(te - sbrk(0));
18714
+ return [result, error[0]];
18715
+ }
18716
+
18717
+ function simplifyScale(fun, vertex_positions, vertex_count, vertex_positions_stride) {
18718
+ var sbrk = instance.exports.sbrk;
18719
+ var sp = sbrk(vertex_count * vertex_positions_stride);
18720
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18721
+ heap.set(bytes(vertex_positions), sp);
18722
+ var result = fun(sp, vertex_count, vertex_positions_stride);
18723
+ sbrk(sp - sbrk(0));
18724
+ return result;
18725
+ }
18726
+
18727
+ function simplifyPoints(
18728
+ fun,
18729
+ vertex_positions,
18730
+ vertex_count,
18731
+ vertex_positions_stride,
18732
+ vertex_colors,
18733
+ vertex_colors_stride,
18734
+ color_weight,
18735
+ target_vertex_count
18736
+ ) {
18737
+ var sbrk = instance.exports.sbrk;
18738
+ var ti = sbrk(target_vertex_count * 4);
18739
+ var sp = sbrk(vertex_count * vertex_positions_stride);
18740
+ var sc = sbrk(vertex_count * vertex_colors_stride);
18741
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18742
+ heap.set(bytes(vertex_positions), sp);
18743
+ if (vertex_colors) {
18744
+ heap.set(bytes(vertex_colors), sc);
18745
+ }
18746
+ var result = fun(ti, sp, vertex_count, vertex_positions_stride, sc, vertex_colors_stride, color_weight, target_vertex_count);
18747
+ // heap may have grown
18748
+ heap = new Uint8Array(instance.exports.memory.buffer);
18749
+ var target = new Uint32Array(result);
18750
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
18751
+ sbrk(ti - sbrk(0));
18752
+ return target;
18753
+ }
18754
+
18755
+ function simplifySloppy(
18756
+ fun,
18757
+ indices,
18758
+ index_count,
18759
+ vertex_positions,
18760
+ vertex_count,
18761
+ vertex_positions_stride,
18762
+ vertex_lock,
18763
+ target_index_count,
18764
+ target_error
18765
+ ) {
18766
+ var sbrk = instance.exports.sbrk;
18767
+ var te = sbrk(4);
18768
+ var ti = sbrk(index_count * 4);
18769
+ var sp = sbrk(vertex_count * vertex_positions_stride);
18770
+ var si = sbrk(index_count * 4);
18771
+ var vl = vertex_lock ? sbrk(vertex_count) : 0;
18772
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18773
+ heap.set(bytes(vertex_positions), sp);
18774
+ heap.set(bytes(indices), si);
18775
+ if (vertex_lock) {
18776
+ heap.set(bytes(vertex_lock), vl);
18777
+ }
18778
+ var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, vl, target_index_count, target_error, te);
18779
+ // heap may have grown
18780
+ heap = new Uint8Array(instance.exports.memory.buffer);
18781
+ var target = new Uint32Array(result);
18782
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
18783
+ var error = new Float32Array(1);
18784
+ bytes(error).set(heap.subarray(te, te + 4));
18785
+ sbrk(te - sbrk(0));
18786
+ return [target, error[0]];
18787
+ }
18788
+
18789
+ function simplifyPrune(fun, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_error) {
18790
+ var sbrk = instance.exports.sbrk;
18791
+ var ti = sbrk(index_count * 4);
18792
+ var sp = sbrk(vertex_count * vertex_positions_stride);
18793
+ var si = sbrk(index_count * 4);
18794
+ var heap = new Uint8Array(instance.exports.memory.buffer);
18795
+ heap.set(bytes(vertex_positions), sp);
18796
+ heap.set(bytes(indices), si);
18797
+ var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, target_error);
18798
+ // heap may have grown
18799
+ heap = new Uint8Array(instance.exports.memory.buffer);
18800
+ var target = new Uint32Array(result);
18801
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
18802
+ sbrk(ti - sbrk(0));
18803
+ return target;
18804
+ }
18805
+
18806
+ var simplifyOptions = {
18807
+ LockBorder: 1,
18808
+ Sparse: 2,
18809
+ ErrorAbsolute: 4,
18810
+ Prune: 8,
18811
+ Regularize: 16,
18812
+ Permissive: 32,
18813
+ _InternalDebug: 1 << 30, // internal, don't use!
18814
+ };
18815
+
18816
+ return {
18817
+ ready: ready,
18818
+ supported: true,
18819
+
18820
+ compactMesh: function (indices) {
18821
+ assert(
18822
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
18823
+ );
18824
+ assert(indices.length % 3 == 0);
18825
+
18826
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
18827
+ return reorder(instance.exports.meshopt_optimizeVertexFetchRemap, indices32, maxindex(indices) + 1);
18828
+ },
18829
+
18830
+ generatePositionRemap: function (vertex_positions, vertex_positions_stride) {
18831
+ assert(vertex_positions instanceof Float32Array);
18832
+ assert(vertex_positions.length % vertex_positions_stride == 0);
18833
+ assert(vertex_positions_stride >= 3);
18834
+
18835
+ return genremap(
18836
+ instance.exports.meshopt_generatePositionRemap,
18837
+ vertex_positions,
18838
+ vertex_positions.length / vertex_positions_stride,
18839
+ vertex_positions_stride
18840
+ );
18841
+ },
18842
+
18843
+ simplify: function (indices, vertex_positions, vertex_positions_stride, target_index_count, target_error, flags) {
18844
+ assert(
18845
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
18846
+ );
18847
+ assert(indices.length % 3 == 0);
18848
+ assert(vertex_positions instanceof Float32Array);
18849
+ assert(vertex_positions.length % vertex_positions_stride == 0);
18850
+ assert(vertex_positions_stride >= 3);
18851
+ assert(target_index_count >= 0 && target_index_count <= indices.length);
18852
+ assert(target_index_count % 3 == 0);
18853
+ assert(target_error >= 0);
18854
+
18855
+ var options = 0;
18856
+ for (var i = 0; i < (flags ? flags.length : 0); ++i) {
18857
+ assert(flags[i] in simplifyOptions);
18858
+ options |= simplifyOptions[flags[i]];
18859
+ }
18860
+
18861
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
18862
+ var result = simplify(
18863
+ instance.exports.meshopt_simplify,
18864
+ indices32,
18865
+ indices.length,
18866
+ vertex_positions,
18867
+ vertex_positions.length / vertex_positions_stride,
18868
+ vertex_positions_stride * 4,
18869
+ target_index_count,
18870
+ target_error,
18871
+ options
18872
+ );
18873
+ result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
18874
+
18875
+ return result;
18876
+ },
18877
+
18878
+ simplifyWithAttributes: function (
18879
+ indices,
18880
+ vertex_positions,
18881
+ vertex_positions_stride,
18882
+ vertex_attributes,
18883
+ vertex_attributes_stride,
18884
+ attribute_weights,
18885
+ vertex_lock,
18886
+ target_index_count,
18887
+ target_error,
18888
+ flags
18889
+ ) {
18890
+ assert(
18891
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
18892
+ );
18893
+ assert(indices.length % 3 == 0);
18894
+ assert(vertex_positions instanceof Float32Array);
18895
+ assert(vertex_positions.length % vertex_positions_stride == 0);
18896
+ assert(vertex_positions_stride >= 3);
18897
+ assert(vertex_attributes instanceof Float32Array);
18898
+ assert(vertex_attributes.length == vertex_attributes_stride * (vertex_positions.length / vertex_positions_stride));
18899
+ assert(vertex_attributes_stride >= 0);
18900
+ assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
18901
+ assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
18902
+ assert(target_index_count >= 0 && target_index_count <= indices.length);
18903
+ assert(target_index_count % 3 == 0);
18904
+ assert(target_error >= 0);
18905
+ assert(Array.isArray(attribute_weights));
18906
+ assert(vertex_attributes_stride >= attribute_weights.length);
18907
+ assert(attribute_weights.length <= 32);
18908
+ for (var i = 0; i < attribute_weights.length; ++i) {
18909
+ assert(attribute_weights[i] >= 0);
18910
+ }
18911
+
18912
+ var options = 0;
18913
+ for (var i = 0; i < (flags ? flags.length : 0); ++i) {
18914
+ assert(flags[i] in simplifyOptions);
18915
+ options |= simplifyOptions[flags[i]];
18916
+ }
18917
+
18918
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
18919
+ var result = simplifyAttr(
18920
+ instance.exports.meshopt_simplifyWithAttributes,
18921
+ indices32,
18922
+ indices.length,
18923
+ vertex_positions,
18924
+ vertex_positions.length / vertex_positions_stride,
18925
+ vertex_positions_stride * 4,
18926
+ vertex_attributes,
18927
+ vertex_attributes_stride * 4,
18928
+ new Float32Array(attribute_weights),
18929
+ vertex_lock,
18930
+ target_index_count,
18931
+ target_error,
18932
+ options
18933
+ );
18934
+ result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
18935
+
18936
+ return result;
18937
+ },
18938
+
18939
+ simplifyWithUpdate: function (
18940
+ indices,
18941
+ vertex_positions,
18942
+ vertex_positions_stride,
18943
+ vertex_attributes,
18944
+ vertex_attributes_stride,
18945
+ attribute_weights,
18946
+ vertex_lock,
18947
+ target_index_count,
18948
+ target_error,
18949
+ flags
18950
+ ) {
18951
+ assert(
18952
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
18953
+ );
18954
+ assert(indices.length % 3 == 0);
18955
+ assert(vertex_positions instanceof Float32Array);
18956
+ assert(vertex_positions.length % vertex_positions_stride == 0);
18957
+ assert(vertex_positions_stride >= 3);
18958
+ assert(vertex_attributes instanceof Float32Array);
18959
+ assert(vertex_attributes.length == vertex_attributes_stride * (vertex_positions.length / vertex_positions_stride));
18960
+ assert(vertex_attributes_stride >= 0);
18961
+ assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
18962
+ assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
18963
+ assert(target_index_count >= 0 && target_index_count <= indices.length);
18964
+ assert(target_index_count % 3 == 0);
18965
+ assert(target_error >= 0);
18966
+ assert(Array.isArray(attribute_weights));
18967
+ assert(vertex_attributes_stride >= attribute_weights.length);
18968
+ assert(attribute_weights.length <= 32);
18969
+ for (var i = 0; i < attribute_weights.length; ++i) {
18970
+ assert(attribute_weights[i] >= 0);
18971
+ }
18972
+
18973
+ var options = 0;
18974
+ for (var i = 0; i < (flags ? flags.length : 0); ++i) {
18975
+ assert(flags[i] in simplifyOptions);
18976
+ options |= simplifyOptions[flags[i]];
18977
+ }
18978
+
18979
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
18980
+ var result = simplifyUpdate(
18981
+ instance.exports.meshopt_simplifyWithUpdate,
18982
+ indices32,
18983
+ indices.length,
18984
+ vertex_positions,
18985
+ vertex_positions.length / vertex_positions_stride,
18986
+ vertex_positions_stride * 4,
18987
+ vertex_attributes,
18988
+ vertex_attributes_stride * 4,
18989
+ new Float32Array(attribute_weights),
18990
+ vertex_lock,
18991
+ target_index_count,
18992
+ target_error,
18993
+ options
18994
+ );
18995
+ if (indices !== indices32) {
18996
+ // copy back indices if they were converted to Uint32Array
18997
+ for (var i = 0; i < result[0]; ++i) {
18998
+ indices[i] = indices32[i];
18999
+ }
19000
+ }
19001
+ return result;
19002
+ },
19003
+
19004
+ getScale: function (vertex_positions, vertex_positions_stride) {
19005
+ assert(vertex_positions instanceof Float32Array);
19006
+ assert(vertex_positions.length % vertex_positions_stride == 0);
19007
+ assert(vertex_positions_stride >= 3);
19008
+ return simplifyScale(
19009
+ instance.exports.meshopt_simplifyScale,
19010
+ vertex_positions,
19011
+ vertex_positions.length / vertex_positions_stride,
19012
+ vertex_positions_stride * 4
19013
+ );
19014
+ },
19015
+
19016
+ simplifyPoints: function (vertex_positions, vertex_positions_stride, target_vertex_count, vertex_colors, vertex_colors_stride, color_weight) {
19017
+ assert(vertex_positions instanceof Float32Array);
19018
+ assert(vertex_positions.length % vertex_positions_stride == 0);
19019
+ assert(vertex_positions_stride >= 3);
19020
+ assert(target_vertex_count >= 0 && target_vertex_count <= vertex_positions.length / vertex_positions_stride);
19021
+ if (vertex_colors) {
19022
+ assert(vertex_colors instanceof Float32Array);
19023
+ assert(vertex_colors.length % vertex_colors_stride == 0);
19024
+ assert(vertex_colors_stride >= 3);
19025
+ assert(vertex_positions.length / vertex_positions_stride == vertex_colors.length / vertex_colors_stride);
19026
+ return simplifyPoints(
19027
+ instance.exports.meshopt_simplifyPoints,
19028
+ vertex_positions,
19029
+ vertex_positions.length / vertex_positions_stride,
19030
+ vertex_positions_stride * 4,
19031
+ vertex_colors,
19032
+ vertex_colors_stride * 4,
19033
+ color_weight,
19034
+ target_vertex_count
19035
+ );
19036
+ } else {
19037
+ return simplifyPoints(
19038
+ instance.exports.meshopt_simplifyPoints,
19039
+ vertex_positions,
19040
+ vertex_positions.length / vertex_positions_stride,
19041
+ vertex_positions_stride * 4,
19042
+ undefined,
19043
+ 0,
19044
+ 0,
19045
+ target_vertex_count
19046
+ );
19047
+ }
19048
+ },
19049
+
19050
+ simplifySloppy: function (indices, vertex_positions, vertex_positions_stride, vertex_lock, target_index_count, target_error) {
19051
+ assert(
19052
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
19053
+ );
19054
+ assert(indices.length % 3 == 0);
19055
+ assert(vertex_positions instanceof Float32Array);
19056
+ assert(vertex_positions.length % vertex_positions_stride == 0);
19057
+ assert(vertex_positions_stride >= 3);
19058
+ assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
19059
+ assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
19060
+ assert(target_index_count >= 0 && target_index_count <= indices.length);
19061
+ assert(target_index_count % 3 == 0);
19062
+ assert(target_error >= 0);
19063
+
19064
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
19065
+ var result = simplifySloppy(
19066
+ instance.exports.meshopt_simplifySloppy,
19067
+ indices32,
19068
+ indices.length,
19069
+ vertex_positions,
19070
+ vertex_positions.length / vertex_positions_stride,
19071
+ vertex_positions_stride * 4,
19072
+ vertex_lock,
19073
+ target_index_count,
19074
+ target_error
19075
+ );
19076
+ result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
19077
+
19078
+ return result;
19079
+ },
19080
+
19081
+ simplifyPrune: function (indices, vertex_positions, vertex_positions_stride, target_error) {
19082
+ assert(
19083
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
19084
+ );
19085
+ assert(indices.length % 3 == 0);
19086
+ assert(vertex_positions instanceof Float32Array);
19087
+ assert(vertex_positions.length % vertex_positions_stride == 0);
19088
+ assert(vertex_positions_stride >= 3);
19089
+ assert(target_error >= 0);
19090
+
19091
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
19092
+ var result = simplifyPrune(
19093
+ instance.exports.meshopt_simplifyPrune,
19094
+ indices32,
19095
+ indices.length,
19096
+ vertex_positions,
19097
+ vertex_positions.length / vertex_positions_stride,
19098
+ vertex_positions_stride * 4,
19099
+ target_error
19100
+ );
19101
+ result = indices instanceof Uint32Array ? result : new indices.constructor(result);
19102
+
19103
+ return result;
19104
+ },
19105
+ };
19106
+ })();
19107
+
19108
+ /**
19109
+ * Build a minimal GLB (glTF 2.0 binary) file containing a single triangle mesh.
19110
+ *
19111
+ * The output contains only positions and triangle indices — no normals,
19112
+ * UVs, or materials — suitable for collision meshes.
19113
+ *
19114
+ * @param positions - Vertex positions (3 floats per vertex)
19115
+ * @param indices - Triangle indices (3 per triangle, unsigned 32-bit)
19116
+ * @returns GLB file as a Uint8Array
19117
+ */
19118
+ function buildCollisionGlb(positions, indices) {
19119
+ const vertexCount = positions.length / 3;
19120
+ const indexCount = indices.length;
19121
+ let minX = Infinity, minY = Infinity, minZ = Infinity;
19122
+ let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
19123
+ for (let i = 0; i < positions.length; i += 3) {
19124
+ const x = positions[i], y = positions[i + 1], z = positions[i + 2];
19125
+ if (x < minX)
19126
+ minX = x;
19127
+ if (y < minY)
19128
+ minY = y;
19129
+ if (z < minZ)
19130
+ minZ = z;
19131
+ if (x > maxX)
19132
+ maxX = x;
19133
+ if (y > maxY)
19134
+ maxY = y;
19135
+ if (z > maxZ)
19136
+ maxZ = z;
19137
+ }
19138
+ const positionsByteLength = positions.byteLength;
19139
+ const indicesByteLength = indices.byteLength;
19140
+ const totalBinSize = positionsByteLength + indicesByteLength;
19141
+ const gltf = {
19142
+ asset: { version: '2.0', generator: 'splat-transform' },
19143
+ scene: 0,
19144
+ scenes: [{ nodes: [0] }],
19145
+ nodes: [{ mesh: 0 }],
19146
+ meshes: [{
19147
+ primitives: [{
19148
+ attributes: { POSITION: 0 },
19149
+ indices: 1
19150
+ }]
19151
+ }],
19152
+ accessors: [
19153
+ {
19154
+ bufferView: 0,
19155
+ componentType: 5126, // FLOAT
19156
+ count: vertexCount,
19157
+ type: 'VEC3',
19158
+ min: [minX, minY, minZ],
19159
+ max: [maxX, maxY, maxZ]
19160
+ },
19161
+ {
19162
+ bufferView: 1,
19163
+ componentType: 5125, // UNSIGNED_INT
19164
+ count: indexCount,
19165
+ type: 'SCALAR'
19166
+ }
19167
+ ],
19168
+ bufferViews: [
19169
+ {
19170
+ buffer: 0,
19171
+ byteOffset: 0,
19172
+ byteLength: positionsByteLength,
19173
+ target: 34962 // ARRAY_BUFFER
19174
+ },
19175
+ {
19176
+ buffer: 0,
19177
+ byteOffset: positionsByteLength,
19178
+ byteLength: indicesByteLength,
19179
+ target: 34963 // ELEMENT_ARRAY_BUFFER
19180
+ }
19181
+ ],
19182
+ buffers: [{ byteLength: totalBinSize }]
19183
+ };
19184
+ const jsonString = JSON.stringify(gltf);
19185
+ const jsonEncoder = new TextEncoder();
19186
+ const jsonBytes = jsonEncoder.encode(jsonString);
19187
+ // JSON chunk must be padded to 4-byte alignment with spaces (0x20)
19188
+ const jsonPadding = (4 - (jsonBytes.length % 4)) % 4;
19189
+ const jsonChunkLength = jsonBytes.length + jsonPadding;
19190
+ // BIN chunk must be padded to 4-byte alignment with zeros
19191
+ const binPadding = (4 - (totalBinSize % 4)) % 4;
19192
+ const binChunkLength = totalBinSize + binPadding;
19193
+ // GLB layout: header (12) + JSON chunk header (8) + JSON data + BIN chunk header (8) + BIN data
19194
+ const totalLength = 12 + 8 + jsonChunkLength + 8 + binChunkLength;
19195
+ const buffer = new ArrayBuffer(totalLength);
19196
+ const view = new DataView(buffer);
19197
+ const byteArray = new Uint8Array(buffer);
19198
+ let offset = 0;
19199
+ // GLB header
19200
+ view.setUint32(offset, 0x46546C67, true);
19201
+ offset += 4; // magic: "glTF"
19202
+ view.setUint32(offset, 2, true);
19203
+ offset += 4; // version: 2
19204
+ view.setUint32(offset, totalLength, true);
19205
+ offset += 4; // total length
19206
+ // JSON chunk header
19207
+ view.setUint32(offset, jsonChunkLength, true);
19208
+ offset += 4;
19209
+ view.setUint32(offset, 0x4E4F534A, true);
19210
+ offset += 4; // type: "JSON"
19211
+ // JSON chunk data
19212
+ byteArray.set(jsonBytes, offset);
19213
+ offset += jsonBytes.length;
19214
+ for (let i = 0; i < jsonPadding; i++) {
19215
+ byteArray[offset++] = 0x20;
19216
+ }
19217
+ // BIN chunk header
19218
+ view.setUint32(offset, binChunkLength, true);
19219
+ offset += 4;
19220
+ view.setUint32(offset, 0x004E4942, true);
19221
+ offset += 4; // type: "BIN\0"
19222
+ // BIN chunk data: positions then indices
19223
+ byteArray.set(new Uint8Array(positions.buffer, positions.byteOffset, positionsByteLength), offset);
19224
+ offset += positionsByteLength;
19225
+ byteArray.set(new Uint8Array(indices.buffer, indices.byteOffset, indicesByteLength), offset);
19226
+ return byteArray;
19227
+ }
19228
+
18380
19229
  /**
18381
19230
  * Compute axis-aligned bounding box half-extents for all Gaussians in a DataTable.
18382
19231
  *
@@ -19242,6 +20091,525 @@ class GpuVoxelization {
19242
20091
  }
19243
20092
  }
19244
20093
 
20094
+ // ============================================================================
20095
+ // Voxel bit helpers
20096
+ // ============================================================================
20097
+ // Bit layout within a 4x4x4 block: bitIdx = lx + ly*4 + lz*16
20098
+ // lo = bits 0-31 (lz 0-1), hi = bits 32-63 (lz 2-3)
20099
+ /**
20100
+ * Test whether a voxel is occupied within a block's bitmask.
20101
+ *
20102
+ * @param lo - Lower 32 bits of the block mask
20103
+ * @param hi - Upper 32 bits of the block mask
20104
+ * @param lx - Local x coordinate (0-3)
20105
+ * @param ly - Local y coordinate (0-3)
20106
+ * @param lz - Local z coordinate (0-3)
20107
+ * @returns True if the voxel is occupied
20108
+ */
20109
+ function isVoxelSet(lo, hi, lx, ly, lz) {
20110
+ const bitIdx = lx + ly * 4 + lz * 16;
20111
+ if (bitIdx < 32) {
20112
+ return (lo & (1 << bitIdx)) !== 0;
20113
+ }
20114
+ return (hi & (1 << (bitIdx - 32))) !== 0;
20115
+ }
20116
+ // ============================================================================
20117
+ // Occupancy grid from BlockAccumulator
20118
+ // ============================================================================
20119
+ /**
20120
+ * Build a fast-lookup occupancy structure from a BlockAccumulator.
20121
+ * Returns a function that queries whether a voxel at global coordinates
20122
+ * (vx, vy, vz) is occupied.
20123
+ *
20124
+ * @param accumulator - Block data
20125
+ * @returns Lookup function (vx, vy, vz) => boolean
20126
+ */
20127
+ function buildOccupancyLookup(accumulator) {
20128
+ // Map from "bx,by,bz" encoded as single number to {lo,hi} or solid flag
20129
+ // Block key = bx + by * stride + bz * stride^2 where stride is large enough
20130
+ const mixed = accumulator.getMixedBlocks();
20131
+ const solid = accumulator.getSolidBlocks();
20132
+ // Use a Map<number, number> where value encodes index into mask arrays.
20133
+ // For solid blocks, store -1 as sentinel.
20134
+ const blockMap = new Map();
20135
+ for (let i = 0; i < mixed.morton.length; i++) {
20136
+ blockMap.set(mixed.morton[i], i);
20137
+ }
20138
+ for (let i = 0; i < solid.length; i++) {
20139
+ blockMap.set(solid[i], -1);
20140
+ }
20141
+ const masks = mixed.masks;
20142
+ return (vx, vy, vz) => {
20143
+ if (vx < 0 || vy < 0 || vz < 0)
20144
+ return false;
20145
+ const bx = vx >> 2;
20146
+ const by = vy >> 2;
20147
+ const bz = vz >> 2;
20148
+ const entry = blockMap.get(xyzToMorton(bx, by, bz));
20149
+ if (entry === undefined)
20150
+ return false;
20151
+ if (entry === -1)
20152
+ return true; // solid block
20153
+ const lo = masks[entry * 2];
20154
+ const hi = masks[entry * 2 + 1];
20155
+ return isVoxelSet(lo, hi, vx & 3, vy & 3, vz & 3);
20156
+ };
20157
+ }
20158
+ // ============================================================================
20159
+ // Marching Cubes
20160
+ // ============================================================================
20161
+ /**
20162
+ * Extract a triangle mesh from a BlockAccumulator using marching cubes.
20163
+ *
20164
+ * Each voxel is treated as a cell in the marching cubes grid. Corner values
20165
+ * are binary (0 = empty, 1 = occupied) with a 0.5 threshold. Vertices are
20166
+ * placed at edge midpoints, producing a mesh that follows voxel boundaries.
20167
+ *
20168
+ * @param accumulator - Voxel block data after filtering
20169
+ * @param gridBounds - Grid bounds aligned to block boundaries
20170
+ * @param voxelResolution - Size of each voxel in world units
20171
+ * @returns Mesh with positions and indices
20172
+ */
20173
+ function marchingCubes(accumulator, gridBounds, voxelResolution) {
20174
+ const isOccupied = buildOccupancyLookup(accumulator);
20175
+ // Collect all voxel coordinates that need processing.
20176
+ // We need to check every cell where at least one corner differs from
20177
+ // the others, which means we need to check occupied voxels and their
20178
+ // immediate neighbors.
20179
+ const mixed = accumulator.getMixedBlocks();
20180
+ const solid = accumulator.getSolidBlocks();
20181
+ // Collect set of all block coordinates that exist
20182
+ const blockSet = new Set();
20183
+ for (let i = 0; i < mixed.morton.length; i++) {
20184
+ blockSet.add(mixed.morton[i]);
20185
+ }
20186
+ for (let i = 0; i < solid.length; i++) {
20187
+ blockSet.add(solid[i]);
20188
+ }
20189
+ // For each block, we process a 4x4x4 region of marching cubes cells.
20190
+ // Each cell at (vx, vy, vz) has corners at (vx..vx+1, vy..vy+1, vz..vz+1).
20191
+ // We only generate triangles for cells that have mixed corners (not all same).
20192
+ // Vertex deduplication: edge ID -> vertex index
20193
+ // Edge ID encodes the voxel coordinate and edge direction
20194
+ const vertexMap = new Map();
20195
+ const positions = [];
20196
+ const indices = [];
20197
+ const originX = gridBounds.min.x;
20198
+ const originY = gridBounds.min.y;
20199
+ const originZ = gridBounds.min.z;
20200
+ // Compute strides from actual grid dimensions (+3 for the -1 boundary
20201
+ // extension, the far edge +1, and one extra for safety).
20202
+ const strideX = Math.round((gridBounds.max.x - gridBounds.min.x) / voxelResolution) + 3;
20203
+ const strideXY = strideX * (Math.round((gridBounds.max.y - gridBounds.min.y) / voxelResolution) + 3);
20204
+ // Get or create a vertex at the midpoint of an edge.
20205
+ // Edge is identified by the lower corner voxel coordinate and axis (0=x, 1=y, 2=z).
20206
+ const getVertex = (vx, vy, vz, axis) => {
20207
+ // Pack (vx, vy, vz, axis) into a single key. Offset by 1 so that
20208
+ // vx = -1 (from the boundary extension) maps to 0, keeping keys non-negative.
20209
+ const key = ((vx + 1) + (vy + 1) * strideX + (vz + 1) * strideXY) * 3 + axis;
20210
+ let idx = vertexMap.get(key);
20211
+ if (idx !== undefined)
20212
+ return idx;
20213
+ idx = positions.length / 3;
20214
+ let px = originX + vx * voxelResolution;
20215
+ let py = originY + vy * voxelResolution;
20216
+ let pz = originZ + vz * voxelResolution;
20217
+ // Place vertex at edge midpoint (binary field -> always at 0.5)
20218
+ if (axis === 0)
20219
+ px += voxelResolution * 0.5;
20220
+ else if (axis === 1)
20221
+ py += voxelResolution * 0.5;
20222
+ else
20223
+ pz += voxelResolution * 0.5;
20224
+ positions.push(px, py, pz);
20225
+ vertexMap.set(key, idx);
20226
+ return idx;
20227
+ };
20228
+ // Process all blocks and their boundary neighbors
20229
+ const allMortons = [];
20230
+ blockSet.forEach(m => allMortons.push(m));
20231
+ for (let bi = 0; bi < allMortons.length; bi++) {
20232
+ const morton = allMortons[bi];
20233
+ const [bx, by, bz] = mortonToXYZ(morton);
20234
+ // Iterate -1..3 to include the boundary layer in the negative
20235
+ // direction. Cells at lx/ly/lz = -1 straddle the block edge and
20236
+ // are needed to close the surface where no neighboring block exists.
20237
+ for (let lz = -1; lz < 4; lz++) {
20238
+ for (let ly = -1; ly < 4; ly++) {
20239
+ for (let lx = -1; lx < 4; lx++) {
20240
+ const vx = bx * 4 + lx;
20241
+ const vy = by * 4 + ly;
20242
+ const vz = bz * 4 + lz;
20243
+ // Determine which block owns this cell
20244
+ const ownerBx = vx >> 2;
20245
+ const ownerBy = vy >> 2;
20246
+ const ownerBz = vz >> 2;
20247
+ if (ownerBx !== bx || ownerBy !== by || ownerBz !== bz) {
20248
+ // Cell belongs to a different block — skip if that
20249
+ // block exists (it will process the cell itself).
20250
+ // Guard negative coords: xyzToMorton assumes non-negative inputs.
20251
+ if (ownerBx >= 0 && ownerBy >= 0 && ownerBz >= 0 &&
20252
+ blockSet.has(xyzToMorton(ownerBx, ownerBy, ownerBz)))
20253
+ continue;
20254
+ }
20255
+ // Get corner values for this cell (8 corners)
20256
+ // Corners: (vx,vy,vz), (vx+1,vy,vz), (vx+1,vy+1,vz), (vx,vy+1,vz),
20257
+ // (vx,vy,vz+1), (vx+1,vy,vz+1), (vx+1,vy+1,vz+1), (vx,vy+1,vz+1)
20258
+ const c0 = isOccupied(vx, vy, vz) ? 1 : 0;
20259
+ const c1 = isOccupied(vx + 1, vy, vz) ? 1 : 0;
20260
+ const c2 = isOccupied(vx + 1, vy + 1, vz) ? 1 : 0;
20261
+ const c3 = isOccupied(vx, vy + 1, vz) ? 1 : 0;
20262
+ const c4 = isOccupied(vx, vy, vz + 1) ? 1 : 0;
20263
+ const c5 = isOccupied(vx + 1, vy, vz + 1) ? 1 : 0;
20264
+ const c6 = isOccupied(vx + 1, vy + 1, vz + 1) ? 1 : 0;
20265
+ const c7 = isOccupied(vx, vy + 1, vz + 1) ? 1 : 0;
20266
+ const cubeIndex = c0 | (c1 << 1) | (c2 << 2) | (c3 << 3) |
20267
+ (c4 << 4) | (c5 << 5) | (c6 << 6) | (c7 << 7);
20268
+ if (cubeIndex === 0 || cubeIndex === 255)
20269
+ continue;
20270
+ const edges = EDGE_TABLE[cubeIndex]; // eslint-disable-line no-use-before-define
20271
+ if (edges === 0)
20272
+ continue;
20273
+ // Compute vertices on active edges
20274
+ // Edge -> vertex mapping using getVertex with (corner voxel coord, axis)
20275
+ const edgeVerts = new Array(12);
20276
+ if (edges & 1)
20277
+ edgeVerts[0] = getVertex(vx, vy, vz, 0); // edge 0: x-axis at (vx, vy, vz)
20278
+ if (edges & 2)
20279
+ edgeVerts[1] = getVertex(vx + 1, vy, vz, 1); // edge 1: y-axis at (vx+1, vy, vz)
20280
+ if (edges & 4)
20281
+ edgeVerts[2] = getVertex(vx, vy + 1, vz, 0); // edge 2: x-axis at (vx, vy+1, vz)
20282
+ if (edges & 8)
20283
+ edgeVerts[3] = getVertex(vx, vy, vz, 1); // edge 3: y-axis at (vx, vy, vz)
20284
+ if (edges & 16)
20285
+ edgeVerts[4] = getVertex(vx, vy, vz + 1, 0); // edge 4: x-axis at (vx, vy, vz+1)
20286
+ if (edges & 32)
20287
+ edgeVerts[5] = getVertex(vx + 1, vy, vz + 1, 1); // edge 5: y-axis at (vx+1, vy, vz+1)
20288
+ if (edges & 64)
20289
+ edgeVerts[6] = getVertex(vx, vy + 1, vz + 1, 0); // edge 6: x-axis at (vx, vy+1, vz+1)
20290
+ if (edges & 128)
20291
+ edgeVerts[7] = getVertex(vx, vy, vz + 1, 1); // edge 7: y-axis at (vx, vy, vz+1)
20292
+ if (edges & 256)
20293
+ edgeVerts[8] = getVertex(vx, vy, vz, 2); // edge 8: z-axis at (vx, vy, vz)
20294
+ if (edges & 512)
20295
+ edgeVerts[9] = getVertex(vx + 1, vy, vz, 2); // edge 9: z-axis at (vx+1, vy, vz)
20296
+ if (edges & 1024)
20297
+ edgeVerts[10] = getVertex(vx + 1, vy + 1, vz, 2); // edge 10: z-axis at (vx+1, vy+1, vz)
20298
+ if (edges & 2048)
20299
+ edgeVerts[11] = getVertex(vx, vy + 1, vz, 2); // edge 11: z-axis at (vx, vy+1, vz)
20300
+ // Emit triangles (reversed winding to face outward)
20301
+ const triRow = TRI_TABLE[cubeIndex]; // eslint-disable-line no-use-before-define
20302
+ for (let t = 0; t < triRow.length; t += 3) {
20303
+ indices.push(edgeVerts[triRow[t]], edgeVerts[triRow[t + 2]], edgeVerts[triRow[t + 1]]);
20304
+ }
20305
+ }
20306
+ }
20307
+ }
20308
+ }
20309
+ return {
20310
+ positions: new Float32Array(positions),
20311
+ indices: new Uint32Array(indices)
20312
+ };
20313
+ }
20314
+ // ============================================================================
20315
+ // Marching Cubes Lookup Tables
20316
+ // ============================================================================
20317
+ // Standard tables from Paul Bourke's polygonising a scalar field.
20318
+ // EDGE_TABLE: 256 entries, each a 12-bit mask of which edges are intersected.
20319
+ // TRI_TABLE: 256 entries, each an array of edge indices forming triangles.
20320
+ const EDGE_TABLE = [
20321
+ 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
20322
+ 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
20323
+ 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
20324
+ 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
20325
+ 0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
20326
+ 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
20327
+ 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
20328
+ 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
20329
+ 0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c,
20330
+ 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
20331
+ 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc,
20332
+ 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
20333
+ 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c,
20334
+ 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
20335
+ 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc,
20336
+ 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
20337
+ 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
20338
+ 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
20339
+ 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
20340
+ 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
20341
+ 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
20342
+ 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
20343
+ 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
20344
+ 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
20345
+ 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
20346
+ 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
20347
+ 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
20348
+ 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
20349
+ 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
20350
+ 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
20351
+ 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
20352
+ 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
20353
+ ];
20354
+ const TRI_TABLE = [
20355
+ [],
20356
+ [0, 8, 3],
20357
+ [0, 1, 9],
20358
+ [1, 8, 3, 9, 8, 1],
20359
+ [1, 2, 10],
20360
+ [0, 8, 3, 1, 2, 10],
20361
+ [9, 2, 10, 0, 2, 9],
20362
+ [2, 8, 3, 2, 10, 8, 10, 9, 8],
20363
+ [3, 11, 2],
20364
+ [0, 11, 2, 8, 11, 0],
20365
+ [1, 9, 0, 2, 3, 11],
20366
+ [1, 11, 2, 1, 9, 11, 9, 8, 11],
20367
+ [3, 10, 1, 11, 10, 3],
20368
+ [0, 10, 1, 0, 8, 10, 8, 11, 10],
20369
+ [3, 9, 0, 3, 11, 9, 11, 10, 9],
20370
+ [9, 8, 10, 10, 8, 11],
20371
+ [4, 7, 8],
20372
+ [4, 3, 0, 7, 3, 4],
20373
+ [0, 1, 9, 8, 4, 7],
20374
+ [4, 1, 9, 4, 7, 1, 7, 3, 1],
20375
+ [1, 2, 10, 8, 4, 7],
20376
+ [3, 4, 7, 3, 0, 4, 1, 2, 10],
20377
+ [9, 2, 10, 9, 0, 2, 8, 4, 7],
20378
+ [2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4],
20379
+ [8, 4, 7, 3, 11, 2],
20380
+ [11, 4, 7, 11, 2, 4, 2, 0, 4],
20381
+ [9, 0, 1, 8, 4, 7, 2, 3, 11],
20382
+ [4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1],
20383
+ [3, 10, 1, 3, 11, 10, 7, 8, 4],
20384
+ [1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4],
20385
+ [4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3],
20386
+ [4, 7, 11, 4, 11, 9, 9, 11, 10],
20387
+ [9, 5, 4],
20388
+ [9, 5, 4, 0, 8, 3],
20389
+ [0, 5, 4, 1, 5, 0],
20390
+ [8, 5, 4, 8, 3, 5, 3, 1, 5],
20391
+ [1, 2, 10, 9, 5, 4],
20392
+ [3, 0, 8, 1, 2, 10, 4, 9, 5],
20393
+ [5, 2, 10, 5, 4, 2, 4, 0, 2],
20394
+ [2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8],
20395
+ [9, 5, 4, 2, 3, 11],
20396
+ [0, 11, 2, 0, 8, 11, 4, 9, 5],
20397
+ [0, 5, 4, 0, 1, 5, 2, 3, 11],
20398
+ [2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5],
20399
+ [10, 3, 11, 10, 1, 3, 9, 5, 4],
20400
+ [4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10],
20401
+ [5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3],
20402
+ [5, 4, 8, 5, 8, 10, 10, 8, 11],
20403
+ [9, 7, 8, 5, 7, 9],
20404
+ [9, 3, 0, 9, 5, 3, 5, 7, 3],
20405
+ [0, 7, 8, 0, 1, 7, 1, 5, 7],
20406
+ [1, 5, 3, 3, 5, 7],
20407
+ [9, 7, 8, 9, 5, 7, 10, 1, 2],
20408
+ [10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3],
20409
+ [8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2],
20410
+ [2, 10, 5, 2, 5, 3, 3, 5, 7],
20411
+ [7, 9, 5, 7, 8, 9, 3, 11, 2],
20412
+ [9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11],
20413
+ [2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7],
20414
+ [11, 2, 1, 11, 1, 7, 7, 1, 5],
20415
+ [9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11],
20416
+ [5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0],
20417
+ [11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0],
20418
+ [11, 10, 5, 7, 11, 5],
20419
+ [10, 6, 5],
20420
+ [0, 8, 3, 5, 10, 6],
20421
+ [9, 0, 1, 5, 10, 6],
20422
+ [1, 8, 3, 1, 9, 8, 5, 10, 6],
20423
+ [1, 6, 5, 2, 6, 1],
20424
+ [1, 6, 5, 1, 2, 6, 3, 0, 8],
20425
+ [9, 6, 5, 9, 0, 6, 0, 2, 6],
20426
+ [5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8],
20427
+ [2, 3, 11, 10, 6, 5],
20428
+ [11, 0, 8, 11, 2, 0, 10, 6, 5],
20429
+ [0, 1, 9, 2, 3, 11, 5, 10, 6],
20430
+ [5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11],
20431
+ [6, 3, 11, 6, 5, 3, 5, 1, 3],
20432
+ [0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6],
20433
+ [3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9],
20434
+ [6, 5, 9, 6, 9, 11, 11, 9, 8],
20435
+ [5, 10, 6, 4, 7, 8],
20436
+ [4, 3, 0, 4, 7, 3, 6, 5, 10],
20437
+ [1, 9, 0, 5, 10, 6, 8, 4, 7],
20438
+ [10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4],
20439
+ [6, 1, 2, 6, 5, 1, 4, 7, 8],
20440
+ [1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7],
20441
+ [8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6],
20442
+ [7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9],
20443
+ [3, 11, 2, 7, 8, 4, 10, 6, 5],
20444
+ [5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11],
20445
+ [0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6],
20446
+ [9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6],
20447
+ [8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6],
20448
+ [5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11],
20449
+ [0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7],
20450
+ [6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9],
20451
+ [10, 4, 9, 6, 4, 10],
20452
+ [4, 10, 6, 4, 9, 10, 0, 8, 3],
20453
+ [10, 0, 1, 10, 6, 0, 6, 4, 0],
20454
+ [8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10],
20455
+ [1, 4, 9, 1, 2, 4, 2, 6, 4],
20456
+ [3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4],
20457
+ [0, 2, 4, 4, 2, 6],
20458
+ [8, 3, 2, 8, 2, 4, 4, 2, 6],
20459
+ [10, 4, 9, 10, 6, 4, 11, 2, 3],
20460
+ [0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6],
20461
+ [3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10],
20462
+ [6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1],
20463
+ [9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3],
20464
+ [8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1],
20465
+ [3, 11, 6, 3, 6, 0, 0, 6, 4],
20466
+ [6, 4, 8, 11, 6, 8],
20467
+ [7, 10, 6, 7, 8, 10, 8, 9, 10],
20468
+ [0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10],
20469
+ [10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0],
20470
+ [10, 6, 7, 10, 7, 1, 1, 7, 3],
20471
+ [1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7],
20472
+ [2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9],
20473
+ [7, 8, 0, 7, 0, 6, 6, 0, 2],
20474
+ [7, 3, 2, 6, 7, 2],
20475
+ [2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7],
20476
+ [2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7],
20477
+ [1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11],
20478
+ [11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1],
20479
+ [8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6],
20480
+ [0, 9, 1, 11, 6, 7],
20481
+ [7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0],
20482
+ [7, 11, 6],
20483
+ [7, 6, 11],
20484
+ [3, 0, 8, 11, 7, 6],
20485
+ [0, 1, 9, 11, 7, 6],
20486
+ [8, 1, 9, 8, 3, 1, 11, 7, 6],
20487
+ [10, 1, 2, 6, 11, 7],
20488
+ [1, 2, 10, 3, 0, 8, 6, 11, 7],
20489
+ [2, 9, 0, 2, 10, 9, 6, 11, 7],
20490
+ [6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8],
20491
+ [7, 2, 3, 6, 2, 7],
20492
+ [7, 0, 8, 7, 6, 0, 6, 2, 0],
20493
+ [2, 7, 6, 2, 3, 7, 0, 1, 9],
20494
+ [1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6],
20495
+ [10, 7, 6, 10, 1, 7, 1, 3, 7],
20496
+ [10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8],
20497
+ [0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7],
20498
+ [7, 6, 10, 7, 10, 8, 8, 10, 9],
20499
+ [6, 8, 4, 11, 8, 6],
20500
+ [3, 6, 11, 3, 0, 6, 0, 4, 6],
20501
+ [8, 6, 11, 8, 4, 6, 9, 0, 1],
20502
+ [9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6],
20503
+ [6, 8, 4, 6, 11, 8, 2, 10, 1],
20504
+ [1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6],
20505
+ [4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9],
20506
+ [10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3],
20507
+ [8, 2, 3, 8, 4, 2, 4, 6, 2],
20508
+ [0, 4, 2, 4, 6, 2],
20509
+ [1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8],
20510
+ [1, 9, 4, 1, 4, 2, 2, 4, 6],
20511
+ [8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1],
20512
+ [10, 1, 0, 10, 0, 6, 6, 0, 4],
20513
+ [4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3],
20514
+ [10, 9, 4, 6, 10, 4],
20515
+ [4, 9, 5, 7, 6, 11],
20516
+ [0, 8, 3, 4, 9, 5, 11, 7, 6],
20517
+ [5, 0, 1, 5, 4, 0, 7, 6, 11],
20518
+ [11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5],
20519
+ [9, 5, 4, 10, 1, 2, 7, 6, 11],
20520
+ [6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5],
20521
+ [7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2],
20522
+ [3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6],
20523
+ [7, 2, 3, 7, 6, 2, 5, 4, 9],
20524
+ [9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7],
20525
+ [3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0],
20526
+ [6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8],
20527
+ [9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7],
20528
+ [1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4],
20529
+ [4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10],
20530
+ [7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10],
20531
+ [6, 9, 5, 6, 11, 9, 11, 8, 9],
20532
+ [3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5],
20533
+ [0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11],
20534
+ [6, 11, 3, 6, 3, 5, 5, 3, 1],
20535
+ [1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6],
20536
+ [0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10],
20537
+ [11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5],
20538
+ [6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3],
20539
+ [5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2],
20540
+ [9, 5, 6, 9, 6, 0, 0, 6, 2],
20541
+ [1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8],
20542
+ [1, 5, 6, 2, 1, 6],
20543
+ [1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6],
20544
+ [10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0],
20545
+ [0, 3, 8, 5, 6, 10],
20546
+ [10, 5, 6],
20547
+ [11, 5, 10, 7, 5, 11],
20548
+ [11, 5, 10, 11, 7, 5, 8, 3, 0],
20549
+ [5, 11, 7, 5, 10, 11, 1, 9, 0],
20550
+ [10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1],
20551
+ [11, 1, 2, 11, 7, 1, 7, 5, 1],
20552
+ [0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11],
20553
+ [9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7],
20554
+ [7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2],
20555
+ [2, 5, 10, 2, 3, 5, 3, 7, 5],
20556
+ [8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5],
20557
+ [9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2],
20558
+ [9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2],
20559
+ [1, 3, 5, 3, 7, 5],
20560
+ [0, 8, 7, 0, 7, 1, 1, 7, 5],
20561
+ [9, 0, 3, 9, 3, 5, 5, 3, 7],
20562
+ [9, 8, 7, 5, 9, 7],
20563
+ [5, 8, 4, 5, 10, 8, 10, 11, 8],
20564
+ [5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0],
20565
+ [0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5],
20566
+ [10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4],
20567
+ [2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8],
20568
+ [0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11],
20569
+ [0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5],
20570
+ [9, 4, 5, 2, 11, 3],
20571
+ [2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4],
20572
+ [5, 10, 2, 5, 2, 4, 4, 2, 0],
20573
+ [3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9],
20574
+ [5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2],
20575
+ [8, 4, 5, 8, 5, 3, 3, 5, 1],
20576
+ [0, 4, 5, 1, 0, 5],
20577
+ [8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5],
20578
+ [9, 4, 5],
20579
+ [4, 11, 7, 4, 9, 11, 9, 10, 11],
20580
+ [0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11],
20581
+ [1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11],
20582
+ [3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4],
20583
+ [4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2],
20584
+ [9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3],
20585
+ [11, 7, 4, 11, 4, 2, 2, 4, 0],
20586
+ [11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4],
20587
+ [2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9],
20588
+ [9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7],
20589
+ [3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10],
20590
+ [1, 10, 2, 8, 7, 4],
20591
+ [4, 9, 1, 4, 1, 7, 7, 1, 3],
20592
+ [4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1],
20593
+ [4, 0, 3, 7, 4, 3],
20594
+ [4, 8, 7],
20595
+ [9, 10, 8, 10, 11, 8],
20596
+ [3, 0, 9, 3, 9, 11, 11, 9, 10],
20597
+ [0, 1, 10, 0, 10, 8, 8, 10, 11],
20598
+ [3, 1, 10, 11, 3, 10],
20599
+ [1, 2, 11, 1, 11, 9, 9, 11, 8],
20600
+ [3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9],
20601
+ [0, 2, 11, 8, 0, 11],
20602
+ [3, 2, 11],
20603
+ [2, 3, 8, 2, 8, 10, 10, 8, 9],
20604
+ [9, 10, 2, 0, 9, 2],
20605
+ [2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8],
20606
+ [1, 10, 2],
20607
+ [1, 3, 8, 9, 1, 8],
20608
+ [0, 9, 1],
20609
+ [0, 3, 8],
20610
+ []
20611
+ ];
20612
+
19245
20613
  // ============================================================================
19246
20614
  // Edge mask constants for 4x4x4 voxel blocks
19247
20615
  // ============================================================================
@@ -19511,9 +20879,10 @@ const writeOctreeFiles = async (fs, jsonFilename, octree) => {
19511
20879
  * Voxelizes Gaussian splat data and writes the result as a sparse voxel octree.
19512
20880
  *
19513
20881
  * This function performs GPU-accelerated voxelization of Gaussian splat data
19514
- * and outputs two files:
20882
+ * and outputs two or three files:
19515
20883
  * - `filename` (.voxel.json) - JSON metadata including bounds, resolution, and array sizes
19516
20884
  * - Corresponding .voxel.bin - Binary octree data (nodes + leafData as Uint32 arrays)
20885
+ * - Corresponding .collision.glb - Triangle mesh extracted via marching cubes (GLB format, optional)
19517
20886
  *
19518
20887
  * The binary file layout is:
19519
20888
  * - Bytes 0 to (nodeCount * 4 - 1): nodes array (Uint32, little-endian)
@@ -19532,16 +20901,17 @@ const writeOctreeFiles = async (fs, jsonFilename, octree) => {
19532
20901
  * dataTable: myDataTable,
19533
20902
  * voxelResolution: 0.05,
19534
20903
  * opacityCutoff: 0.5,
20904
+ * collisionMesh: true,
19535
20905
  * createDevice: async () => myGraphicsDevice
19536
20906
  * }, fs);
19537
20907
  * ```
19538
20908
  */
19539
20909
  const writeVoxel = async (options, fs) => {
19540
- const { filename, dataTable, voxelResolution = 0.05, opacityCutoff = 0.5, createDevice } = options;
20910
+ const { filename, dataTable, voxelResolution = 0.05, opacityCutoff = 0.5, createDevice, collisionMesh = false, meshSimplify = 0.25 } = options;
19541
20911
  if (!createDevice) {
19542
20912
  throw new Error('writeVoxel requires a createDevice function for GPU voxelization');
19543
20913
  }
19544
- logger.progress.begin(4);
20914
+ logger.progress.begin(collisionMesh ? 7 : 5);
19545
20915
  const extentsResult = computeGaussianExtents(dataTable);
19546
20916
  const bounds = extentsResult.sceneBounds;
19547
20917
  logger.progress.step('Building BVH');
@@ -19713,10 +21083,61 @@ const writeVoxel = async (options, fs) => {
19713
21083
  gpuVoxelization.destroy();
19714
21084
  logger.progress.step('Filtering');
19715
21085
  accumulator = filterAndFillBlocks(accumulator);
21086
+ let glbBytes = null;
21087
+ if (collisionMesh) {
21088
+ logger.progress.step('Extracting collision mesh');
21089
+ const rawMesh = marchingCubes(accumulator, gridBounds, voxelResolution);
21090
+ logger.log(`collision mesh (raw): ${rawMesh.positions.length / 3} vertices, ${rawMesh.indices.length / 3} triangles`);
21091
+ if (rawMesh.indices.length < 3) {
21092
+ logger.progress.step('Simplifying collision mesh');
21093
+ logger.log('collision mesh: no triangles generated, skipping GLB output');
21094
+ }
21095
+ else {
21096
+ logger.progress.step('Simplifying collision mesh');
21097
+ await MeshoptSimplifier.ready;
21098
+ const clampedSimplify = Number.isFinite(meshSimplify) ? Math.min(1, Math.max(0, meshSimplify)) : 0.25;
21099
+ const targetIndexCount = Math.max(3, Math.min(rawMesh.indices.length, Math.floor(rawMesh.indices.length * clampedSimplify / 3) * 3));
21100
+ const [simplifiedIndices] = MeshoptSimplifier.simplify(rawMesh.indices, rawMesh.positions, 3, targetIndexCount, voxelResolution, ['ErrorAbsolute']);
21101
+ const vertexRemap = new Map();
21102
+ let newVertexCount = 0;
21103
+ for (let i = 0; i < simplifiedIndices.length; i++) {
21104
+ if (!vertexRemap.has(simplifiedIndices[i])) {
21105
+ vertexRemap.set(simplifiedIndices[i], newVertexCount++);
21106
+ }
21107
+ }
21108
+ const compactPositions = new Float32Array(newVertexCount * 3);
21109
+ for (const [oldIdx, newIdx] of vertexRemap) {
21110
+ compactPositions[newIdx * 3] = rawMesh.positions[oldIdx * 3];
21111
+ compactPositions[newIdx * 3 + 1] = rawMesh.positions[oldIdx * 3 + 1];
21112
+ compactPositions[newIdx * 3 + 2] = rawMesh.positions[oldIdx * 3 + 2];
21113
+ }
21114
+ const compactIndices = new Uint32Array(simplifiedIndices.length);
21115
+ for (let i = 0; i < simplifiedIndices.length; i++) {
21116
+ compactIndices[i] = vertexRemap.get(simplifiedIndices[i]);
21117
+ }
21118
+ const reduction = (1 - simplifiedIndices.length / rawMesh.indices.length) * 100;
21119
+ logger.log(`collision mesh (simplified): ${newVertexCount} vertices, ${simplifiedIndices.length / 3} triangles (${reduction.toFixed(0)}% reduction)`);
21120
+ glbBytes = buildCollisionGlb(compactPositions, compactIndices);
21121
+ }
21122
+ }
21123
+ logger.progress.step('Building octree');
19716
21124
  const octree = buildSparseOctree(accumulator, gridBounds, bounds, // Original scene bounds
19717
21125
  voxelResolution);
21126
+ logger.log(`octree: depth=${octree.treeDepth}, interior=${octree.numInteriorNodes}, mixed=${octree.numMixedLeaves}`);
19718
21127
  logger.progress.step('Writing');
19719
21128
  await writeOctreeFiles(fs, filename, octree);
21129
+ if (glbBytes) {
21130
+ const glbFilename = filename.replace('.voxel.json', '.collision.glb');
21131
+ logger.log(`writing '${glbFilename}'...`);
21132
+ await writeFile$1(fs, glbFilename, glbBytes);
21133
+ }
21134
+ const totalBytes = (octree.nodes.length + octree.leafData.length) * 4;
21135
+ if (glbBytes) {
21136
+ logger.log(`total size: octree ${(totalBytes / 1024).toFixed(1)} KB, collision mesh ${(glbBytes.length / 1024).toFixed(1)} KB`);
21137
+ }
21138
+ else {
21139
+ logger.log(`total size: ${(totalBytes / 1024).toFixed(1)} KB`);
21140
+ }
19720
21141
  };
19721
21142
 
19722
21143
  /**
@@ -19849,6 +21270,8 @@ const writeFile = async (writeOptions, fs) => {
19849
21270
  dataTable,
19850
21271
  voxelResolution: options.voxelResolution,
19851
21272
  opacityCutoff: options.opacityCutoff,
21273
+ collisionMesh: options.collisionMesh,
21274
+ meshSimplify: options.meshSimplify,
19852
21275
  createDevice
19853
21276
  }, fs);
19854
21277
  break;
@@ -20374,7 +21797,9 @@ const parseArguments = async () => {
20374
21797
  'lod-chunk-extent': { type: 'string', short: 'X', default: '16' },
20375
21798
  unbundled: { type: 'boolean', short: 'U', default: false },
20376
21799
  'voxel-resolution': { type: 'string', short: 'R', default: '0.05' },
20377
- 'opacity-cutoff': { type: 'string', short: 'A', default: '0.5' },
21800
+ 'opacity-cutoff': { type: 'string', short: 'A', default: '0.1' },
21801
+ 'collision-mesh': { type: 'boolean', short: 'K', default: false },
21802
+ 'mesh-simplify': { type: 'string', short: 'T', default: '0.25' },
20378
21803
  // per-file options
20379
21804
  translate: { type: 'string', short: 't', multiple: true },
20380
21805
  rotate: { type: 'string', short: 'r', multiple: true },
@@ -20461,8 +21886,13 @@ const parseArguments = async () => {
20461
21886
  lodChunkCount: parseInteger(v['lod-chunk-count']),
20462
21887
  lodChunkExtent: parseInteger(v['lod-chunk-extent']),
20463
21888
  voxelResolution: parseNumber(v['voxel-resolution']),
20464
- opacityCutoff: parseNumber(v['opacity-cutoff'])
21889
+ opacityCutoff: parseNumber(v['opacity-cutoff']),
21890
+ collisionMesh: v['collision-mesh'],
21891
+ meshSimplify: parseNumber(v['mesh-simplify'])
20465
21892
  };
21893
+ if (!Number.isFinite(options.meshSimplify) || options.meshSimplify < 0 || options.meshSimplify > 1) {
21894
+ throw new Error(`Invalid mesh-simplify value: ${options.meshSimplify}. Must be a finite number between 0 and 1.`);
21895
+ }
20466
21896
  for (const t of tokens) {
20467
21897
  if (t.kind === 'positional') {
20468
21898
  files.push({
@@ -20669,7 +22099,9 @@ GLOBAL OPTIONS
20669
22099
  -C, --lod-chunk-count <n> Approximate number of Gaussians per LOD chunk in K. Default: 512
20670
22100
  -X, --lod-chunk-extent <n> Approximate size of an LOD chunk in world units (m). Default: 16
20671
22101
  -R, --voxel-resolution <n> Voxel size in world units for .voxel.json. Default: 0.05
20672
- -A, --opacity-cutoff <n> Opacity threshold for solid voxels. Default: 0.5
22102
+ -A, --opacity-cutoff <n> Opacity threshold for solid voxels. Default: 0.1
22103
+ -K, --collision-mesh Generate collision mesh (.collision.glb) with voxel output
22104
+ -T, --mesh-simplify <n> Ratio of triangles to keep for collision mesh (0-1). Default: 0.25
20673
22105
 
20674
22106
  EXAMPLES
20675
22107
  # Scale then translate
@@ -20687,9 +22119,12 @@ EXAMPLES
20687
22119
  # Generate LOD with custom chunk size and node split size
20688
22120
  splat-transform -O 0,1,2 -C 1024 -X 32 input.lcc output/lod-meta.json
20689
22121
 
20690
- # Generate voxel collision data
22122
+ # Generate voxel data
20691
22123
  splat-transform input.ply output.voxel.json
20692
22124
 
22125
+ # Generate voxel data with collision mesh
22126
+ splat-transform -K input.ply output.voxel.json
22127
+
20693
22128
  # Generate voxel data with custom resolution and opacity threshold
20694
22129
  splat-transform -R 0.1 -A 0.3 input.ply output.voxel.json
20695
22130
 
@@ -20720,15 +22155,17 @@ const main = async () => {
20720
22155
  if (node.stepName) {
20721
22156
  console.error(`[${node.step}/${node.totalSteps}] ${node.stepName}`);
20722
22157
  }
22158
+ else if (node.step === 0) {
22159
+ start = hrtime();
22160
+ }
20723
22161
  else {
20724
- if (node.step === 0) {
20725
- start = hrtime();
20726
- }
20727
- else if (node.step === node.totalSteps) {
20728
- process.stderr.write(`# done in ${hrtimeDelta(start, hrtime()).toFixed(3)}s 🎉\n`);
20729
- }
20730
- else {
20731
- process.stderr.write('#');
22162
+ const displaySteps = 10;
22163
+ const curr = Math.round(displaySteps * node.step / node.totalSteps);
22164
+ const prev = Math.round(displaySteps * (node.step - 1) / node.totalSteps);
22165
+ if (curr > prev)
22166
+ process.stderr.write('#'.repeat(curr - prev));
22167
+ if (node.step === node.totalSteps) {
22168
+ process.stderr.write(` done in ${hrtimeDelta(start, hrtime()).toFixed(3)}s 🎉\n`);
20732
22169
  }
20733
22170
  }
20734
22171
  }