@plasius/gpu-shared 0.1.10 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/README.md +59 -2
  3. package/assets/brigantine.gltf +549 -24
  4. package/assets/cutter.gltf +538 -0
  5. package/assets/harbor-dock.gltf +680 -0
  6. package/assets/lighthouse.gltf +604 -0
  7. package/dist/chunk-2FIFSBB4.js +74 -0
  8. package/dist/chunk-2FIFSBB4.js.map +1 -0
  9. package/dist/chunk-DABW627O.js +113 -0
  10. package/dist/chunk-DABW627O.js.map +1 -0
  11. package/dist/chunk-DQX4DXBR.js +369 -0
  12. package/dist/chunk-DQX4DXBR.js.map +1 -0
  13. package/dist/chunk-NCPJWLX3.js +17 -0
  14. package/dist/chunk-NCPJWLX3.js.map +1 -0
  15. package/dist/gltf-loader-WAM23F37.js +9 -0
  16. package/dist/index.cjs +1265 -281
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.js +19 -6
  19. package/dist/index.js.map +1 -1
  20. package/dist/showcase-inline-assets-B7U7VX5H.js +7 -0
  21. package/dist/{showcase-runtime-55OVDYWT.js → showcase-runtime-PN7N3FZY.js} +818 -239
  22. package/dist/showcase-runtime-PN7N3FZY.js.map +1 -0
  23. package/package.json +15 -1
  24. package/src/asset-url.js +62 -11
  25. package/src/feature-flags.js +1 -0
  26. package/src/gltf-loader.js +322 -32
  27. package/src/i18n.js +71 -0
  28. package/src/index.d.ts +115 -1
  29. package/src/index.js +9 -1
  30. package/src/showcase-inline-assets.js +3 -0
  31. package/src/showcase-runtime.js +924 -190
  32. package/src/translations/en-GB.js +55 -0
  33. package/dist/chunk-DGUM43GV.js +0 -11
  34. package/dist/chunk-OTCJ3VOK.js +0 -35
  35. package/dist/chunk-OTCJ3VOK.js.map +0 -1
  36. package/dist/chunk-QBMXJ3V2.js +0 -142
  37. package/dist/chunk-QBMXJ3V2.js.map +0 -1
  38. package/dist/gltf-loader-LKALCZAV.js +0 -8
  39. package/dist/showcase-runtime-55OVDYWT.js.map +0 -1
  40. /package/dist/{chunk-DGUM43GV.js.map → gltf-loader-WAM23F37.js.map} +0 -0
  41. /package/dist/{gltf-loader-LKALCZAV.js.map → showcase-inline-assets-B7U7VX5H.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -19,9 +19,24 @@ var __copyProps = (to, from, except, desc) => {
19
19
  };
20
20
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
21
 
22
+ // src/showcase-inline-assets.js
23
+ var showcase_inline_assets_exports = {};
24
+ __export(showcase_inline_assets_exports, {
25
+ INLINE_SHOWCASE_ASSET_URLS: () => INLINE_SHOWCASE_ASSET_URLS
26
+ });
27
+ var INLINE_SHOWCASE_ASSET_URLS;
28
+ var init_showcase_inline_assets = __esm({
29
+ "src/showcase-inline-assets.js"() {
30
+ INLINE_SHOWCASE_ASSET_URLS = Object.freeze({
31
+ "brigantine": "data:application/json;base64,ewogICJhc3NldCI6IHsKICAgICJ2ZXJzaW9uIjogIjIuMCIsCiAgICAiZ2VuZXJhdG9yIjogIkBwbGFzaXVzL2dwdS1zaGFyZWQgc2hvd2Nhc2UgYXNzZXQgZ2VuZXJhdG9yIgogIH0sCiAgInNjZW5lIjogMCwKICAic2NlbmVzIjogWwogICAgewogICAgICAibm9kZXMiOiBbCiAgICAgICAgMAogICAgICBdCiAgICB9CiAgXSwKICAibm9kZXMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUiLAogICAgICAiY2hpbGRyZW4iOiBbCiAgICAgICAgMSwKICAgICAgICAyLAogICAgICAgIDMKICAgICAgXSwKICAgICAgImV4dHJhcyI6IHsKICAgICAgICAicGh5c2ljcyI6IHsKICAgICAgICAgICJzaGFwZSI6ICJib3giLAogICAgICAgICAgImhhbGZFeHRlbnRzIjogWwogICAgICAgICAgICAxLjU4LAogICAgICAgICAgICAxLjEyLAogICAgICAgICAgICA0LjQKICAgICAgICAgIF0sCiAgICAgICAgICAibWFzcyI6IDQ3MDAsCiAgICAgICAgICAicmVzdGl0dXRpb24iOiAwLjIsCiAgICAgICAgICAibGluZWFyRGFtcGluZyI6IDAuMDM4LAogICAgICAgICAgImFuZ3VsYXJEYW1waW5nIjogMC4wNzYsCiAgICAgICAgICAid2F0ZXJsaW5lIjogMC40NAogICAgICAgIH0KICAgICAgfQogICAgfSwKICAgIHsKICAgICAgIm5hbWUiOiAiYnJpZ2FudGluZS1odWxsIiwKICAgICAgIm1lc2giOiAwCiAgICB9LAogICAgewogICAgICAibmFtZSI6ICJicmlnYW50aW5lLXJpZyIsCiAgICAgICJtZXNoIjogMQogICAgfSwKICAgIHsKICAgICAgIm5hbWUiOiAiYnJpZ2FudGluZS1sYW50ZXJucyIsCiAgICAgICJtZXNoIjogMgogICAgfQogIF0sCiAgIm1lc2hlcyI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAiYnJpZ2FudGluZS1odWxsIiwKICAgICAgInByaW1pdGl2ZXMiOiBbCiAgICAgICAgewogICAgICAgICAgImF0dHJpYnV0ZXMiOiB7CiAgICAgICAgICAgICJQT1NJVElPTiI6IDAsCiAgICAgICAgICAgICJOT1JNQUwiOiAxCiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiAyLAogICAgICAgICAgIm1hdGVyaWFsIjogMAogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgImF0dHJpYnV0ZXMiOiB7CiAgICAgICAgICAgICJQT1NJVElPTiI6IDMsCiAgICAgICAgICAgICJOT1JNQUwiOiA0CiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiA1LAogICAgICAgICAgIm1hdGVyaWFsIjogMQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgImF0dHJpYnV0ZXMiOiB7CiAgICAgICAgICAgICJQT1NJVElPTiI6IDYsCiAgICAgICAgICAgICJOT1JNQUwiOiA3CiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiA4LAogICAgICAgICAgIm1hdGVyaWFsIjogMgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgIHsKICAgICAgIm5hbWUiOiAiYnJpZ2FudGluZS1yaWciLAogICAgICAicHJpbWl0aXZlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAiYXR0cmlidXRlcyI6IHsKICAgICAgICAgICAgIlBPU0lUSU9OIjogOSwKICAgICAgICAgICAgIk5PUk1BTCI6IDEwCiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiAxMSwKICAgICAgICAgICJtYXRlcmlhbCI6IDMKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJhdHRyaWJ1dGVzIjogewogICAgICAgICAgICAiUE9TSVRJT04iOiAxMiwKICAgICAgICAgICAgIk5PUk1BTCI6IDEzCiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiAxNCwKICAgICAgICAgICJtYXRlcmlhbCI6IDQKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJhdHRyaWJ1dGVzIjogewogICAgICAgICAgICAiUE9TSVRJT04iOiAxNSwKICAgICAgICAgICAgIk5PUk1BTCI6IDE2CiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiAxNywKICAgICAgICAgICJtYXRlcmlhbCI6IDUKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUtbGFudGVybnMiLAogICAgICAicHJpbWl0aXZlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAiYXR0cmlidXRlcyI6IHsKICAgICAgICAgICAgIlBPU0lUSU9OIjogMTgsCiAgICAgICAgICAgICJOT1JNQUwiOiAxOQogICAgICAgICAgfSwKICAgICAgICAgICJpbmRpY2VzIjogMjAsCiAgICAgICAgICAibWF0ZXJpYWwiOiA2CiAgICAgICAgfQogICAgICBdCiAgICB9CiAgXSwKICAibWF0ZXJpYWxzIjogWwogICAgewogICAgICAibmFtZSI6ICJwYWludGVkLWh1bGwiLAogICAgICAicGJyTWV0YWxsaWNSb3VnaG5lc3MiOiB7CiAgICAgICAgImJhc2VDb2xvckZhY3RvciI6IFsKICAgICAgICAgIDAuNDIsCiAgICAgICAgICAwLjI0LAogICAgICAgICAgMC4xNiwKICAgICAgICAgIDEKICAgICAgICBdLAogICAgICAgICJtZXRhbGxpY0ZhY3RvciI6IDAuMDgsCiAgICAgICAgInJvdWdobmVzc0ZhY3RvciI6IDAuNzYKICAgICAgfQogICAgfSwKICAgIHsKICAgICAgIm5hbWUiOiAiZGVjay1wbGFuayIsCiAgICAgICJwYnJNZXRhbGxpY1JvdWdobmVzcyI6IHsKICAgICAgICAiYmFzZUNvbG9yRmFjdG9yIjogWwogICAgICAgICAgMC41MywKICAgICAgICAgIDAuMzksCiAgICAgICAgICAwLjI2LAogICAgICAgICAgMQogICAgICAgIF0sCiAgICAgICAgIm1ldGFsbGljRmFjdG9yIjogMC4wMiwKICAgICAgICAicm91Z2huZXNzRmFjdG9yIjogMC45CiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJuYW1lIjogImh1bGwtdHJpbSIsCiAgICAgICJwYnJNZXRhbGxpY1JvdWdobmVzcyI6IHsKICAgICAgICAiYmFzZUNvbG9yRmFjdG9yIjogWwogICAgICAgICAgMC43MiwKICAgICAgICAgIDAuNzEsCiAgICAgICAgICAwLjY2LAogICAgICAgICAgMQogICAgICAgIF0sCiAgICAgICAgIm1ldGFsbGljRmFjdG9yIjogMC4xOCwKICAgICAgICAicm91Z2huZXNzRmFjdG9yIjogMC40MgogICAgICB9CiAgICB9LAogICAgewogICAgICAibmFtZSI6ICJtYXN0LXdvb2QiLAogICAgICAicGJyTWV0YWxsaWNSb3VnaG5lc3MiOiB7CiAgICAgICAgImJhc2VDb2xvckZhY3RvciI6IFsKICAgICAgICAgIDAuMzcsCiAgICAgICAgICAwLjI3LAogICAgICAgICAgMC4xOCwKICAgICAgICAgIDEKICAgICAgICBdLAogICAgICAgICJtZXRhbGxpY0ZhY3RvciI6IDAuMDIsCiAgICAgICAgInJvdWdobmVzc0ZhY3RvciI6IDAuODIKICAgICAgfQogICAgfSwKICAgIHsKICAgICAgIm5hbWUiOiAic2FpbC1jYW52YXMiLAogICAgICAicGJyTWV0YWxsaWNSb3VnaG5lc3MiOiB7CiAgICAgICAgImJhc2VDb2xvckZhY3RvciI6IFsKICAgICAgICAgIDAuODIsCiAgICAgICAgICAwLjc5LAogICAgICAgICAgMC43MiwKICAgICAgICAgIDEKICAgICAgICBdLAogICAgICAgICJtZXRhbGxpY0ZhY3RvciI6IDAsCiAgICAgICAgInJvdWdobmVzc0ZhY3RvciI6IDAuOTYKICAgICAgfQogICAgfSwKICAgIHsKICAgICAgIm5hbWUiOiAibWV0YWwtZGFyayIsCiAgICAgICJwYnJNZXRhbGxpY1JvdWdobmVzcyI6IHsKICAgICAgICAiYmFzZUNvbG9yRmFjdG9yIjogWwogICAgICAgICAgMC4yMSwKICAgICAgICAgIDAuMjIsCiAgICAgICAgICAwLjI0LAogICAgICAgICAgMQogICAgICAgIF0sCiAgICAgICAgIm1ldGFsbGljRmFjdG9yIjogMC44NCwKICAgICAgICAicm91Z2huZXNzRmFjdG9yIjogMC4zNAogICAgICB9CiAgICB9LAogICAgewogICAgICAibmFtZSI6ICJ3YXJtLWdsYXNzIiwKICAgICAgInBick1ldGFsbGljUm91Z2huZXNzIjogewogICAgICAgICJiYXNlQ29sb3JGYWN0b3IiOiBbCiAgICAgICAgICAwLjk1LAogICAgICAgICAgMC44MiwKICAgICAgICAgIDAuNTYsCiAgICAgICAgICAwLjg0CiAgICAgICAgXSwKICAgICAgICAibWV0YWxsaWNGYWN0b3IiOiAwLjAyLAogICAgICAgICJyb3VnaG5lc3NGYWN0b3IiOiAwLjE2CiAgICAgIH0sCiAgICAgICJlbWlzc2l2ZUZhY3RvciI6IFsKICAgICAgICAwLjkyLAogICAgICAgIDAuNywKICAgICAgICAwLjM0CiAgICAgIF0sCiAgICAgICJhbHBoYU1vZGUiOiAiQkxFTkQiCiAgICB9CiAgXSwKICAiYnVmZmVycyI6IFsKICAgIHsKICAgICAgInVyaSI6ICJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsQUFBQUFJWHJVYi9Oekl6QWZQS3dQc2U2dUw3TnpJekFsLzhRUDlQZTRMNEFBRkRBQUFBQUFJWHJVYi9Oekl6QWwvOFFQOVBlNEw0QUFGREFBQUFBQUkvQ2RiOEFBRkRBZlBLd1BzZTZ1TDdOekl6QW5ETWlQeHBSMmo3TnpJekFTK3FFUDBJKzZENEFBRkRBZlBLd1BzZTZ1TDdOekl6QVMrcUVQMEkrNkQ0QUFGREFsLzhRUDlQZTRMNEFBRkRBbkRNaVB4cFIyajdOekl6QTdGRTRQNFhyVVQvTnpJekFQUXFYUDJabVpqOEFBRkRBbkRNaVB4cFIyajdOekl6QVBRcVhQMlptWmo4QUFGREFTK3FFUDBJKzZENEFBRkRBN0ZFNHY0WHJVVC9Oekl6QW5ETWl2eHBSMmo3TnpJekFTK3FFdjBJKzZENEFBRkRBN0ZFNHY0WHJVVC9Oekl6QVMrcUV2MEkrNkQ0QUFGREFQUXFYdjJabVpqOEFBRkRBbkRNaXZ4cFIyajdOekl6QWZQS3d2c2U2dUw3TnpJekFsLzhRdjlQZTRMNEFBRkRBbkRNaXZ4cFIyajdOekl6QWwvOFF2OVBlNEw0QUFGREFTK3FFdjBJKzZENEFBRkRBZlBLd3ZzZTZ1TDdOekl6QUFBQUFBSVhyVWIvTnpJekFBQUFBQUkvQ2RiOEFBRkRBZlBLd3ZzZTZ1TDdOekl6QUFBQUFBSS9DZGI4QUFGREFsLzhRdjlQZTRMNEFBRkRBQUFBQUFJL0NkYjhBQUZEQWwvOFFQOVBlNEw0QUFGREFvV2N6UDQvazhyNW1aZ2JBQUFBQUFJL0NkYjhBQUZEQW9XY3pQNC9rOHI1bVpnYkFBQUFBQUxnZWhiOW1aZ2JBbC84UVA5UGU0TDRBQUZEQVMrcUVQMEkrNkQ0QUFGREFWSFNrUDl1Sy9UNW1aZ2JBbC84UVA5UGU0TDRBQUZEQVZIU2tQOXVLL1Q1bVpnYkFvV2N6UDQvazhyNW1aZ2JBUytxRVAwSSs2RDRBQUZEQVBRcVhQMlptWmo4QUFGREFTT0c2UDBqaGVqOW1aZ2JBUytxRVAwSSs2RDRBQUZEQVNPRzZQMGpoZWo5bVpnYkFWSFNrUDl1Sy9UNW1aZ2JBUFFxWHYyWm1aajhBQUZEQVMrcUV2MEkrNkQ0QUFGREFWSFNrdjl1Sy9UNW1aZ2JBUFFxWHYyWm1aajhBQUZEQVZIU2t2OXVLL1Q1bVpnYkFTT0c2djBqaGVqOW1aZ2JBUytxRXYwSSs2RDRBQUZEQWwvOFF2OVBlNEw0QUFGREFvV2N6djQvazhyNW1aZ2JBUytxRXYwSSs2RDRBQUZEQW9XY3p2NC9rOHI1bVpnYkFWSFNrdjl1Sy9UNW1aZ2JBbC84UXY5UGU0TDRBQUZEQUFBQUFBSS9DZGI4QUFGREFBQUFBQUxnZWhiOW1aZ2JBbC84UXY5UGU0TDRBQUZEQUFBQUFBTGdlaGI5bVpnYkFvV2N6djQvazhyNW1aZ2JBQUFBQUFMZ2VoYjltWmdiQW9XY3pQNC9rOHI1bVpnYkFnU1pDUDIzbis3NHpNek8vQUFBQUFMZ2VoYjltWmdiQWdTWkNQMjNuKzc0ek16Ty9BQUFBQUhFOWlyOHpNek8vb1djelA0L2s4cjVtWmdiQVZIU2tQOXVLL1Q1bVpnYkFvZml4UDVNWUJEOHpNek8vb1djelA0L2s4cjVtWmdiQW9maXhQNU1ZQkQ4ek16Ty9nU1pDUDIzbis3NHpNek8vVkhTa1A5dUsvVDVtWmdiQVNPRzZQMGpoZWo5bVpnYkFjVDNLUDF5UGdqOHpNek8vVkhTa1A5dUsvVDVtWmdiQWNUM0tQMXlQZ2o4ek16Ty9vZml4UDVNWUJEOHpNek8vU09HNnYwamhlajltWmdiQVZIU2t2OXVLL1Q1bVpnYkFvZml4djVNWUJEOHpNek8vU09HNnYwamhlajltWmdiQW9maXh2NU1ZQkQ4ek16Ty9jVDNLdjF5UGdqOHpNek8vVkhTa3Y5dUsvVDVtWmdiQW9XY3p2NC9rOHI1bVpnYkFnU1pDdjIzbis3NHpNek8vVkhTa3Y5dUsvVDVtWmdiQWdTWkN2MjNuKzc0ek16Ty9vZml4djVNWUJEOHpNek8vb1djenY0L2s4cjVtWmdiQUFBQUFBTGdlaGI5bVpnYkFBQUFBQUhFOWlyOHpNek8vb1djenY0L2s4cjVtWmdiQUFBQUFBSEU5aXI4ek16Ty9nU1pDdjIzbis3NHpNek8vQUFBQUFIRTlpcjh6TXpPL2dTWkNQMjNuKzc0ek16Ty9WbjB1UDBDazM3NW1ab1kvQUFBQUFIRTlpcjh6TXpPL1ZuMHVQMENrMzc1bVpvWS9BQUFBQUVqaGVyOW1ab1kvZ1NaQ1AyM24rNzR6TXpPL29maXhQNU1ZQkQ4ek16Ty81ZktmUC84aC9UNW1ab1kvZ1NaQ1AyM24rNzR6TXpPLzVmS2ZQLzhoL1Q1bVpvWS9WbjB1UDBDazM3NW1ab1kvb2ZpeFA1TVlCRDh6TXpPL2NUM0tQMXlQZ2o4ek16Ty9qOEsxUDQvQ2RUOW1ab1kvb2ZpeFA1TVlCRDh6TXpPL2o4SzFQNC9DZFQ5bVpvWS81ZktmUC84aC9UNW1ab1kvY1QzS3YxeVBnajh6TXpPL29maXh2NU1ZQkQ4ek16Ty81Zktmdi84aC9UNW1ab1kvY1QzS3YxeVBnajh6TXpPLzVmS2Z2LzhoL1Q1bVpvWS9qOEsxdjQvQ2RUOW1ab1kvb2ZpeHY1TVlCRDh6TXpPL2dTWkN2MjNuKzc0ek16Ty9WbjB1djBDazM3NW1ab1kvb2ZpeHY1TVlCRDh6TXpPL1ZuMHV2MENrMzc1bVpvWS81Zktmdi84aC9UNW1ab1kvZ1NaQ3YyM24rNzR6TXpPL0FBQUFBSEU5aXI4ek16Ty9BQUFBQUVqaGVyOW1ab1kvZ1NaQ3YyM24rNzR6TXpPL0FBQUFBRWpoZXI5bVpvWS9WbjB1djBDazM3NW1ab1kvQUFBQUFFamhlcjltWm9ZL1ZuMHVQMENrMzc1bVpvWS9zQVBuUGpTQXQ3NHpNeU5BQUFBQUFFamhlcjltWm9ZL3NBUG5QalNBdDc0ek15TkFBQUFBQUQwS1Y3OHpNeU5BVm4wdVAwQ2szNzVtWm9ZLzVmS2ZQLzhoL1Q1bVpvWS9ZY05UUDljMDd6NHpNeU5BVm4wdVAwQ2szNzVtWm9ZL1ljTlRQOWMwN3o0ek15TkFzQVBuUGpTQXQ3NHpNeU5BNWZLZlAvOGgvVDVtWm9ZL2o4SzFQNC9DZFQ5bVpvWS8xNk53UDY1SFlUOHpNeU5BNWZLZlAvOGgvVDVtWm9ZLzE2TndQNjVIWVQ4ek15TkFZY05UUDljMDd6NHpNeU5BajhLMXY0L0NkVDltWm9ZLzVmS2Z2LzhoL1Q1bVpvWS9ZY05UdjljMDd6NHpNeU5BajhLMXY0L0NkVDltWm9ZL1ljTlR2OWMwN3o0ek15TkExNk53djY1SFlUOHpNeU5BNWZLZnYvOGgvVDVtWm9ZL1ZuMHV2MENrMzc1bVpvWS9zQVBudmpTQXQ3NHpNeU5BNWZLZnYvOGgvVDVtWm9ZL3NBUG52alNBdDc0ek15TkFZY05UdjljMDd6NHpNeU5BVm4wdXYwQ2szNzVtWm9ZL0FBQUFBRWpoZXI5bVpvWS9BQUFBQUQwS1Y3OHpNeU5BVm4wdXYwQ2szNzVtWm9ZL0FBQUFBRDBLVjc4ek15TkFzQVBudmpTQXQ3NHpNeU5BQUFBQUFEMEtWNzh6TXlOQXNBUG5QalNBdDc0ek15TkErdTNyUGJyYWlyNmFtWGxBQUFBQUFEMEtWNzh6TXlOQSt1M3JQYnJhaXI2YW1YbEFBQUFBQUhzVUxyK2FtWGxBc0FQblBqU0F0NzR6TXlOQVljTlRQOWMwN3o0ek15TkEwRVJZUG9qMDJ6NmFtWGxBc0FQblBqU0F0NzR6TXlOQTBFUllQb2owMno2YW1YbEErdTNyUGJyYWlyNmFtWGxBWWNOVFA5YzA3ejR6TXlOQTE2TndQNjVIWVQ4ek15TkFqOEoxUGhTdVJ6K2FtWGxBWWNOVFA5YzA3ejR6TXlOQWo4SjFQaFN1UnorYW1YbEEwRVJZUG9qMDJ6NmFtWGxBMTZOd3Y2NUhZVDh6TXlOQVljTlR2OWMwN3o0ek15TkEwRVJZdm9qMDJ6NmFtWGxBMTZOd3Y2NUhZVDh6TXlOQTBFUll2b2owMno2YW1YbEFqOEoxdmhTdVJ6K2FtWGxBWWNOVHY5YzA3ejR6TXlOQXNBUG52alNBdDc0ek15TkErdTNydmJyYWlyNmFtWGxBWWNOVHY5YzA3ejR6TXlOQSt1M3J2YnJhaXI2YW1YbEEwRVJZdm9qMDJ6NmFtWGxBc0FQbnZqU0F0NzR6TXlOQUFBQUFBRDBLVjc4ek15TkFBQUFBQUhzVUxyK2FtWGxBc0FQbnZqU0F0NzR6TXlOQUFBQUFBSHNVTHIrYW1YbEErdTNydmJyYWlyNmFtWGxBajhKMVBoU3VSeithbVhsQUFBQUFBTTNNVEQrYW1YbEFqOEoxdmhTdVJ6K2FtWGxBajhKMVBoU3VSeithbVhsQWo4SjF2aFN1UnorYW1YbEEwRVJZdm9qMDJ6NmFtWGxBajhKMVBoU3VSeithbVhsQTBFUll2b2owMno2YW1YbEErdTNydmJyYWlyNmFtWGxBajhKMVBoU3VSeithbVhsQSt1M3J2YnJhaXI2YW1YbEFBQUFBQUhzVUxyK2FtWGxBajhKMVBoU3VSeithbVhsQUFBQUFBSHNVTHIrYW1YbEErdTNyUGJyYWlyNmFtWGxBajhKMVBoU3VSeithbVhsQSt1M3JQYnJhaXI2YW1YbEEwRVJZUG9qMDJ6NmFtWGxBN0ZFNHY0WHJVVC9Oekl6QUFBQUFBUFlvWEQvTnpJekE3RkU0UDRYclVUL056SXpBN0ZFNHY0WHJVVC9Oekl6QTdGRTRQNFhyVVQvTnpJekFuRE1pUHhwUjJqN056SXpBN0ZFNHY0WHJVVC9Oekl6QW5ETWlQeHBSMmo3TnpJekFmUEt3UHNlNnVMN056SXpBN0ZFNHY0WHJVVC9Oekl6QWZQS3dQc2U2dUw3TnpJekFBQUFBQUlYclViL056SXpBN0ZFNHY0WHJVVC9Oekl6QUFBQUFBSVhyVWIvTnpJekFmUEt3dnNlNnVMN056SXpBN0ZFNHY0WHJVVC9Oekl6QWZQS3d2c2U2dUw3TnpJekFuRE1pdnhwUjJqN056SXpBeHNoSVArY2NGNy8vYUVPK3hzaElQK2NjRjcvL2FFTyt4c2hJUCtjY0Y3Ly9hRU8rUHBVc1A2V3hPNzh0ekxhOVBwVXNQNld4Tzc4dHpMYTlQcFVzUDZXeE83OHR6TGE5aGRCa1A5OXNwNzRlSUoyK2hkQmtQOTlzcDc0ZUlKMitoZEJrUDk5c3A3NGVJSjIrN05wZFAvcVQ2cjUxWGtxKzdOcGRQL3FUNnI1MVhrcSs3TnBkUC9xVDZyNTFYa3ErekJCcVAyS0ZUYjZiR3JTK3pCQnFQMktGVGI2YkdyUyt6QkJxUDJLRlRiNmJHclMrbk5ablA0a1VrNzVEdkorK25OWm5QNGtVazc1RHZKKytuTlpuUDRrVWs3NUR2SisrN3ROc3YwanlUNzZDUktTKzd0TnN2MGp5VDc2Q1JLUys3dE5zdjBqeVQ3NkNSS1MrVDVObHZ3YWxrYjVPaDYyK1Q1Tmx2d2Fsa2I1T2g2MitUNU5sdndhbGtiNU9oNjIrZHBOcnYybGZyTDdQYkV5K2RwTnJ2Mmxmckw3UGJFeStkcE5ydjJsZnJMN1BiRXkrSE1SWXYzTXk1YjZxTHBPK0hNUll2M015NWI2cUxwTytITVJZdjNNeTViNnFMcE8rVFA5THYvS0hHYitnaHBXOVRQOUx2L0tIR2IrZ2hwVzlUUDlMdi9LSEdiK2docFc5b0ljcXZ3RjJPYitSaWpXK29JY3F2d0YyT2IrUmlqVytvSWNxdndGMk9iK1JpalcrOG1Jc1AvSjZPNzhFRmMrOThtSXNQL0o2Tzc4RUZjKzk4bUlzUC9KNk83OEVGYys5allzZ1ArbnJScitIYUYyOWpZc2dQK25yUnIrSGFGMjlqWXNnUCtuclJyK0hhRjI5UUFaZlAzblE2NzY2RkM2K1FBWmZQM25RNjc2NkZDNitRQVpmUDNuUTY3NjZGQzYrQjlaWlAzTTBBNytaeSt1OUI5WlpQM00wQTcrWnkrdTlCOVpaUDNNMEE3K1p5K3U5S01KdVAyeDRsNzZ2ZEZPK0tNSnVQMng0bDc2dmRGTytLTUp1UDJ4NGw3NnZkRk8rTXBCc1B6djdxcjc0WHo2K01wQnNQenY3cXI3NFh6NitNcEJzUHp2N3FyNzRYejYrUnBWdnYxditsNzQwVmtLK1JwVnZ2MXYrbDc0MFZrSytScFZ2djF2K2w3NDBWa0srQTlkcnYyTjFxcjY1K0UyK0E5ZHJ2Mk4xcXI2NStFMitBOWRydjJOMXFyNjUrRTIrNThSZ3Y3Mm83YjVFUCsrOTU4Umd2NzJvN2I1RVArKzk1OFJndjcybzdiNUVQKys5aGw5WXYrRlNBcjk3bFNhK2hsOVl2K0ZTQXI5N2xTYStobDlZditGU0FyOTdsU2ErUGd3dHZ4RXpQTDltZVZHOVBnd3R2eEV6UEw5bWVWRzlQZ3d0dnhFelBMOW1lVkc5bGdZZ3Z5cEhScjlhSzhhOWxnWWd2eXBIUnI5YUs4YTlsZ1lndnlwSFJyOWFLOGE5bzYwZ1B5VVdSNzhwMFJHOW82MGdQeVVXUjc4cDBSRzlvNjBnUHlVV1I3OHAwUkc5Z2RFY1A0RkRTcjlEN2JpOGdkRWNQNEZEU3I5RDdiaThnZEVjUDRGRFNyOUQ3Ymk4alBCYVA1M2VBNyt2NFdpOWpQQmFQNTNlQTcrdjRXaTlqUEJhUDUzZUE3K3Y0V2k5QTdWWVB6WGZCNzhlL0NtOUE3VllQelhmQjc4ZS9DbTlBN1ZZUHpYZkI3OGUvQ205WXlod1AxS1VyYjZMMTVDOVl5aHdQMUtVcmI2TDE1QzlZeWh3UDFLVXJiNkwxNUM5bWhodlB5L2tzNzQwbG9XOW1oaHZQeS9rczc0MGxvVzltaGh2UHkva3M3NDBsb1c5WGoxd3YzeWpyYjcvcFlhOVhqMXd2M3lqcmI3L3BZYTlYajF3djN5anJiNy9wWWE5eXdSdnYwalZzNzZnV0krOXl3UnZ2MGpWczc2Z1dJKzl5d1J2djBqVnM3NmdXSSs5aWhwYnYrajNBNy8reGlxOWlocGJ2K2ozQTcvK3hpcTlpaHBiditqM0E3Lyt4aXE5OG8xWXY3YkdCNzhKRTJXOThvMVl2N2JHQjc4SkUyVzk4bzFZdjdiR0I3OEpFMlc5ajcwZ3Y5OHBSNytvRjdhOGo3MGd2OThwUjcrb0Y3YThqNzBndjk4cFI3K29GN2E4OXNJY3Y4QXdTci94M0ErOTlzSWN2OEF3U3IveDNBKzk5c0ljdjhBd1NyL3gzQSs5NzZVY1AwOExTcjl5OWxNOTc2VWNQMDhMU3I5eTlsTTk3NlVjUDA4TFNyOXk5bE05MjJNZlB5QUFTTCtMMnpZOTIyTWZQeUFBU0wrTDJ6WTkyMk1mUHlBQVNMK0wyelk5eEh0WVAxQzdCNytQNEhzOXhIdFlQMUM3QjcrUDRIczl4SHRZUDFDN0I3K1A0SHM5R3p4YVA2QWRCYjk2YTF3OUd6eGFQNkFkQmI5NmExdzlHenhhUDZBZEJiOTZhMXc5TlBadVAwN0tzNzVpSUpZOU5QWnVQMDdLczc1aUlKWTlOUFp1UDA3S3M3NWlJSlk5OWN0dlAzU0ZyNzVlcnBFOTljdHZQM1NGcjc1ZXJwRTk5Y3R2UDNTRnI3NWVycEU5WWdGdnY3ZlNzNzZjOVpBOVlnRnZ2N2ZTczc2YzlaQTlZZ0Z2djdmU3M3NmM5WkE5czc5dnYzdDhyNzdlU3BjOXM3OXZ2M3Q4cjc3ZVNwYzlzNzl2djN0OHI3N2VTcGM5UVpSWXY2dktCNytZbTF3OVFaUll2NnZLQjcrWW0xdzlRWlJZdjZ2S0I3K1ltMXc5RFNGYXZ4OE5CYjlsaG40OURTRmF2eDhOQmI5bGhuNDlEU0Zhdng4TkJiOWxobjQ5MnJJY3Yva2JTcjhleVRnOTJySWN2L2tiU3I4ZXlUZzkyckljdi9rYlNyOGV5VGc5YlZVZnZ3WHVSNzhCeUZROWJWVWZ2d1h1Ujc4QnlGUTliVlVmdndYdVI3OEJ5RlE5dlJRZVA2QmJScjlTbUFvK3ZSUWVQNkJiUnI5U21Bbyt2UlFlUDZCYlJyOVNtQW8rdlhBNlAvYXJMci9yYTRJOXZYQTZQL2FyTHIvcmE0STl2WEE2UC9hckxyL3JhNEk5RC9KVVA3VGpBYi9IY0dZK0QvSlVQN1RqQWIvSGNHWStEL0pVUDdUakFiL0hjR1kraXY5bFA1WiswYjdHTlNNK2l2OWxQNVorMGI3R05TTStpdjlsUDVaKzBiN0dOU00rNjE1blA1ZGFxYjZMQzRzKzYxNW5QNWRhcWI2TEM0cys2MTVuUDVkYXFiNkxDNHMrdnBodVAxWmxncjVjQTRRK3ZwaHVQMVpsZ3I1Y0E0USt2cGh1UDFabGdyNWNBNFErWGNWb3YvVmdxcjdQQVlBK1hjVm92L1ZncXI3UEFZQStYY1Zvdi9WZ3FyN1BBWUErR2VGc3Z4RjFnYjdJc3BBK0dlRnN2eEYxZ2I3SXNwQStHZUZzdnhGMWdiN0lzcEErcU54WHZ4cXJBNzh1SnlBK3FOeFh2eHFyQTc4dUp5QStxTnhYdnhxckE3OHVKeUErRkJaaXYyanV6Yjd5TVhjK0ZCWml2Mmp1emI3eU1YYytGQlppdjJqdXpiN3lNWGMrTmlBZnZ6K3JSNzhORnBVOU5pQWZ2eityUjc4TkZwVTlOaUFmdnorclI3OE5GcFU5cXM4NHZ6Y2xMYjgydnhVK3FzODR2emNsTGI4MnZ4VStxczg0dnpjbExiODJ2eFUrWnpzMlA2RzZLcitRaUdFK1p6czJQNkc2S3IrUWlHRStaenMyUDZHNktyK1FpR0UrcTBaMlB5Zk5pcjZ4bWdNOXEwWjJQeWZOaXI2eG1nTTlxMFoyUHlmTmlyNnhtZ005Q3dsWVA4REd4TDd4cTc4K0N3bFlQOERHeEw3eHE3OCtDd2xZUDhER3hMN3hxNzgrOWI1MVA4S25Ccjc1V1gwKzliNTFQOEtuQnI3NVdYMCs5YjUxUDhLbkJyNzVXWDArSjVKZVAzSkdjNzdaemQwK0o1SmVQM0pHYzc3WnpkMCtKNUplUDNKR2M3N1p6ZDArZFhOb1B6SFltTDJkRWRNK2RYTm9QekhZbUwyZEVkTStkWE5vUHpIWW1MMmRFZE0rTXFGaXZ5UzJkNzcyWHNzK01xRml2eVMyZDc3MlhzcytNcUZpdnlTMmQ3NzJYc3MrNkRoanZ3eG9sYjBFMytnKzZEaGp2d3hvbGIwRTMrZys2RGhqdnd4b2xiMEUzK2crWGRoaHZ6RzJ6YjZVYW5zK1hkaGh2ekcyemI2VWFucytYZGhodnpHMnpiNlVhbnMrZW5CbnY5YWgvYjJlY2RFK2VuQm52OWFoL2IyZWNkRStlbkJudjlhaC9iMmVjZEUra2pVNnY0ZDBMci9NYUtVOWtqVTZ2NGQwTHIvTWFLVTlralU2djRkMExyL01hS1U5dmFSdXYrdC9ocjVQOVg0K3ZhUnV2K3QvaHI1UDlYNCt2YVJ1dit0L2hyNVA5WDQrQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQkFBSUFBd0FFQUFVQUJnQUhBQWdBQ1FBS0FBc0FEQUFOQUE0QUR3QVFBQkVBRWdBVEFCUUFGUUFXQUJjQUdBQVpBQm9BR3dBY0FCMEFIZ0FmQUNBQUlRQWlBQ01BSkFBbEFDWUFKd0FvQUNrQUtnQXJBQ3dBTFFBdUFDOEFNQUF4QURJQU13QTBBRFVBTmdBM0FEZ0FPUUE2QURzQVBBQTlBRDRBUHdCQUFFRUFRZ0JEQUVRQVJRQkdBRWNBU0FCSkFFb0FTd0JNQUUwQVRnQlBBRkFBVVFCU0FGTUFWQUJWQUZZQVZ3QllBRmtBV2dCYkFGd0FYUUJlQUY4QVlBQmhBR0lBWXdCa0FHVUFaZ0JuQUdnQWFRQnFBR3NBYkFCdEFHNEFid0J3QUhFQWNnQnpBSFFBZFFCMkFIY0FlQUI1QUhvQWV3QjhBSDBBZmdCL0FJQUFnUUNDQUlNQWhBQ0ZBSVlBaHdDSUFJa0FpZ0NMQUl3QWpRQ09BSThBa0FDUkFKSUFrd0NVQUpVQWxnQ1hBSmdBbVFDYUFKc0FuQUNkQUo0QW53Q2dBS0VBb2dDakFLUUFwUUNtQUtjQXFBQ3BBS29BcXdDc0FLMEFyZ0N2QUxBQXNRQ3lBTE1BdEFDMUFMWUF0d0M0QUxrQXVnQzdBTHdBdlFDK0FMOEF3QURCQU1JQXd3REVBTVVBeGdESEFNZ0F5UURLQU1zQXpBRE5BTTRBendEUUFORUEwZ0RUQU5RQTFRRFdBTmNBMkFEWkFOb0Eyd0RjQU4wQTNnRGZBT0FBNFFEaUFPTUE1QURsQU9ZQTV3RG9BT2tBNmdEckFPd0E3UUR1QU84QThBRHhBUElBOHdEMEFQVUE5Z0QzQVBnQStRRDZBUHNBQUFBQUFQWW9YRC9Oekl6QTdGRTRQNFhyVVQvTnpJekFQUXFYUDJabVpqOEFBRkRBQUFBQUFQWW9YRC9Oekl6QVBRcVhQMlptWmo4QUFGREFBQUFBQURNemN6OEFBRkRBN0ZFNHY0WHJVVC9Oekl6QUFBQUFBUFlvWEQvTnpJekFBQUFBQURNemN6OEFBRkRBN0ZFNHY0WHJVVC9Oekl6QUFBQUFBRE16Y3o4QUFGREFQUXFYdjJabVpqOEFBRkRBQUFBQUFETXpjejhBQUZEQVBRcVhQMlptWmo4QUFGREFTT0c2UDBqaGVqOW1aZ2JBQUFBQUFETXpjejhBQUZEQVNPRzZQMGpoZWo5bVpnYkFBQUFBQUFyWGd6OW1aZ2JBUFFxWHYyWm1aajhBQUZEQUFBQUFBRE16Y3o4QUFGREFBQUFBQUFyWGd6OW1aZ2JBUFFxWHYyWm1aajhBQUZEQUFBQUFBQXJYZ3o5bVpnYkFTT0c2djBqaGVqOW1aZ2JBQUFBQUFBclhnejltWmdiQVNPRzZQMGpoZWo5bVpnYkFjVDNLUDF5UGdqOHpNek8vQUFBQUFBclhnejltWmdiQWNUM0tQMXlQZ2o4ek16Ty9BQUFBQUhFOWlqOHpNek8vU09HNnYwamhlajltWmdiQUFBQUFBQXJYZ3o5bVpnYkFBQUFBQUhFOWlqOHpNek8vU09HNnYwamhlajltWmdiQUFBQUFBSEU5aWo4ek16Ty9jVDNLdjF5UGdqOHpNek8vQUFBQUFIRTlpajh6TXpPL2NUM0tQMXlQZ2o4ek16Ty9qOEsxUDQvQ2RUOW1ab1kvQUFBQUFIRTlpajh6TXpPL2o4SzFQNC9DZFQ5bVpvWS9BQUFBQUs1SGdUOW1ab1kvY1QzS3YxeVBnajh6TXpPL0FBQUFBSEU5aWo4ek16Ty9BQUFBQUs1SGdUOW1ab1kvY1QzS3YxeVBnajh6TXpPL0FBQUFBSzVIZ1Q5bVpvWS9qOEsxdjQvQ2RUOW1ab1kvQUFBQUFLNUhnVDltWm9ZL2o4SzFQNC9DZFQ5bVpvWS8xNk53UDY1SFlUOHpNeU5BQUFBQUFLNUhnVDltWm9ZLzE2TndQNjVIWVQ4ek15TkFBQUFBQUIrRmF6OHpNeU5BajhLMXY0L0NkVDltWm9ZL0FBQUFBSzVIZ1Q5bVpvWS9BQUFBQUIrRmF6OHpNeU5BajhLMXY0L0NkVDltWm9ZL0FBQUFBQitGYXo4ek15TkExNk53djY1SFlUOHpNeU5BQUFBQUFCK0Zhejh6TXlOQTE2TndQNjVIWVQ4ek15TkFqOEoxUGhTdVJ6K2FtWGxBQUFBQUFCK0Zhejh6TXlOQWo4SjFQaFN1UnorYW1YbEFBQUFBQU0zTVREK2FtWGxBMTZOd3Y2NUhZVDh6TXlOQUFBQUFBQitGYXo4ek15TkFBQUFBQU0zTVREK2FtWGxBMTZOd3Y2NUhZVDh6TXlOQUFBQUFBTTNNVEQrYW1YbEFqOEoxdmhTdVJ6K2FtWGxBZXhRdXZ3QUFnRCthbVJtL2V4UXVQd0FBZ0QrYW1SbS9leFF1UDdnZXhUK2FtUm0vZXhRdXZ3QUFnRCthbVJtL2V4UXVQN2dleFQrYW1SbS9leFF1djdnZXhUK2FtUm0vZXhRdVB3QUFnRDltWmhiQWV4UXV2d0FBZ0Q5bVpoYkFleFF1djdnZXhUOW1aaGJBZXhRdVB3QUFnRDltWmhiQWV4UXV2N2dleFQ5bVpoYkFleFF1UDdnZXhUOW1aaGJBZXhRdXZ3QUFnRDltWmhiQWV4UXV2d0FBZ0QrYW1SbS9leFF1djdnZXhUK2FtUm0vZXhRdXZ3QUFnRDltWmhiQWV4UXV2N2dleFQrYW1SbS9leFF1djdnZXhUOW1aaGJBZXhRdVB3QUFnRCthbVJtL2V4UXVQd0FBZ0Q5bVpoYkFleFF1UDdnZXhUOW1aaGJBZXhRdVB3QUFnRCthbVJtL2V4UXVQN2dleFQ5bVpoYkFleFF1UDdnZXhUK2FtUm0vZXhRdXY3Z2V4VCthbVJtL2V4UXVQN2dleFQrYW1SbS9leFF1UDdnZXhUOW1aaGJBZXhRdXY3Z2V4VCthbVJtL2V4UXVQN2dleFQ5bVpoYkFleFF1djdnZXhUOW1aaGJBZXhRdXZ3QUFnRDltWmhiQWV4UXVQd0FBZ0Q5bVpoYkFleFF1UHdBQWdEK2FtUm0vZXhRdXZ3QUFnRDltWmhiQWV4UXVQd0FBZ0QrYW1SbS9leFF1dndBQWdEK2FtUm0vcmtmaHZseVBnaithbWRrL3JrZmhQbHlQZ2orYW1kay9ya2ZoUHRlanNEK2FtZGsvcmtmaHZseVBnaithbWRrL3JrZmhQdGVqc0QrYW1kay9ya2ZodnRlanNEK2FtZGsvcmtmaFBseVBnajhBQUFBL3JrZmh2bHlQZ2o4QUFBQS9ya2ZodnRlanNEOEFBQUEvcmtmaFBseVBnajhBQUFBL3JrZmh2dGVqc0Q4QUFBQS9ya2ZoUHRlanNEOEFBQUEvcmtmaHZseVBnajhBQUFBL3JrZmh2bHlQZ2orYW1kay9ya2ZodnRlanNEK2FtZGsvcmtmaHZseVBnajhBQUFBL3JrZmh2dGVqc0QrYW1kay9ya2ZodnRlanNEOEFBQUEvcmtmaFBseVBnaithbWRrL3JrZmhQbHlQZ2o4QUFBQS9ya2ZoUHRlanNEOEFBQUEvcmtmaFBseVBnaithbWRrL3JrZmhQdGVqc0Q4QUFBQS9ya2ZoUHRlanNEK2FtZGsvcmtmaHZ0ZWpzRCthbWRrL3JrZmhQdGVqc0QrYW1kay9ya2ZoUHRlanNEOEFBQUEvcmtmaHZ0ZWpzRCthbWRrL3JrZmhQdGVqc0Q4QUFBQS9ya2ZodnRlanNEOEFBQUEvcmtmaHZseVBnajhBQUFBL3JrZmhQbHlQZ2o4QUFBQS9ya2ZoUGx5UGdqK2FtZGsvcmtmaHZseVBnajhBQUFBL3JrZmhQbHlQZ2orYW1kay9ya2Zodmx5UGdqK2FtZGsvekVGaXZRYUtmcjl4NkxvOXpFRml2UWFLZnI5eDZMbzl6RUZpdlFhS2ZyOXg2TG85UnVBc3ZRRCtmcisxcFo4OVJ1QXN2UUQrZnIrMXBaODlSdUFzdlFEK2ZyKzFwWjg5eElOaVBUM1VmcitQaTU4OXhJTmlQVDNVZnIrUGk1ODl4SU5pUFQzVWZyK1BpNTg5Y3NJc1BRTFNmcjl2WGJBOWNzSXNQUUxTZnI5dlhiQTljc0lzUFFMU2ZyOXZYYkE5cGRvc3ZiUDFmcjhMNzZJOXBkb3N2YlAxZnI4TDc2STlwZG9zdmJQMWZyOEw3Nkk5ck5vTHZlRTdmNzhRQzQ0OXJOb0x2ZUU3Zjc4UUM0NDlyTm9MdmVFN2Y3OFFDNDQ5aGZ3c1Bhc25mNy9SLzQwOWhmd3NQYXNuZjcvUi80MDloZndzUGFzbmY3L1IvNDA5ME1RTFBmc1RmNy9KK0o0OTBNUUxQZnNUZjcvSitKNDkwTVFMUGZzVGY3L0orSjQ5VVI4TXZTaTVmNytkNlFBOVVSOE12U2k1ZjcrZDZRQTlVUjhNdlNpNWY3K2Q2UUE5V0ZVYnZTS25mNzljRmhJOVdGVWJ2U0tuZjc5Y0ZoSTlXRlVidlNLbmY3OWNGaEk5UWhvTVBldXZmNzlpR3hJOVFob01QZXV2Zjc5aUd4STlRaG9NUGV1dmY3OWlHeEk5amxvYlBiU3ZmNytETXdJOWpsb2JQYlN2ZjcrRE13STlqbG9iUGJTdmY3K0RNd0k5WGxJYnZUdWlmNzhvYnhxOVhsSWJ2VHVpZjc4b2J4cTlYbElidlR1aWY3OG9ieHE5WUFVUXZTU2pmNytjbXlPOVlBVVF2U1NqZjcrY215TzlZQVVRdlNTamY3K2NteU85Nms0YlBZdWNmNzlqbHlPOTZrNGJQWXVjZjc5amx5Tzk2azRiUFl1Y2Y3OWpseU85N2dnUVBYU3BmNy93YWhtOTdnZ1FQWFNwZjcvd2FobTk3Z2dRUFhTcGY3L3dhaG05S3RZUHZWZFBmNzh6OG9POUt0WVB2VmRQZjc4ejhvTzlLdFlQdlZkUGY3OHo4b085QjlRdHZXdFBmNzhLR1hXOUI5UXR2V3RQZjc4S0dYVzlCOVF0dld0UGY3OEtHWFc5cXVBUFBmdGhmNy9kS25XOXF1QVBQZnRoZjcvZEtuVzlxdUFQUGZ0aGY3L2RLblc5aE1BdFBjRXlmNzlXcjRpOWhNQXRQY0V5Zjc5V3I0aTloTUF0UGNFeWY3OVdyNGk5cmxjdHZjZVlmcjhWME1POXJsY3R2Y2VZZnI4VjBNTzlybGN0dmNlWWZyOFYwTU85N1dtcHZlTWVmcjlCdGJTOTdXbXB2ZU1lZnI5QnRiUzk3V21wdmVNZWZyOUJ0YlM5SlhVdFBRN0VmcisxS3JXOUpYVXRQUTdFZnIrMUtyVzlKWFV0UFE3RWZyKzFLclc5WCsyb1BRNWtmYi9idisyOVgrMm9QUTVrZmIvYnYrMjlYKzJvUFE1a2ZiL2J2KzI5QUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBSUFBQUFBQUFBQ0FQd0FBQUlBQUFBQUFBQUNBUHdBQUFJQUFBQUFBQUFBQWdBQUFnRDhBQUFBQUFBQUFnQUFBZ0Q4QUFBQUFBQUFBZ0FBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBSUFBQUFBQUFBQ0FQd0FBQUlBQUFBQUFBQUNBUHdBQUFJQUFBQUFBQUFBQWdBQUFnRDhBQUFBQUFBQUFnQUFBZ0Q4QUFBQUFBQUFBZ0FBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQkFBSUFBd0FFQUFVQUJnQUhBQWdBQ1FBS0FBc0FEQUFOQUE0QUR3QVFBQkVBRWdBVEFCUUFGUUFXQUJjQUdBQVpBQm9BR3dBY0FCMEFIZ0FmQUNBQUlRQWlBQ01BSkFBbEFDWUFKd0FvQUNrQUtnQXJBQ3dBTFFBdUFDOEFNQUF4QURJQU13QTBBRFVBTmdBM0FEZ0FPUUE2QURzQVBBQTlBRDRBUHdCQUFFRUFRZ0JEQUVRQVJRQkdBRWNBU0FCSkFFb0FTd0JNQUUwQVRnQlBBRkFBVVFCU0FGTUFWQUJWQUZZQVZ3QllBRmtBV2dCYkFGd0FYUUJlQUY4QVlBQmhBR0lBWXdCa0FHVUFaZ0JuQUdnQWFRQnFBR3NBYkFCdEFHNEFid0J3QUhFQWNnQnpBSFFBZFFCMkFIY0FlQUI1QUhvQWV3QjhBSDBBZmdCL0FJQUFnUUNDQUlNQWhBQ0ZBSVlBaHdDSUFJa0FpZ0NMQUl3QWpRQ09BSThBcEhDOXZ6MEtWeithbVJsQXBIQzlQejBLVnorYW1SbEFwSEM5UHpNemN6K2FtUmxBcEhDOXZ6MEtWeithbVJsQXBIQzlQek16Y3orYW1SbEFwSEM5dnpNemN6K2FtUmxBcEhDOVB6MEtWei9OekF6QXBIQzl2ejBLVnovTnpBekFwSEM5dnpNemN6L056QXpBcEhDOVB6MEtWei9OekF6QXBIQzl2ek16Y3ovTnpBekFwSEM5UHpNemN6L056QXpBcEhDOXZ6MEtWei9OekF6QXBIQzl2ejBLVnorYW1SbEFwSEM5dnpNemN6K2FtUmxBcEhDOXZ6MEtWei9OekF6QXBIQzl2ek16Y3orYW1SbEFwSEM5dnpNemN6L056QXpBcEhDOVB6MEtWeithbVJsQXBIQzlQejBLVnovTnpBekFwSEM5UHpNemN6L056QXpBcEhDOVB6MEtWeithbVJsQXBIQzlQek16Y3ovTnpBekFwSEM5UHpNemN6K2FtUmxBcEhDOXZ6TXpjeithbVJsQXBIQzlQek16Y3orYW1SbEFwSEM5UHpNemN6L056QXpBcEhDOXZ6TXpjeithbVJsQXBIQzlQek16Y3ovTnpBekFwSEM5dnpNemN6L056QXpBcEhDOXZ6MEtWei9OekF6QXBIQzlQejBLVnovTnpBekFwSEM5UHowS1Z6K2FtUmxBcEhDOXZ6MEtWei9OekF6QXBIQzlQejBLVnorYW1SbEFwSEM5dnowS1Z6K2FtUmxBS1Z3UHZ4K0Zxejk3Rkc2L0tWd1BQeCtGcXo5N0ZHNi9oZXZSUGlsY3p6OTdGRzYvS1Z3UHZ4K0Zxejk3Rkc2L2hldlJQaWxjeno5N0ZHNi9oZXZSdmlsY3p6OTdGRzYvS1Z3UFB4K0ZxeitGNndIQUtWd1B2eCtGcXorRjZ3SEFoZXZSdmlsY3p6K0Y2d0hBS1Z3UFB4K0ZxeitGNndIQWhldlJ2aWxjenorRjZ3SEFoZXZSUGlsY3p6K0Y2d0hBS1Z3UHZ4K0ZxeitGNndIQUtWd1B2eCtGcXo5N0ZHNi9oZXZSdmlsY3p6OTdGRzYvS1Z3UHZ4K0ZxeitGNndIQWhldlJ2aWxjeno5N0ZHNi9oZXZSdmlsY3p6K0Y2d0hBS1Z3UFB4K0Zxejk3Rkc2L0tWd1BQeCtGcXorRjZ3SEFoZXZSUGlsY3p6K0Y2d0hBS1Z3UFB4K0Zxejk3Rkc2L2hldlJQaWxjenorRjZ3SEFoZXZSUGlsY3p6OTdGRzYvaGV2UnZpbGN6ejk3Rkc2L2hldlJQaWxjeno5N0ZHNi9oZXZSUGlsY3p6K0Y2d0hBaGV2UnZpbGN6ejk3Rkc2L2hldlJQaWxjenorRjZ3SEFoZXZSdmlsY3p6K0Y2d0hBS1Z3UHZ4K0ZxeitGNndIQUtWd1BQeCtGcXorRjZ3SEFLVndQUHgrRnF6OTdGRzYvS1Z3UHZ4K0ZxeitGNndIQUtWd1BQeCtGcXo5N0ZHNi9LVndQdngrRnF6OTdGRzYvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBSUFBQUFBQUFBQ0FQd0FBQUlBQUFBQUFBQUNBUHdBQUFJQUFBQUFBQUFBQWdBQUFnRDhBQUFBQUFBQUFnQUFBZ0Q4QUFBQUFBQUFBZ0FBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvcktoaHZ3SEg4VDRBQUFBQXJLaGh2d0hIOFQ0QUFBQUFyS2hodndISDhUNEFBQUFBcktoaHZ3SEg4VDRBQUFBQXJLaGh2d0hIOFQ0QUFBQUFyS2hodndISDhUNEFBQUFBcktoaFB3SEg4VDRBQUFBQXJLaGhQd0hIOFQ0QUFBQUFyS2hoUHdISDhUNEFBQUFBcktoaFB3SEg4VDRBQUFBQXJLaGhQd0hIOFQ0QUFBQUFyS2hoUHdISDhUNEFBQUFBQUFBQWdBQUFnRDhBQUFBQUFBQUFnQUFBZ0Q4QUFBQUFBQUFBZ0FBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQkFBSUFBd0FFQUFVQUJnQUhBQWdBQ1FBS0FBc0FEQUFOQUE0QUR3QVFBQkVBRWdBVEFCUUFGUUFXQUJjQUdBQVpBQm9BR3dBY0FCMEFIZ0FmQUNBQUlRQWlBQ01BSkFBbEFDWUFKd0FvQUNrQUtnQXJBQ3dBTFFBdUFDOEFNQUF4QURJQU13QTBBRFVBTmdBM0FEZ0FPUUE2QURzQVBBQTlBRDRBUHdCQUFFRUFRZ0JEQUVRQVJRQkdBRWNBemN6TVBacVpXVDhmaFd1L0tWeVBQUUFBeUVBZmhXdS8zN2FHUFFBQXlFQVpaR1cvemN6TVBacVpXVDhmaFd1LzM3YUdQUUFBeUVBWlpHVy85WExBUFpxWldUK293MksvOVhMQVBacVpXVCtvdzJLLzM3YUdQUUFBeUVBWlpHVy82S05iUFFBQXlFQlNBR0MvOVhMQVBacVpXVCtvdzJLLzZLTmJQUUFBeUVCU0FHQy95dUtjUFpxWldUK01FRnUveXVLY1BacVpXVCtNRUZ1LzZLTmJQUUFBeUVCU0FHQy9LVndQUFFBQXlFQTJBRnkveXVLY1BacVpXVCtNRUZ1L0tWd1BQUUFBeUVBMkFGeS96Y3hNUFpxWldUK0pXVlcvemN4TVBacVpXVCtKV1ZXL0tWd1BQUUFBeUVBMkFGeS9WQ2RIUEFBQXlFQkwzMW0vemN4TVBacVpXVCtKV1ZXL1ZDZEhQQUFBeUVCTDMxbS9xa0NPUEpxWldUOFZUMUsvcWtDT1BKcVpXVDhWVDFLL1ZDZEhQQUFBeUVCTDMxbS9WQ2RIdkFBQXlFQkwzMW0vcWtDT1BKcVpXVDhWVDFLL1ZDZEh2QUFBeUVCTDMxbS9xa0NPdkpxWldUOFZUMUsvcWtDT3ZKcVpXVDhWVDFLL1ZDZEh2QUFBeUVCTDMxbS9LVndQdlFBQXlFQTJBRnkvcWtDT3ZKcVpXVDhWVDFLL0tWd1B2UUFBeUVBMkFGeS96Y3hNdlpxWldUK0pXVlcvemN4TXZacVpXVCtKV1ZXL0tWd1B2UUFBeUVBMkFGeS82S05idlFBQXlFQlNBR0MvemN4TXZacVpXVCtKV1ZXLzZLTmJ2UUFBeUVCU0FHQy95dUtjdlpxWldUK01FRnUveXVLY3ZacVpXVCtNRUZ1LzZLTmJ2UUFBeUVCU0FHQy8zN2FHdlFBQXlFQVpaR1cveXVLY3ZacVpXVCtNRUZ1LzM3YUd2UUFBeUVBWlpHVy85WExBdlpxWldUK293MksvOVhMQXZacVpXVCtvdzJLLzM3YUd2UUFBeUVBWlpHVy9LVnlQdlFBQXlFQWZoV3UvOVhMQXZacVpXVCtvdzJLL0tWeVB2UUFBeUVBZmhXdS96Y3pNdlpxWldUOGZoV3UvemN6TXZacVpXVDhmaFd1L0tWeVB2UUFBeUVBZmhXdS8zN2FHdlFBQXlFQWxwbkcvemN6TXZacVpXVDhmaFd1LzM3YUd2UUFBeUVBbHBuRy85WExBdlpxWldUK1ZSblMvOVhMQXZacVpXVCtWUm5TLzM3YUd2UUFBeUVBbHBuRy82S05idlFBQXlFRHNDWGUvOVhMQXZacVpXVCtWUm5TLzZLTmJ2UUFBeUVEc0NYZS95dUtjdlpxWldUK3grWHUveXVLY3ZacVpXVCt4K1h1LzZLTmJ2UUFBeUVEc0NYZS9LVndQdlFBQXlFQUhDbnUveXVLY3ZacVpXVCt4K1h1L0tWd1B2UUFBeUVBSENudS96Y3hNdlpxWldUOWEySUMvemN4TXZacVpXVDlhMklDL0tWd1B2UUFBeUVBSENudS9WQ2RIdkFBQXlFRHlLbjIvemN4TXZacVpXVDlhMklDL1ZDZEh2QUFBeUVEeUtuMi9xa0NPdkpxWldUK1VYWUsvcWtDT3ZKcVpXVCtVWFlLL1ZDZEh2QUFBeUVEeUtuMi9WQ2RIUEFBQXlFRHlLbjIvcWtDT3ZKcVpXVCtVWFlLL1ZDZEhQQUFBeUVEeUtuMi9xa0NPUEpxWldUK1VYWUsvcWtDT1BKcVpXVCtVWFlLL1ZDZEhQQUFBeUVEeUtuMi9LVndQUFFBQXlFQUhDbnUvcWtDT1BKcVpXVCtVWFlLL0tWd1BQUUFBeUVBSENudS96Y3hNUFpxWldUOWEySUMvemN4TVBacVpXVDlhMklDL0tWd1BQUUFBeUVBSENudS82S05iUFFBQXlFRHNDWGUvemN4TVBacVpXVDlhMklDLzZLTmJQUUFBeUVEc0NYZS95dUtjUFpxWldUK3grWHUveXVLY1BacVpXVCt4K1h1LzZLTmJQUUFBeUVEc0NYZS8zN2FHUFFBQXlFQWxwbkcveXVLY1BacVpXVCt4K1h1LzM3YUdQUUFBeUVBbHBuRy85WExBUFpxWldUK1ZSblMvOVhMQVBacVpXVCtWUm5TLzM3YUdQUUFBeUVBbHBuRy9LVnlQUFFBQXlFQWZoV3UvOVhMQVBacVpXVCtWUm5TL0tWeVBQUUFBeUVBZmhXdS96Y3pNUFpxWldUOGZoV3UvMzdhR1BRQUF5RUFscG5HLzZLTmJQUUFBeUVEc0NYZS9LVndQUFFBQXlFQUhDbnUvMzdhR1BRQUF5RUFscG5HL0tWd1BQUUFBeUVBSENudS9WQ2RIUEFBQXlFRHlLbjIvMzdhR1BRQUF5RUFscG5HL1ZDZEhQQUFBeUVEeUtuMi9WQ2RIdkFBQXlFRHlLbjIvMzdhR1BRQUF5RUFscG5HL1ZDZEh2QUFBeUVEeUtuMi9LVndQdlFBQXlFQUhDbnUvMzdhR1BRQUF5RUFscG5HL0tWd1B2UUFBeUVBSENudS82S05idlFBQXlFRHNDWGUvMzdhR1BRQUF5RUFscG5HLzZLTmJ2UUFBeUVEc0NYZS8zN2FHdlFBQXlFQWxwbkcvMzdhR1BRQUF5RUFscG5HLzM3YUd2UUFBeUVBbHBuRy9LVnlQdlFBQXlFQWZoV3UvMzdhR1BRQUF5RUFscG5HL0tWeVB2UUFBeUVBZmhXdS8zN2FHdlFBQXlFQVpaR1cvMzdhR1BRQUF5RUFscG5HLzM3YUd2UUFBeUVBWlpHVy82S05idlFBQXlFQlNBR0MvMzdhR1BRQUF5RUFscG5HLzZLTmJ2UUFBeUVCU0FHQy9LVndQdlFBQXlFQTJBRnkvMzdhR1BRQUF5RUFscG5HL0tWd1B2UUFBeUVBMkFGeS9WQ2RIdkFBQXlFQkwzMW0vMzdhR1BRQUF5RUFscG5HL1ZDZEh2QUFBeUVCTDMxbS9WQ2RIUEFBQXlFQkwzMW0vMzdhR1BRQUF5RUFscG5HL1ZDZEhQQUFBeUVCTDMxbS9LVndQUFFBQXlFQTJBRnkvMzdhR1BRQUF5RUFscG5HL0tWd1BQUUFBeUVBMkFGeS82S05iUFFBQXlFQlNBR0MvMzdhR1BRQUF5RUFscG5HLzZLTmJQUUFBeUVCU0FHQy8zN2FHUFFBQXlFQVpaR1cvMzdhR1BRQUF5RUFscG5HLzM3YUdQUUFBeUVBWlpHVy9LVnlQUFFBQXlFQWZoV3UvemN6TVBacVpXVDhmaFd1LzlYTEFQWnFaV1Qrb3cySy95dUtjUFpxWldUK01FRnUvemN6TVBacVpXVDhmaFd1L3l1S2NQWnFaV1QrTUVGdS96Y3hNUFpxWldUK0pXVlcvemN6TVBacVpXVDhmaFd1L3pjeE1QWnFaV1QrSldWVy9xa0NPUEpxWldUOFZUMUsvemN6TVBacVpXVDhmaFd1L3FrQ09QSnFaV1Q4VlQxSy9xa0NPdkpxWldUOFZUMUsvemN6TVBacVpXVDhmaFd1L3FrQ092SnFaV1Q4VlQxSy96Y3hNdlpxWldUK0pXVlcvemN6TVBacVpXVDhmaFd1L3pjeE12WnFaV1QrSldWVy95dUtjdlpxWldUK01FRnUvemN6TVBacVpXVDhmaFd1L3l1S2N2WnFaV1QrTUVGdS85WExBdlpxWldUK293MksvemN6TVBacVpXVDhmaFd1LzlYTEF2WnFaV1Qrb3cySy96Y3pNdlpxWldUOGZoV3UvemN6TVBacVpXVDhmaFd1L3pjek12WnFaV1Q4ZmhXdS85WExBdlpxWldUK1ZSblMvemN6TVBacVpXVDhmaFd1LzlYTEF2WnFaV1QrVlJuUy95dUtjdlpxWldUK3grWHUvemN6TVBacVpXVDhmaFd1L3l1S2N2WnFaV1QreCtYdS96Y3hNdlpxWldUOWEySUMvemN6TVBacVpXVDhmaFd1L3pjeE12WnFaV1Q5YTJJQy9xa0NPdkpxWldUK1VYWUsvemN6TVBacVpXVDhmaFd1L3FrQ092SnFaV1QrVVhZSy9xa0NPUEpxWldUK1VYWUsvemN6TVBacVpXVDhmaFd1L3FrQ09QSnFaV1QrVVhZSy96Y3hNUFpxWldUOWEySUMvemN6TVBacVpXVDhmaFd1L3pjeE1QWnFaV1Q5YTJJQy95dUtjUFpxWldUK3grWHUvemN6TVBacVpXVDhmaFd1L3l1S2NQWnFaV1QreCtYdS85WExBUFpxWldUK1ZSblMvQUFBQUFJL0NkVDlJNFRyQWo4TDF2T3hSbUVCSTRUckFJRHNIdmV4Um1FQVp5VG5BQUFBQUFJL0NkVDlJNFRyQUlEc0h2ZXhSbUVBWnlUbkFtUmVldTQvQ2RULzlJRG5BbVJlZXU0L0NkVC85SURuQUlEc0h2ZXhSbUVBWnlUbkFTc3NxdmV4Um1FQzEwampBbVJlZXU0L0NkVC85SURuQVNzc3F2ZXhSbUVDMTBqakFPMU9adkkvQ2RUL0VsamZBTzFPWnZJL0NkVC9FbGpmQVNzc3F2ZXhSbUVDMTBqakFya2RodmV4Um1FRFZHempBTzFPWnZJL0NkVC9FbGpmQXJrZGh2ZXhSbUVEVkd6akFDdGNqdlkvQ2RUOHFjamJBQ3RjanZZL0NkVDhxY2piQXJrZGh2ZXhSbUVEVkd6akE5UTZTdmV4Um1FQ0h1amZBQ3RjanZZL0NkVDhxY2piQTlRNlN2ZXhSbUVDSHVqZkF0V09IdlkvQ2RUOTUxalhBdFdPSHZZL0NkVDk1MWpYQTlRNlN2ZXhSbUVDSHVqZkFINSsxdmV4Um1FQ0h1amZBdFdPSHZZL0NkVDk1MWpYQUg1KzF2ZXhSbUVDSHVqZkFYMHJBdlkvQ2RUOTUxalhBWDByQXZZL0NkVDk1MWpYQUg1KzF2ZXhSbUVDSHVqZkFQUXJYdmV4Um1FRFZHempBWDByQXZZL0NkVDk1MWpYQVBRclh2ZXhSbUVEVkd6akFqOEwxdlkvQ2RUOHFjamJBajhMMXZZL0NkVDhxY2piQVBRclh2ZXhSbUVEVkd6akFiMGp5dmV4Um1FQzEwampBajhMMXZZL0NkVDhxY2piQWIwanl2ZXhSbUVDMTBqakFvNndRdm8vQ2RUL0VsamZBbzZ3UXZvL0NkVC9FbGpmQWIwanl2ZXhSbUVDMTBqakFRZ2dDdnV4Um1FQVp5VG5BbzZ3UXZvL0NkVC9FbGpmQVFnZ0N2dXhSbUVBWnlUbkFUZVlldm8vQ2RULzlJRG5BVGVZZXZvL0NkVC85SURuQVFnZ0N2dXhSbUVBWnlUbkF1QjRGdnV4Um1FQkk0VHJBVGVZZXZvL0NkVC85SURuQXVCNEZ2dXhSbUVCSTRUckFDdGNqdm8vQ2RUOUk0VHJBQ3RjanZvL0NkVDlJNFRyQXVCNEZ2dXhSbUVCSTRUckFRZ2dDdnV4Um1FQjMrVHZBQ3RjanZvL0NkVDlJNFRyQVFnZ0N2dXhSbUVCMytUdkFUZVlldm8vQ2RUK1RvVHpBVGVZZXZvL0NkVCtUb1R6QVFnZ0N2dXhSbUVCMytUdkFiMGp5dmV4Um1FRGE3enpBVGVZZXZvL0NkVCtUb1R6QWIwanl2ZXhSbUVEYTd6ekFvNndRdm8vQ2RUL0xLejdBbzZ3UXZvL0NkVC9MS3o3QWIwanl2ZXhSbUVEYTd6ekFQUXJYdmV4Um1FQzZwajNBbzZ3UXZvL0NkVC9MS3o3QVBRclh2ZXhSbUVDNnBqM0FqOEwxdlkvQ2RUOW1VRC9BajhMMXZZL0NkVDltVUQvQVBRclh2ZXhSbUVDNnBqM0FINSsxdmV4Um1FQUpDRDdBajhMMXZZL0NkVDltVUQvQUg1KzF2ZXhSbUVBSkNEN0FYMHJBdlkvQ2RUOFc3RC9BWDByQXZZL0NkVDhXN0QvQUg1KzF2ZXhSbUVBSkNEN0E5UTZTdmV4Um1FQUpDRDdBWDByQXZZL0NkVDhXN0QvQTlRNlN2ZXhSbUVBSkNEN0F0V09IdlkvQ2RUOFc3RC9BdFdPSHZZL0NkVDhXN0QvQTlRNlN2ZXhSbUVBSkNEN0Fya2RodmV4Um1FQzZwajNBdFdPSHZZL0NkVDhXN0QvQXJrZGh2ZXhSbUVDNnBqM0FDdGNqdlkvQ2RUOW1VRC9BQ3RjanZZL0NkVDltVUQvQXJrZGh2ZXhSbUVDNnBqM0FTc3NxdmV4Um1FRGE3enpBQ3RjanZZL0NkVDltVUQvQVNzc3F2ZXhSbUVEYTd6ekFPMU9adkkvQ2RUL0xLejdBTzFPWnZJL0NkVC9MS3o3QVNzc3F2ZXhSbUVEYTd6ekFJRHNIdmV4Um1FQjMrVHZBTzFPWnZJL0NkVC9MS3o3QUlEc0h2ZXhSbUVCMytUdkFtUmVldTQvQ2RUK1RvVHpBbVJlZXU0L0NkVCtUb1R6QUlEc0h2ZXhSbUVCMytUdkFqOEwxdk94Um1FQkk0VHJBbVJlZXU0L0NkVCtUb1R6QWo4TDF2T3hSbUVCSTRUckFBQUFBQUkvQ2RUOUk0VHJBSURzSHZleFJtRUIzK1R2QVNzc3F2ZXhSbUVEYTd6ekFya2RodmV4Um1FQzZwajNBSURzSHZleFJtRUIzK1R2QXJrZGh2ZXhSbUVDNnBqM0E5UTZTdmV4Um1FQUpDRDdBSURzSHZleFJtRUIzK1R2QTlRNlN2ZXhSbUVBSkNEN0FINSsxdmV4Um1FQUpDRDdBSURzSHZleFJtRUIzK1R2QUg1KzF2ZXhSbUVBSkNEN0FQUXJYdmV4Um1FQzZwajNBSURzSHZleFJtRUIzK1R2QVBRclh2ZXhSbUVDNnBqM0FiMGp5dmV4Um1FRGE3enpBSURzSHZleFJtRUIzK1R2QWIwanl2ZXhSbUVEYTd6ekFRZ2dDdnV4Um1FQjMrVHZBSURzSHZleFJtRUIzK1R2QVFnZ0N2dXhSbUVCMytUdkF1QjRGdnV4Um1FQkk0VHJBSURzSHZleFJtRUIzK1R2QXVCNEZ2dXhSbUVCSTRUckFRZ2dDdnV4Um1FQVp5VG5BSURzSHZleFJtRUIzK1R2QVFnZ0N2dXhSbUVBWnlUbkFiMGp5dmV4Um1FQzEwampBSURzSHZleFJtRUIzK1R2QWIwanl2ZXhSbUVDMTBqakFQUXJYdmV4Um1FRFZHempBSURzSHZleFJtRUIzK1R2QVBRclh2ZXhSbUVEVkd6akFINSsxdmV4Um1FQ0h1amZBSURzSHZleFJtRUIzK1R2QUg1KzF2ZXhSbUVDSHVqZkE5UTZTdmV4Um1FQ0h1amZBSURzSHZleFJtRUIzK1R2QTlRNlN2ZXhSbUVDSHVqZkFya2RodmV4Um1FRFZHempBSURzSHZleFJtRUIzK1R2QXJrZGh2ZXhSbUVEVkd6akFTc3NxdmV4Um1FQzEwampBSURzSHZleFJtRUIzK1R2QVNzc3F2ZXhSbUVDMTBqakFJRHNIdmV4Um1FQVp5VG5BSURzSHZleFJtRUIzK1R2QUlEc0h2ZXhSbUVBWnlUbkFqOEwxdk94Um1FQkk0VHJBQUFBQUFJL0NkVDlJNFRyQW1SZWV1NC9DZFQvOUlEbkFPMU9adkkvQ2RUL0VsamZBQUFBQUFJL0NkVDlJNFRyQU8xT1p2SS9DZFQvRWxqZkFDdGNqdlkvQ2RUOHFjamJBQUFBQUFJL0NkVDlJNFRyQUN0Y2p2WS9DZFQ4cWNqYkF0V09IdlkvQ2RUOTUxalhBQUFBQUFJL0NkVDlJNFRyQXRXT0h2WS9DZFQ5NTFqWEFYMHJBdlkvQ2RUOTUxalhBQUFBQUFJL0NkVDlJNFRyQVgwckF2WS9DZFQ5NTFqWEFqOEwxdlkvQ2RUOHFjamJBQUFBQUFJL0NkVDlJNFRyQWo4TDF2WS9DZFQ4cWNqYkFvNndRdm8vQ2RUL0VsamZBQUFBQUFJL0NkVDlJNFRyQW82d1F2by9DZFQvRWxqZkFUZVlldm8vQ2RULzlJRG5BQUFBQUFJL0NkVDlJNFRyQVRlWWV2by9DZFQvOUlEbkFDdGNqdm8vQ2RUOUk0VHJBQUFBQUFJL0NkVDlJNFRyQUN0Y2p2by9DZFQ5STRUckFUZVlldm8vQ2RUK1RvVHpBQUFBQUFJL0NkVDlJNFRyQVRlWWV2by9DZFQrVG9UekFvNndRdm8vQ2RUL0xLejdBQUFBQUFJL0NkVDlJNFRyQW82d1F2by9DZFQvTEt6N0FqOEwxdlkvQ2RUOW1VRC9BQUFBQUFJL0NkVDlJNFRyQWo4TDF2WS9DZFQ5bVVEL0FYMHJBdlkvQ2RUOFc3RC9BQUFBQUFJL0NkVDlJNFRyQVgwckF2WS9DZFQ4VzdEL0F0V09IdlkvQ2RUOFc3RC9BQUFBQUFJL0NkVDlJNFRyQXRXT0h2WS9DZFQ4VzdEL0FDdGNqdlkvQ2RUOW1VRC9BQUFBQUFJL0NkVDlJNFRyQUN0Y2p2WS9DZFQ5bVVEL0FPMU9adkkvQ2RUL0xLejdBQUFBQUFJL0NkVDlJNFRyQU8xT1p2SS9DZFQvTEt6N0FtUmVldTQvQ2RUK1RvVHpBQ3RlanZUTXpVMEN1UjJHL0g0VUxRRE16VTBDdVIyRy9INFVMUU94UldFQ3VSMkcvQ3RlanZUTXpVMEN1UjJHL0g0VUxRT3hSV0VDdVIyRy9DdGVqdmV4UldFQ3VSMkcvSDRVTFFETXpVMEFBQUlDL0N0ZWp2VE16VTBBQUFJQy9DdGVqdmV4UldFQUFBSUMvSDRVTFFETXpVMEFBQUlDL0N0ZWp2ZXhSV0VBQUFJQy9INFVMUU94UldFQUFBSUMvQ3RlanZUTXpVMEFBQUlDL0N0ZWp2VE16VTBDdVIyRy9DdGVqdmV4UldFQ3VSMkcvQ3RlanZUTXpVMEFBQUlDL0N0ZWp2ZXhSV0VDdVIyRy9DdGVqdmV4UldFQUFBSUMvSDRVTFFETXpVMEN1UjJHL0g0VUxRRE16VTBBQUFJQy9INFVMUU94UldFQUFBSUMvSDRVTFFETXpVMEN1UjJHL0g0VUxRT3hSV0VBQUFJQy9INFVMUU94UldFQ3VSMkcvQ3RlanZleFJXRUN1UjJHL0g0VUxRT3hSV0VDdVIyRy9INFVMUU94UldFQUFBSUMvQ3RlanZleFJXRUN1UjJHL0g0VUxRT3hSV0VBQUFJQy9DdGVqdmV4UldFQUFBSUMvQ3RlanZUTXpVMEFBQUlDL0g0VUxRRE16VTBBQUFJQy9INFVMUURNelUwQ3VSMkcvQ3RlanZUTXpVMEFBQUlDL0g0VUxRRE16VTBDdVIyRy9DdGVqdlRNelUwQ3VSMkcvS1Z3UHZwcVpHVUNhbVRuQUN0ZWpQNXFaR1VDYW1UbkFDdGVqUDFLNEhrQ2FtVG5BS1Z3UHZwcVpHVUNhbVRuQUN0ZWpQMUs0SGtDYW1UbkFLVndQdmxLNEhrQ2FtVG5BQ3RlalA1cVpHVUFBQUVEQUtWd1B2cHFaR1VBQUFFREFLVndQdmxLNEhrQUFBRURBQ3RlalA1cVpHVUFBQUVEQUtWd1B2bEs0SGtBQUFFREFDdGVqUDFLNEhrQUFBRURBS1Z3UHZwcVpHVUFBQUVEQUtWd1B2cHFaR1VDYW1UbkFLVndQdmxLNEhrQ2FtVG5BS1Z3UHZwcVpHVUFBQUVEQUtWd1B2bEs0SGtDYW1UbkFLVndQdmxLNEhrQUFBRURBQ3RlalA1cVpHVUNhbVRuQUN0ZWpQNXFaR1VBQUFFREFDdGVqUDFLNEhrQUFBRURBQ3RlalA1cVpHVUNhbVRuQUN0ZWpQMUs0SGtBQUFFREFDdGVqUDFLNEhrQ2FtVG5BS1Z3UHZsSzRIa0NhbVRuQUN0ZWpQMUs0SGtDYW1UbkFDdGVqUDFLNEhrQUFBRURBS1Z3UHZsSzRIa0NhbVRuQUN0ZWpQMUs0SGtBQUFFREFLVndQdmxLNEhrQUFBRURBS1Z3UHZwcVpHVUFBQUVEQUN0ZWpQNXFaR1VBQUFFREFDdGVqUDVxWkdVQ2FtVG5BS1Z3UHZwcVpHVUFBQUVEQUN0ZWpQNXFaR1VDYW1UbkFLVndQdnBxWkdVQ2FtVG5BQ3RjanZZL0N0VCthbWFGQWo4SjFQWS9DdFQrYW1hRkFqOEoxUFFBQXdEK2FtYUZBQ3RjanZZL0N0VCthbWFGQWo4SjFQUUFBd0QrYW1hRkFDdGNqdlFBQXdEK2FtYUZBajhKMVBZL0N0VC9Oekd4QUN0Y2p2WS9DdFQvTnpHeEFDdGNqdlFBQXdEL056R3hBajhKMVBZL0N0VC9Oekd4QUN0Y2p2UUFBd0QvTnpHeEFqOEoxUFFBQXdEL056R3hBQ3RjanZZL0N0VC9Oekd4QUN0Y2p2WS9DdFQrYW1hRkFDdGNqdlFBQXdEK2FtYUZBQ3RjanZZL0N0VC9Oekd4QUN0Y2p2UUFBd0QrYW1hRkFDdGNqdlFBQXdEL056R3hBajhKMVBZL0N0VCthbWFGQWo4SjFQWS9DdFQvTnpHeEFqOEoxUFFBQXdEL056R3hBajhKMVBZL0N0VCthbWFGQWo4SjFQUUFBd0QvTnpHeEFqOEoxUFFBQXdEK2FtYUZBQ3RjanZRQUF3RCthbWFGQWo4SjFQUUFBd0QrYW1hRkFqOEoxUFFBQXdEL056R3hBQ3RjanZRQUF3RCthbWFGQWo4SjFQUUFBd0QvTnpHeEFDdGNqdlFBQXdEL056R3hBQ3RjanZZL0N0VC9Oekd4QWo4SjFQWS9DdFQvTnpHeEFqOEoxUFkvQ3RUK2FtYUZBQ3RjanZZL0N0VC9Oekd4QWo4SjFQWS9DdFQrYW1hRkFDdGNqdlkvQ3RUK2FtYUZBL2Y1L1A2a0t0anNBQUFBQS9mNS9QNmtLdGpzQUFBQUF2NDV3UDZrS3RqdVRISzgrL2Y1L1A2a0t0anNBQUFBQXY0NXdQNmtLdGp1VEhLOCt2NDV3UDZrS3RqdVRISzgrdjQ1d1A2a0t0anVUSEs4K3Y0NXdQNmtLdGp1VEhLOCt0eHBFUDZrS3Rqc1VqU1EvdjQ1d1A2a0t0anVUSEs4K3R4cEVQNmtLdGpzVWpTUS90eHBFUDZrS3Rqc1VqU1EvdHhwRVA2a0t0anNValNRL3R4cEVQNmtLdGpzVWpTUS8vZjcvUHFrS3RqdjNzbDAvdHhwRVA2a0t0anNValNRLy9mNy9QcWtLdGp2M3NsMC8vZjcvUHFrS3RqdjNzbDAvL2Y3L1Bxa0t0anYzc2wwLy9mNy9QcWtLdGp2M3NsMC9JTkF4UHFrS3RqdGRHM3cvL2Y3L1Bxa0t0anYzc2wwL0lOQXhQcWtLdGp0ZEczdy9JTkF4UHFrS3RqdGRHM3cvSU5BeFBxa0t0anRkRzN3L0lOQXhQcWtLdGp0ZEczdy9JTkF4dnFrS3RqdGRHM3cvSU5BeFBxa0t0anRkRzN3L0lOQXh2cWtLdGp0ZEczdy9JTkF4dnFrS3RqdGRHM3cvSU5BeHZxa0t0anRkRzN3L0lOQXh2cWtLdGp0ZEczdy8vZjcvdnFrS3RqdjNzbDAvSU5BeHZxa0t0anRkRzN3Ly9mNy92cWtLdGp2M3NsMC8vZjcvdnFrS3RqdjNzbDAvL2Y3L3Zxa0t0anYzc2wwLy9mNy92cWtLdGp2M3NsMC90eHBFdjZrS3Rqc1VqU1EvL2Y3L3Zxa0t0anYzc2wwL3R4cEV2NmtLdGpzVWpTUS90eHBFdjZrS3Rqc1VqU1EvdHhwRXY2a0t0anNValNRL3R4cEV2NmtLdGpzVWpTUS92NDV3djZrS3RqdVRISzgrdHhwRXY2a0t0anNValNRL3Y0NXd2NmtLdGp1VEhLOCt2NDV3djZrS3RqdVRISzgrdjQ1d3Y2a0t0anVUSEs4K3Y0NXd2NmtLdGp1VEhLOCsvZjUvdjZrS3RqdWpNQTBsdjQ1d3Y2a0t0anVUSEs4Ky9mNS92NmtLdGp1ak1BMGwvZjUvdjZrS3RqdWpNQTBsL2Y1L3Y2a0t0anVqTUEwbC9mNS92NmtLdGp1ak1BMGx2NDV3djZrS3RqdVRISysrL2Y1L3Y2a0t0anVqTUEwbHY0NXd2NmtLdGp1VEhLKyt2NDV3djZrS3RqdVRISysrdjQ1d3Y2a0t0anVUSEsrK3Y0NXd2NmtLdGp1VEhLKyt0eHBFdjZrS3Rqc1VqU1MvdjQ1d3Y2a0t0anVUSEsrK3R4cEV2NmtLdGpzVWpTUy90eHBFdjZrS3Rqc1VqU1MvdHhwRXY2a0t0anNValNTL3R4cEV2NmtLdGpzVWpTUy8vZjcvdnFrS3RqdjNzbDIvdHhwRXY2a0t0anNValNTLy9mNy92cWtLdGp2M3NsMi8vZjcvdnFrS3RqdjNzbDIvL2Y3L3Zxa0t0anYzc2wyLy9mNy92cWtLdGp2M3NsMi9JTkF4dnFrS3RqdGRHM3kvL2Y3L3Zxa0t0anYzc2wyL0lOQXh2cWtLdGp0ZEczeS9JTkF4dnFrS3RqdGRHM3kvSU5BeHZxa0t0anRkRzN5L0lOQXh2cWtLdGp0ZEczeS9JTkF4UHFrS3RqdGRHM3kvSU5BeHZxa0t0anRkRzN5L0lOQXhQcWtLdGp0ZEczeS9JTkF4UHFrS3RqdGRHM3kvSU5BeFBxa0t0anRkRzN5L0lOQXhQcWtLdGp0ZEczeS8vZjcvUHFrS3RqdjNzbDIvSU5BeFBxa0t0anRkRzN5Ly9mNy9QcWtLdGp2M3NsMi8vZjcvUHFrS3RqdjNzbDIvL2Y3L1Bxa0t0anYzc2wyLy9mNy9QcWtLdGp2M3NsMi90eHBFUDZrS3Rqc1VqU1MvL2Y3L1Bxa0t0anYzc2wyL3R4cEVQNmtLdGpzVWpTUy90eHBFUDZrS3Rqc1VqU1MvdHhwRVA2a0t0anNValNTL3R4cEVQNmtLdGpzVWpTUy92NDV3UDZrS3RqdVRISysrdHhwRVA2a0t0anNValNTL3Y0NXdQNmtLdGp1VEhLKyt2NDV3UDZrS3RqdVRISysrdjQ1d1A2a0t0anVUSEsrK3Y0NXdQNmtLdGp1VEhLKysvZjUvUDZrS3Rqc0FBQUFBdjQ1d1A2a0t0anVUSEsrKy9mNS9QNmtLdGpzQUFBQUEvZjUvUDZrS3Rqc0FBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFDQUFBQUFBQUFBZ0Q4QUFBQ0FBQUFBQUFBQWdEOEFBQUNBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQWdBQUFnTDhBQUFBQUFBQUFnQUFBZ0w4QUFBQUFBQUFBZ0FBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBOWYxL1ArVlhBVHdBQUFBQTlmMS9QK1ZYQVR3QUFBQUF4NDF3UCtWWEFUemVHNjgrOWYxL1ArVlhBVHdBQUFBQXg0MXdQK1ZYQVR6ZUc2OCt4NDF3UCtWWEFUemVHNjgreDQxd1ArVlhBVHplRzY4K3g0MXdQK1ZYQVR6ZUc2OCs3UmxFUCtWWEFUeHJqQ1EveDQxd1ArVlhBVHplRzY4KzdSbEVQK1ZYQVR4cmpDUS83UmxFUCtWWEFUeHJqQ1EvN1JsRVArVlhBVHhyakNRLzdSbEVQK1ZYQVR4cmpDUS85ZjMvUHVWWEFUd1NzbDAvN1JsRVArVlhBVHhyakNRLzlmMy9QdVZYQVR3U3NsMC85ZjMvUHVWWEFUd1NzbDAvOWYzL1B1VlhBVHdTc2wwLzlmMy9QdVZYQVR3U3NsMC9hYzh4UHVWWEFUeGFHbncvOWYzL1B1VlhBVHdTc2wwL2FjOHhQdVZYQVR4YUdudy9hYzh4UHVWWEFUeGFHbncvYWM4eFB1VlhBVHhhR253L2FjOHhQdVZYQVR4YUdudy9hYzh4dnVWWEFUeGFHbncvYWM4eFB1VlhBVHhhR253L2FjOHh2dVZYQVR4YUdudy9hYzh4dnVWWEFUeGFHbncvYWM4eHZ1VlhBVHhhR253L2FjOHh2dVZYQVR4YUdudy85ZjMvdnVWWEFUd1NzbDAvYWM4eHZ1VlhBVHhhR253LzlmMy92dVZYQVR3U3NsMC85ZjMvdnVWWEFUd1NzbDAvOWYzL3Z1VlhBVHdTc2wwLzlmMy92dVZYQVR3U3NsMC83UmxFditWWEFUeHJqQ1EvOWYzL3Z1VlhBVHdTc2wwLzdSbEV2K1ZYQVR4cmpDUS83UmxFditWWEFUeHJqQ1EvN1JsRXYrVlhBVHhyakNRLzdSbEV2K1ZYQVR4cmpDUS94NDF3ditWWEFUemVHNjgrN1JsRXYrVlhBVHhyakNRL3g0MXd2K1ZYQVR6ZUc2OCt4NDF3ditWWEFUemVHNjgreDQxd3YrVlhBVHplRzY4K3g0MXd2K1ZYQVR6ZUc2OCs5ZjEvditWWEFUd1JNQTBseDQxd3YrVlhBVHplRzY4KzlmMS92K1ZYQVR3Uk1BMGw5ZjEvditWWEFUd1JNQTBsOWYxL3YrVlhBVHdSTUEwbDlmMS92K1ZYQVR3Uk1BMGx4NDF3ditWWEFUemVHNisrOWYxL3YrVlhBVHdSTUEwbHg0MXd2K1ZYQVR6ZUc2Kyt4NDF3ditWWEFUemVHNisreDQxd3YrVlhBVHplRzYrK3g0MXd2K1ZYQVR6ZUc2Kys3UmxFditWWEFUeHJqQ1MveDQxd3YrVlhBVHplRzYrKzdSbEV2K1ZYQVR4cmpDUy83UmxFditWWEFUeHJqQ1MvN1JsRXYrVlhBVHhyakNTLzdSbEV2K1ZYQVR4cmpDUy85ZjMvdnVWWEFUd1NzbDIvN1JsRXYrVlhBVHhyakNTLzlmMy92dVZYQVR3U3NsMi85ZjMvdnVWWEFUd1NzbDIvOWYzL3Z1VlhBVHdTc2wyLzlmMy92dVZYQVR3U3NsMi9hYzh4dnVWWEFUeGFHbnkvOWYzL3Z1VlhBVHdTc2wyL2FjOHh2dVZYQVR4YUdueS9hYzh4dnVWWEFUeGFHbnkvYWM4eHZ1VlhBVHhhR255L2FjOHh2dVZYQVR4YUdueS9hYzh4UHVWWEFUeGFHbnkvYWM4eHZ1VlhBVHhhR255L2FjOHhQdVZYQVR4YUdueS9hYzh4UHVWWEFUeGFHbnkvYWM4eFB1VlhBVHhhR255L2FjOHhQdVZYQVR4YUdueS85ZjMvUHVWWEFUd1NzbDIvYWM4eFB1VlhBVHhhR255LzlmMy9QdVZYQVR3U3NsMi85ZjMvUHVWWEFUd1NzbDIvOWYzL1B1VlhBVHdTc2wyLzlmMy9QdVZYQVR3U3NsMi83UmxFUCtWWEFUeHJqQ1MvOWYzL1B1VlhBVHdTc2wyLzdSbEVQK1ZYQVR4cmpDUy83UmxFUCtWWEFUeHJqQ1MvN1JsRVArVlhBVHhyakNTLzdSbEVQK1ZYQVR4cmpDUy94NDF3UCtWWEFUemVHNisrN1JsRVArVlhBVHhyakNTL3g0MXdQK1ZYQVR6ZUc2Kyt4NDF3UCtWWEFUemVHNisreDQxd1ArVlhBVHplRzYrK3g0MXdQK1ZYQVR6ZUc2Kys5ZjEvUCtWWEFUd0FBQUFBeDQxd1ArVlhBVHplRzYrKzlmMS9QK1ZYQVR3QUFBQUE5ZjEvUCtWWEFUd0FBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFDQUFBQUFBQUFBZ0Q4QUFBQ0FBQUFBQUFBQWdEOEFBQUNBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQWdBQUFnTDhBQUFBQUFBQUFnQUFBZ0w4QUFBQUFBQUFBZ0FBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBSUFBQUFBQUFBQ0FQd0FBQUlBQUFBQUFBQUNBUHdBQUFJQUFBQUFBQUFBQWdBQUFnRDhBQUFBQUFBQUFnQUFBZ0Q4QUFBQUFBQUFBZ0FBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBSUFBQUFBQUFBQ0FQd0FBQUlBQUFBQUFBQUNBUHdBQUFJQUFBQUFBQUFBQWdBQUFnRDhBQUFBQUFBQUFnQUFBZ0Q4QUFBQUFBQUFBZ0FBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBSUFBQUFBQUFBQ0FQd0FBQUlBQUFBQUFBQUNBUHdBQUFJQUFBQUFBQUFBQWdBQUFnRDhBQUFBQUFBQUFnQUFBZ0Q4QUFBQUFBQUFBZ0FBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQkFBSUFBd0FFQUFVQUJnQUhBQWdBQ1FBS0FBc0FEQUFOQUE0QUR3QVFBQkVBRWdBVEFCUUFGUUFXQUJjQUdBQVpBQm9BR3dBY0FCMEFIZ0FmQUNBQUlRQWlBQ01BSkFBbEFDWUFKd0FvQUNrQUtnQXJBQ3dBTFFBdUFDOEFNQUF4QURJQU13QTBBRFVBTmdBM0FEZ0FPUUE2QURzQVBBQTlBRDRBUHdCQUFFRUFRZ0JEQUVRQVJRQkdBRWNBU0FCSkFFb0FTd0JNQUUwQVRnQlBBRkFBVVFCU0FGTUFWQUJWQUZZQVZ3QllBRmtBV2dCYkFGd0FYUUJlQUY4QVlBQmhBR0lBWXdCa0FHVUFaZ0JuQUdnQWFRQnFBR3NBYkFCdEFHNEFid0J3QUhFQWNnQnpBSFFBZFFCMkFIY0FlQUI1QUhvQWV3QjhBSDBBZmdCL0FJQUFnUUNDQUlNQWhBQ0ZBSVlBaHdDSUFJa0FpZ0NMQUl3QWpRQ09BSThBa0FDUkFKSUFrd0NVQUpVQWxnQ1hBSmdBbVFDYUFKc0FuQUNkQUo0QW53Q2dBS0VBb2dDakFLUUFwUUNtQUtjQXFBQ3BBS29BcXdDc0FLMEFyZ0N2QUxBQXNRQ3lBTE1BdEFDMUFMWUF0d0M0QUxrQXVnQzdBTHdBdlFDK0FMOEF3QURCQU1JQXd3REVBTVVBeGdESEFNZ0F5UURLQU1zQXpBRE5BTTRBendEUUFORUEwZ0RUQU5RQTFRRFdBTmNBMkFEWkFOb0Eyd0RjQU4wQTNnRGZBT0FBNFFEaUFPTUE1QURsQU9ZQTV3RG9BT2tBNmdEckFPd0E3UUR1QU84QThBRHhBUElBOHdEMEFQVUE5Z0QzQVBnQStRRDZBUHNBL0FEOUFQNEEvd0FBQVFFQkFnRURBUVFCQlFFR0FRY0JDQUVKQVFvQkN3RU1BUTBCRGdFUEFSQUJFUUVTQVJNQkZBRVZBUllCRndFWUFSa0JHZ0ViQVJ3QkhRRWVBUjhCSUFFaEFTSUJJd0VrQVNVQkpnRW5BU2dCS1FFcUFTc0JMQUV0QVM0Qkx3RXdBVEVCTWdFekFUUUJOUUUyQVRjQk9BRTVBVG9CT3dFOEFUMEJQZ0UvQVVBQlFRRkNBVU1CUkFGRkFVWUJSd0ZJQVVrQlNnRkxBVXdCVFFGT0FVOEJVQUZSQVZJQlV3RlVBVlVCVmdGWEFWZ0JXUUZhQVZzQlhBRmRBVjRCWHdGZ0FXRUJZZ0ZqQVdRQlpRRm1BV2NCYUFGcEFXb0Jhd0ZzQVcwQmJnRnZBWEFCY1FGeUFYTUJkQUYxQVhZQmR3RjRBWGtCZWdGN0FYd0JmUUYrQVg4QmdBR0JBWUlCZ3dHRUFZVUJoZ0dIQVlnQmlRR0tBWXNCakFHTkFZNEJqd0dRQVpFQmtnR1RBWlFCbFFHV0FaY0JtQUdaQVpvQm13R2NBWjBCbmdHZkFhQUJvUUdpQWFNQnBBR2xBYVlCcHdHb0Fha0JxZ0dyQWF3QnJRR3VBYThCc0FHeEFiSUJzd0cwQWJVQnRnRzNBYmdCdVFHNkFic0J2QUc5QWI0QnZ3SEFBY0VCd2dIREFjUUJ4UUhHQWNjQnlBSEpBY29CeXdITUFjMEJ6Z0hQQWRBQjBRSFNBZE1CMUFIVkFkWUIxd0hZQWRrQjJnSGJBZHdCM1FIZUFkOEI0QUhoQWVJQjR3SGtBZVVCNWdIbkFlZ0I2UUhxQWVzQjdBSHRBZTRCN3dId0FmRUI4Z0h6QWZRQjlRSDJBZmNCK0FINUFmb0Ird0g4QWYwQi9nSC9BUUFDQVFJQ0FnTUNDdGVqUFhFOW1rQWZoV3UvZXhUdVAwamhXa0E5Q2xlL3VCN0ZQeWxjenora2NEMi9DdGVqUFhFOW1rQWZoV3UvdUI3RlB5bGN6eitrY0QyL0N0ZWpQTGdlQlVEMktGeS96Y3hNdlQwS2QwQ2tjRDNBTXpPVFA2UndIVUE5Q2pmQWo4SjFQeWxjanorRjZ6SEF6Y3hNdlQwS2QwQ2tjRDNBajhKMVB5bGNqeitGNnpIQUN0ZWp2UlN1eHo5STRUckExMWFQT3JyL1k3MWFtbisvMTFhUE9yci9ZNzFhbW4rLzExYVBPcnIvWTcxYW1uKy8rYmVTUFZxNnY3eWNSWCsvK2JlU1BWcTZ2N3ljUlgrLytiZVNQVnE2djd5Y1JYKy9tdmMvUE1IZGVyMTJnSCsvbXZjL1BNSGRlcjEyZ0grL212Yy9QTUhkZXIxMmdIKy9TNHdBUGdtN21yekY3WDIvUzR3QVBnbTdtcnpGN1gyL1M0d0FQZ203bXJ6RjdYMi9BQUFCQUFJQUF3QUVBQVVBQmdBSEFBZ0FDUUFLQUFzQWo4SjF2eFN1Unovc1ViZy9qOEoxUHhTdVJ6L3NVYmcvajhKMVA2NUhZVC9zVWJnL2o4SjF2eFN1Unovc1ViZy9qOEoxUDY1SFlUL3NVYmcvajhKMXY2NUhZVC9zVWJnL2o4SjFQeFN1UnordVI2RS9qOEoxdnhTdVJ6K3VSNkUvajhKMXY2NUhZVCt1UjZFL2o4SjFQeFN1UnordVI2RS9qOEoxdjY1SFlUK3VSNkUvajhKMVA2NUhZVCt1UjZFL2o4SjF2eFN1UnordVI2RS9qOEoxdnhTdVJ6L3NVYmcvajhKMXY2NUhZVC9zVWJnL2o4SjF2eFN1UnordVI2RS9qOEoxdjY1SFlUL3NVYmcvajhKMXY2NUhZVCt1UjZFL2o4SjFQeFN1Unovc1ViZy9qOEoxUHhTdVJ6K3VSNkUvajhKMVA2NUhZVCt1UjZFL2o4SjFQeFN1Unovc1ViZy9qOEoxUDY1SFlUK3VSNkUvajhKMVA2NUhZVC9zVWJnL2o4SjF2NjVIWVQvc1ViZy9qOEoxUDY1SFlUL3NVYmcvajhKMVA2NUhZVCt1UjZFL2o4SjF2NjVIWVQvc1ViZy9qOEoxUDY1SFlUK3VSNkUvajhKMXY2NUhZVCt1UjZFL2o4SjF2eFN1UnordVI2RS9qOEoxUHhTdVJ6K3VSNkUvajhKMVB4U3VSei9zVWJnL2o4SjF2eFN1UnordVI2RS9qOEoxUHhTdVJ6L3NVYmcvajhKMXZ4U3VSei9zVWJnL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQS9BQUFBQUFBQUFBQUFBSUEvQUFBQUFBQUFBQUFBQUlBL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQUFBQUFBQUFBQUFJQy9BQUFBQUFBQUFBQUFBSUMvQUFBQUFBQUFBQUFBQUlDL0FBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQXZ3QUFBQUFBQUFBQUFBQ0F2d0FBQUFBQUFBQUFBQUNBdndBQUFBQUFBQUFBQUFDQXZ3QUFBQUFBQUFBQUFBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQ0FQd0FBQUlBQUFBQUFBQUNBUHdBQUFJQUFBQUFBQUFDQVB3QUFBSUFBQUFBQUFBQUFnQUFBZ0Q4QUFBQUFBQUFBZ0FBQWdEOEFBQUFBQUFBQWdBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUJBQUlBQXdBRUFBVUFCZ0FIQUFnQUNRQUtBQXNBREFBTkFBNEFEd0FRQUJFQUVnQVRBQlFBRlFBV0FCY0FHQUFaQUJvQUd3QWNBQjBBSGdBZkFDQUFJUUFpQUNNQXpjeE1QeWxjanorUHduVS96Y3hNUDNzVXJqK1B3blUvdGoxTFAzc1Vyai9zbUgwL3pjeE1QeWxjanorUHduVS90ajFMUDNzVXJqL3NtSDAvdGoxTFB5bGNqei9zbUgwL3RqMUxQeWxjanovc21IMC90ajFMUDNzVXJqL3NtSDAvTXMxR1Azc1Vyai9ySG9JL3RqMUxQeWxjanovc21IMC9NczFHUDNzVXJqL3JIb0kvTXMxR1B5bGNqei9ySG9JL01zMUdQeWxjanovckhvSS9NczFHUDNzVXJqL3JIb0kvU1NoQVAzc1Vyajh0VjRRL01zMUdQeWxjanovckhvSS9TU2hBUDNzVXJqOHRWNFEvU1NoQVB5bGNqejh0VjRRL1NTaEFQeWxjano4dFY0US9TU2hBUDNzVXJqOHRWNFEvN0ZFNFAzc1Vyais0SG9VL1NTaEFQeWxjano4dFY0US83RkU0UDNzVXJqKzRIb1UvN0ZFNFB5bGNqeis0SG9VLzdGRTRQeWxjanorNEhvVS83RkU0UDNzVXJqKzRIb1UvajNzd1Azc1Vyajh0VjRRLzdGRTRQeWxjanorNEhvVS9qM3N3UDNzVXJqOHRWNFEvajNzd1B5bGNqejh0VjRRL2ozc3dQeWxjano4dFY0US9qM3N3UDNzVXJqOHRWNFEvcGRZcFAzc1Vyai9ySG9JL2ozc3dQeWxjano4dFY0US9wZFlwUDNzVXJqL3JIb0kvcGRZcFB5bGNqei9ySG9JL3BkWXBQeWxjanovckhvSS9wZFlwUDNzVXJqL3JIb0kvSVdZbFAzc1Vyai9zbUgwL3BkWXBQeWxjanovckhvSS9JV1lsUDNzVXJqL3NtSDAvSVdZbFB5bGNqei9zbUgwL0lXWWxQeWxjanovc21IMC9JV1lsUDNzVXJqL3NtSDAvQ3RjalAzc1VyaitQd25VL0lXWWxQeWxjanovc21IMC9DdGNqUDNzVXJqK1B3blUvQ3RjalB5bGNqeitQd25VL0N0Y2pQeWxjanorUHduVS9DdGNqUDNzVXJqK1B3blUvSVdZbFAzc1Vyajh5N0cwL0N0Y2pQeWxjanorUHduVS9JV1lsUDNzVXJqOHk3RzAvSVdZbFB5bGNqejh5N0cwL0lXWWxQeWxjano4eTdHMC9JV1lsUDNzVXJqOHk3RzAvcGRZcFAzc1VyajlKUjJjL0lXWWxQeWxjano4eTdHMC9wZFlwUDNzVXJqOUpSMmMvcGRZcFB5bGNqejlKUjJjL3BkWXBQeWxjano5SlIyYy9wZFlwUDNzVXJqOUpSMmMvajNzd1Azc1Vyai9GMW1JL3BkWXBQeWxjano5SlIyYy9qM3N3UDNzVXJqL0YxbUkvajNzd1B5bGNqei9GMW1JL2ozc3dQeWxjanovRjFtSS9qM3N3UDNzVXJqL0YxbUkvN0ZFNFAzc1Vyait1UjJFL2ozc3dQeWxjanovRjFtSS83RkU0UDNzVXJqK3VSMkUvN0ZFNFB5bGNqeit1UjJFLzdGRTRQeWxjanordVIyRS83RkU0UDNzVXJqK3VSMkUvU1NoQVAzc1Vyai9GMW1JLzdGRTRQeWxjanordVIyRS9TU2hBUDNzVXJqL0YxbUkvU1NoQVB5bGNqei9GMW1JL1NTaEFQeWxjanovRjFtSS9TU2hBUDNzVXJqL0YxbUkvTXMxR1Azc1VyajlKUjJjL1NTaEFQeWxjanovRjFtSS9NczFHUDNzVXJqOUpSMmMvTXMxR1B5bGNqejlKUjJjL01zMUdQeWxjano5SlIyYy9NczFHUDNzVXJqOUpSMmMvdGoxTFAzc1Vyajh5N0cwL01zMUdQeWxjano5SlIyYy90ajFMUDNzVXJqOHk3RzAvdGoxTFB5bGNqejh5N0cwL3RqMUxQeWxjano4eTdHMC90ajFMUDNzVXJqOHk3RzAvemN4TVAzc1VyaitQd25VL3RqMUxQeWxjano4eTdHMC96Y3hNUDNzVXJqK1B3blUvemN4TVB5bGNqeitQd25VL3RqMUxQM3NVcmo4eTdHMC9NczFHUDNzVXJqOUpSMmMvU1NoQVAzc1Vyai9GMW1JL3RqMUxQM3NVcmo4eTdHMC9TU2hBUDNzVXJqL0YxbUkvN0ZFNFAzc1Vyait1UjJFL3RqMUxQM3NVcmo4eTdHMC83RkU0UDNzVXJqK3VSMkUvajNzd1Azc1Vyai9GMW1JL3RqMUxQM3NVcmo4eTdHMC9qM3N3UDNzVXJqL0YxbUkvcGRZcFAzc1VyajlKUjJjL3RqMUxQM3NVcmo4eTdHMC9wZFlwUDNzVXJqOUpSMmMvSVdZbFAzc1Vyajh5N0cwL3RqMUxQM3NVcmo4eTdHMC9JV1lsUDNzVXJqOHk3RzAvQ3RjalAzc1VyaitQd25VL3RqMUxQM3NVcmo4eTdHMC9DdGNqUDNzVXJqK1B3blUvSVdZbFAzc1Vyai9zbUgwL3RqMUxQM3NVcmo4eTdHMC9JV1lsUDNzVXJqL3NtSDAvcGRZcFAzc1Vyai9ySG9JL3RqMUxQM3NVcmo4eTdHMC9wZFlwUDNzVXJqL3JIb0kvajNzd1Azc1Vyajh0VjRRL3RqMUxQM3NVcmo4eTdHMC9qM3N3UDNzVXJqOHRWNFEvN0ZFNFAzc1Vyais0SG9VL3RqMUxQM3NVcmo4eTdHMC83RkU0UDNzVXJqKzRIb1UvU1NoQVAzc1Vyajh0VjRRL3RqMUxQM3NVcmo4eTdHMC9TU2hBUDNzVXJqOHRWNFEvTXMxR1Azc1Vyai9ySG9JL3RqMUxQM3NVcmo4eTdHMC9NczFHUDNzVXJqL3JIb0kvdGoxTFAzc1Vyai9zbUgwL3RqMUxQM3NVcmo4eTdHMC90ajFMUDNzVXJqL3NtSDAvemN4TVAzc1VyaitQd25VL3pjeE1QeWxjanorUHduVS90ajFMUHlsY2p6L3NtSDAvTXMxR1B5bGNqei9ySG9JL3pjeE1QeWxjanorUHduVS9NczFHUHlsY2p6L3JIb0kvU1NoQVB5bGNqejh0VjRRL3pjeE1QeWxjanorUHduVS9TU2hBUHlsY2p6OHRWNFEvN0ZFNFB5bGNqeis0SG9VL3pjeE1QeWxjanorUHduVS83RkU0UHlsY2p6KzRIb1UvajNzd1B5bGNqejh0VjRRL3pjeE1QeWxjanorUHduVS9qM3N3UHlsY2p6OHRWNFEvcGRZcFB5bGNqei9ySG9JL3pjeE1QeWxjanorUHduVS9wZFlwUHlsY2p6L3JIb0kvSVdZbFB5bGNqei9zbUgwL3pjeE1QeWxjanorUHduVS9JV1lsUHlsY2p6L3NtSDAvQ3RjalB5bGNqeitQd25VL3pjeE1QeWxjanorUHduVS9DdGNqUHlsY2p6K1B3blUvSVdZbFB5bGNqejh5N0cwL3pjeE1QeWxjanorUHduVS9JV1lsUHlsY2p6OHk3RzAvcGRZcFB5bGNqejlKUjJjL3pjeE1QeWxjanorUHduVS9wZFlwUHlsY2p6OUpSMmMvajNzd1B5bGNqei9GMW1JL3pjeE1QeWxjanorUHduVS9qM3N3UHlsY2p6L0YxbUkvN0ZFNFB5bGNqeit1UjJFL3pjeE1QeWxjanorUHduVS83RkU0UHlsY2p6K3VSMkUvU1NoQVB5bGNqei9GMW1JL3pjeE1QeWxjanorUHduVS9TU2hBUHlsY2p6L0YxbUkvTXMxR1B5bGNqejlKUjJjL3pjeE1QeWxjanorUHduVS9NczFHUHlsY2p6OUpSMmMvdGoxTFB5bGNqejh5N0cwL0N0Y2p2eFN1aHorNEhzVy9DdGNqdjJabXBqKzRIc1cvSVdZbHYyWm1waitLTThHL0N0Y2p2eFN1aHorNEhzVy9JV1lsdjJabXBqK0tNOEcvSVdZbHZ4U3VoeitLTThHL0lXWWx2eFN1aHorS004Ry9JV1lsdjJabXBqK0tNOEcvcGRZcHYyWm1wajhWNGIyL0lXWWx2eFN1aHorS004Ry9wZFlwdjJabXBqOFY0YjIvcGRZcHZ4U3VoejhWNGIyL3BkWXB2eFN1aHo4VjRiMi9wZFlwdjJabXBqOFY0YjIvajNzd3YyWm1wai9UcUx1L3BkWXB2eFN1aHo4VjRiMi9qM3N3djJabXBqL1RxTHUvajNzd3Z4U3Voei9UcUx1L2ozc3d2eFN1aHovVHFMdS9qM3N3djJabXBqL1RxTHUvN0ZFNHYyWm1wajlJNGJxL2ozc3d2eFN1aHovVHFMdS83RkU0djJabXBqOUk0YnEvN0ZFNHZ4U3VoejlJNGJxLzdGRTR2eFN1aHo5STRicS83RkU0djJabXBqOUk0YnEvU1NoQXYyWm1wai9UcUx1LzdGRTR2eFN1aHo5STRicS9TU2hBdjJabXBqL1RxTHUvU1NoQXZ4U3Voei9UcUx1L1NTaEF2eFN1aHovVHFMdS9TU2hBdjJabXBqL1RxTHUvTXMxR3YyWm1wajhWNGIyL1NTaEF2eFN1aHovVHFMdS9NczFHdjJabXBqOFY0YjIvTXMxR3Z4U3VoejhWNGIyL01zMUd2eFN1aHo4VjRiMi9NczFHdjJabXBqOFY0YjIvdGoxTHYyWm1waitLTThHL01zMUd2eFN1aHo4VjRiMi90ajFMdjJabXBqK0tNOEcvdGoxTHZ4U3VoeitLTThHL3RqMUx2eFN1aHorS004Ry90ajFMdjJabXBqK0tNOEcvemN4TXYyWm1wais0SHNXL3RqMUx2eFN1aHorS004Ry96Y3hNdjJabXBqKzRIc1cvemN4TXZ4U3Voeis0SHNXL3pjeE12eFN1aHorNEhzVy96Y3hNdjJabXBqKzRIc1cvdGoxTHYyWm1wai9uQ2NtL3pjeE12eFN1aHorNEhzVy90ajFMdjJabXBqL25DY20vdGoxTHZ4U3Voei9uQ2NtL3RqMUx2eFN1aHovbkNjbS90ajFMdjJabXBqL25DY20vTXMxR3YyWm1wajljWE15L3RqMUx2eFN1aHovbkNjbS9NczFHdjJabXBqOWNYTXkvTXMxR3Z4U3VoejljWE15L01zMUd2eFN1aHo5Y1hNeS9NczFHdjJabXBqOWNYTXkvU1NoQXYyWm1waitkbE02L01zMUd2eFN1aHo5Y1hNeS9TU2hBdjJabXBqK2RsTTYvU1NoQXZ4U3VoeitkbE02L1NTaEF2eFN1aHorZGxNNi9TU2hBdjJabXBqK2RsTTYvN0ZFNHYyWm1wajhwWE0rL1NTaEF2eFN1aHorZGxNNi83RkU0djJabXBqOHBYTSsvN0ZFNHZ4U3VoejhwWE0rLzdGRTR2eFN1aHo4cFhNKy83RkU0djJabXBqOHBYTSsvajNzd3YyWm1waitkbE02LzdGRTR2eFN1aHo4cFhNKy9qM3N3djJabXBqK2RsTTYvajNzd3Z4U3VoeitkbE02L2ozc3d2eFN1aHorZGxNNi9qM3N3djJabXBqK2RsTTYvcGRZcHYyWm1wajljWE15L2ozc3d2eFN1aHorZGxNNi9wZFlwdjJabXBqOWNYTXkvcGRZcHZ4U3VoejljWE15L3BkWXB2eFN1aHo5Y1hNeS9wZFlwdjJabXBqOWNYTXkvSVdZbHYyWm1wai9uQ2NtL3BkWXB2eFN1aHo5Y1hNeS9JV1lsdjJabXBqL25DY20vSVdZbHZ4U3Voei9uQ2NtL0lXWWx2eFN1aHovbkNjbS9JV1lsdjJabXBqL25DY20vQ3RjanYyWm1wais0SHNXL0lXWWx2eFN1aHovbkNjbS9DdGNqdjJabXBqKzRIc1cvQ3RjanZ4U3Voeis0SHNXL0lXWWx2MlptcGovbkNjbS9wZFlwdjJabXBqOWNYTXkvajNzd3YyWm1waitkbE02L0lXWWx2MlptcGovbkNjbS9qM3N3djJabXBqK2RsTTYvN0ZFNHYyWm1wajhwWE0rL0lXWWx2MlptcGovbkNjbS83RkU0djJabXBqOHBYTSsvU1NoQXYyWm1waitkbE02L0lXWWx2MlptcGovbkNjbS9TU2hBdjJabXBqK2RsTTYvTXMxR3YyWm1wajljWE15L0lXWWx2MlptcGovbkNjbS9NczFHdjJabXBqOWNYTXkvdGoxTHYyWm1wai9uQ2NtL0lXWWx2MlptcGovbkNjbS90ajFMdjJabXBqL25DY20vemN4TXYyWm1wais0SHNXL0lXWWx2MlptcGovbkNjbS96Y3hNdjJabXBqKzRIc1cvdGoxTHYyWm1waitLTThHL0lXWWx2MlptcGovbkNjbS90ajFMdjJabXBqK0tNOEcvTXMxR3YyWm1wajhWNGIyL0lXWWx2MlptcGovbkNjbS9NczFHdjJabXBqOFY0YjIvU1NoQXYyWm1wai9UcUx1L0lXWWx2MlptcGovbkNjbS9TU2hBdjJabXBqL1RxTHUvN0ZFNHYyWm1wajlJNGJxL0lXWWx2MlptcGovbkNjbS83RkU0djJabXBqOUk0YnEvajNzd3YyWm1wai9UcUx1L0lXWWx2MlptcGovbkNjbS9qM3N3djJabXBqL1RxTHUvcGRZcHYyWm1wajhWNGIyL0lXWWx2MlptcGovbkNjbS9wZFlwdjJabXBqOFY0YjIvSVdZbHYyWm1waitLTThHL0lXWWx2MlptcGovbkNjbS9JV1lsdjJabXBqK0tNOEcvQ3RjanYyWm1wais0SHNXL0N0Y2p2eFN1aHorNEhzVy9JV1lsdnhTdWh6K0tNOEcvcGRZcHZ4U3VoejhWNGIyL0N0Y2p2eFN1aHorNEhzVy9wZFlwdnhTdWh6OFY0YjIvajNzd3Z4U3Voei9UcUx1L0N0Y2p2eFN1aHorNEhzVy9qM3N3dnhTdWh6L1RxTHUvN0ZFNHZ4U3VoejlJNGJxL0N0Y2p2eFN1aHorNEhzVy83RkU0dnhTdWh6OUk0YnEvU1NoQXZ4U3Voei9UcUx1L0N0Y2p2eFN1aHorNEhzVy9TU2hBdnhTdWh6L1RxTHUvTXMxR3Z4U3VoejhWNGIyL0N0Y2p2eFN1aHorNEhzVy9NczFHdnhTdWh6OFY0YjIvdGoxTHZ4U3VoeitLTThHL0N0Y2p2eFN1aHorNEhzVy90ajFMdnhTdWh6K0tNOEcvemN4TXZ4U3Voeis0SHNXL0N0Y2p2eFN1aHorNEhzVy96Y3hNdnhTdWh6KzRIc1cvdGoxTHZ4U3Voei9uQ2NtL0N0Y2p2eFN1aHorNEhzVy90ajFMdnhTdWh6L25DY20vTXMxR3Z4U3VoejljWE15L0N0Y2p2eFN1aHorNEhzVy9NczFHdnhTdWh6OWNYTXkvU1NoQXZ4U3VoeitkbE02L0N0Y2p2eFN1aHorNEhzVy9TU2hBdnhTdWh6K2RsTTYvN0ZFNHZ4U3VoejhwWE0rL0N0Y2p2eFN1aHorNEhzVy83RkU0dnhTdWh6OHBYTSsvajNzd3Z4U3VoeitkbE02L0N0Y2p2eFN1aHorNEhzVy9qM3N3dnhTdWh6K2RsTTYvcGRZcHZ4U3VoejljWE15L0N0Y2p2eFN1aHorNEhzVy9wZFlwdnhTdWh6OWNYTXkvSVdZbHZ4U3Voei9uQ2NtL0FBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBWG9Oc1B3QUFBQUFWNzhNK0FBQ0FQd0FBQUFBQUFBQUFYb05zUHdBQUFBQVY3OE0rWG9Oc1B3QUFBQUFWNzhNK1hvTnNQd0FBQUFBVjc4TStYb05zUHdBQUFBQVY3OE0rOHdRMVB3QUFBQUR6QkRVL1hvTnNQd0FBQUFBVjc4TSs4d1ExUHdBQUFBRHpCRFUvOHdRMVB3QUFBQUR6QkRVLzh3UTFQd0FBQUFEekJEVS84d1ExUHdBQUFBRHpCRFUvRmUvRFBnQUFBQUJlZzJ3Lzh3UTFQd0FBQUFEekJEVS9GZS9EUGdBQUFBQmVnMncvRmUvRFBnQUFBQUJlZzJ3L0ZlL0RQZ0FBQUFCZWcydy9GZS9EUGdBQUFBQmVnMncvTWpHTkpBQUFBQUFBQUlBL0ZlL0RQZ0FBQUFCZWcydy9NakdOSkFBQUFBQUFBSUEvTWpHTkpBQUFBQUFBQUlBL01qR05KQUFBQUFBQUFJQS9NakdOSkFBQUFBQUFBSUEvRmUvRHZnQUFBQUJlZzJ3L01qR05KQUFBQUFBQUFJQS9GZS9EdmdBQUFBQmVnMncvRmUvRHZnQUFBQUJlZzJ3L0ZlL0R2Z0FBQUFCZWcydy9GZS9EdmdBQUFBQmVnMncvOHdRMXZ3QUFBQUR6QkRVL0ZlL0R2Z0FBQUFCZWcydy84d1ExdndBQUFBRHpCRFUvOHdRMXZ3QUFBQUR6QkRVLzh3UTF2d0FBQUFEekJEVS84d1ExdndBQUFBRHpCRFUvWG9Oc3Z3QUFBQUFWNzhNKzh3UTF2d0FBQUFEekJEVS9Yb05zdndBQUFBQVY3OE0rWG9Oc3Z3QUFBQUFWNzhNK1hvTnN2d0FBQUFBVjc4TStYb05zdndBQUFBQVY3OE0rQUFDQXZ3QUFBQUF5TVEwbFhvTnN2d0FBQUFBVjc4TStBQUNBdndBQUFBQXlNUTBsQUFDQXZ3QUFBQUF5TVEwbEFBQ0F2d0FBQUFBeU1RMGxBQUNBdndBQUFBQXlNUTBsWG9Oc3Z3QUFBQUFWNzhPK0FBQ0F2d0FBQUFBeU1RMGxYb05zdndBQUFBQVY3OE8rWG9Oc3Z3QUFBQUFWNzhPK1hvTnN2d0FBQUFBVjc4TytYb05zdndBQUFBQVY3OE8rOHdRMXZ3QUFBQUR6QkRXL1hvTnN2d0FBQUFBVjc4Tys4d1ExdndBQUFBRHpCRFcvOHdRMXZ3QUFBQUR6QkRXLzh3UTF2d0FBQUFEekJEVy84d1ExdndBQUFBRHpCRFcvRmUvRHZnQUFBQUJlZzJ5Lzh3UTF2d0FBQUFEekJEVy9GZS9EdmdBQUFBQmVnMnkvRmUvRHZnQUFBQUJlZzJ5L0ZlL0R2Z0FBQUFCZWcyeS9GZS9EdmdBQUFBQmVnMnkveXNsVHBRQUFBQUFBQUlDL0ZlL0R2Z0FBQUFCZWcyeS95c2xUcFFBQUFBQUFBSUMveXNsVHBRQUFBQUFBQUlDL3lzbFRwUUFBQUFBQUFJQy95c2xUcFFBQUFBQUFBSUMvRmUvRFBnQUFBQUJlZzJ5L3lzbFRwUUFBQUFBQUFJQy9GZS9EUGdBQUFBQmVnMnkvRmUvRFBnQUFBQUJlZzJ5L0ZlL0RQZ0FBQUFCZWcyeS9GZS9EUGdBQUFBQmVnMnkvOHdRMVB3QUFBQUR6QkRXL0ZlL0RQZ0FBQUFCZWcyeS84d1ExUHdBQUFBRHpCRFcvOHdRMVB3QUFBQUR6QkRXLzh3UTFQd0FBQUFEekJEVy84d1ExUHdBQUFBRHpCRFcvWG9Oc1B3QUFBQUFWNzhPKzh3UTFQd0FBQUFEekJEVy9Yb05zUHdBQUFBQVY3OE8rWG9Oc1B3QUFBQUFWNzhPK1hvTnNQd0FBQUFBVjc4TytYb05zUHdBQUFBQVY3OE8rQUFDQVB3QUFBQUFBQUFBQVhvTnNQd0FBQUFBVjc4TytBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQ0FBQUFBQUFBQWdEOEFBQUNBQUFBQUFBQUFnRDhBQUFDQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFnQUFBZ0w4QUFBQUFBQUFBZ0FBQWdMOEFBQUFBQUFBQWdBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQ0FQd0FBQUFBQUFBQUFBQUNBUHdBQUFBQUFBQUFBWG9Oc1B3QUFBQUFWNzhNK0FBQ0FQd0FBQUFBQUFBQUFYb05zUHdBQUFBQVY3OE0rWG9Oc1B3QUFBQUFWNzhNK1hvTnNQd0FBQUFBVjc4TStYb05zUHdBQUFBQVY3OE0rOHdRMVB3QUFBQUR6QkRVL1hvTnNQd0FBQUFBVjc4TSs4d1ExUHdBQUFBRHpCRFUvOHdRMVB3QUFBQUR6QkRVLzh3UTFQd0FBQUFEekJEVS84d1ExUHdBQUFBRHpCRFUvRmUvRFBnQUFBQUJlZzJ3Lzh3UTFQd0FBQUFEekJEVS9GZS9EUGdBQUFBQmVnMncvRmUvRFBnQUFBQUJlZzJ3L0ZlL0RQZ0FBQUFCZWcydy9GZS9EUGdBQUFBQmVnMncvTWpHTkpBQUFBQUFBQUlBL0ZlL0RQZ0FBQUFCZWcydy9NakdOSkFBQUFBQUFBSUEvTWpHTkpBQUFBQUFBQUlBL01qR05KQUFBQUFBQUFJQS9NakdOSkFBQUFBQUFBSUEvRmUvRHZnQUFBQUJlZzJ3L01qR05KQUFBQUFBQUFJQS9GZS9EdmdBQUFBQmVnMncvRmUvRHZnQUFBQUJlZzJ3L0ZlL0R2Z0FBQUFCZWcydy9GZS9EdmdBQUFBQmVnMncvOHdRMXZ3QUFBQUR6QkRVL0ZlL0R2Z0FBQUFCZWcydy84d1ExdndBQUFBRHpCRFUvOHdRMXZ3QUFBQUR6QkRVLzh3UTF2d0FBQUFEekJEVS84d1ExdndBQUFBRHpCRFUvWG9Oc3Z3QUFBQUFWNzhNKzh3UTF2d0FBQUFEekJEVS9Yb05zdndBQUFBQVY3OE0rWG9Oc3Z3QUFBQUFWNzhNK1hvTnN2d0FBQUFBVjc4TStYb05zdndBQUFBQVY3OE0rQUFDQXZ3QUFBQUF5TVEwbFhvTnN2d0FBQUFBVjc4TStBQUNBdndBQUFBQXlNUTBsQUFDQXZ3QUFBQUF5TVEwbEFBQ0F2d0FBQUFBeU1RMGxBQUNBdndBQUFBQXlNUTBsWG9Oc3Z3QUFBQUFWNzhPK0FBQ0F2d0FBQUFBeU1RMGxYb05zdndBQUFBQVY3OE8rWG9Oc3Z3QUFBQUFWNzhPK1hvTnN2d0FBQUFBVjc4TytYb05zdndBQUFBQVY3OE8rOHdRMXZ3QUFBQUR6QkRXL1hvTnN2d0FBQUFBVjc4Tys4d1ExdndBQUFBRHpCRFcvOHdRMXZ3QUFBQUR6QkRXLzh3UTF2d0FBQUFEekJEVy84d1ExdndBQUFBRHpCRFcvRmUvRHZnQUFBQUJlZzJ5Lzh3UTF2d0FBQUFEekJEVy9GZS9EdmdBQUFBQmVnMnkvRmUvRHZnQUFBQUJlZzJ5L0ZlL0R2Z0FBQUFCZWcyeS9GZS9EdmdBQUFBQmVnMnkveXNsVHBRQUFBQUFBQUlDL0ZlL0R2Z0FBQUFCZWcyeS95c2xUcFFBQUFBQUFBSUMveXNsVHBRQUFBQUFBQUlDL3lzbFRwUUFBQUFBQUFJQy95c2xUcFFBQUFBQUFBSUMvRmUvRFBnQUFBQUJlZzJ5L3lzbFRwUUFBQUFBQUFJQy9GZS9EUGdBQUFBQmVnMnkvRmUvRFBnQUFBQUJlZzJ5L0ZlL0RQZ0FBQUFCZWcyeS9GZS9EUGdBQUFBQmVnMnkvOHdRMVB3QUFBQUR6QkRXL0ZlL0RQZ0FBQUFCZWcyeS84d1ExUHdBQUFBRHpCRFcvOHdRMVB3QUFBQUR6QkRXLzh3UTFQd0FBQUFEekJEVy84d1ExUHdBQUFBRHpCRFcvWG9Oc1B3QUFBQUFWNzhPKzh3UTFQd0FBQUFEekJEVy9Yb05zUHdBQUFBQVY3OE8rWG9Oc1B3QUFBQUFWNzhPK1hvTnNQd0FBQUFBVjc4TytYb05zUHdBQUFBQVY3OE8rQUFDQVB3QUFBQUFBQUFBQVhvTnNQd0FBQUFBVjc4TytBQUNBUHdBQUFBQUFBQUFBQUFDQVB3QUFBQUFBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0Q4QUFBQ0FBQUFBQUFBQWdEOEFBQUNBQUFBQUFBQUFnRDhBQUFDQUFBQUFBQUFBZ0Q4QUFBQUFBQUFBQUFBQWdEOEFBQUFBQUFBQUFBQUFnRDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFnQUFBZ0w4QUFBQUFBQUFBZ0FBQWdMOEFBQUFBQUFBQWdBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUFBQUFBZ0w4QUFBQUFBQUFBQUFBQWdMOEFBQUFBQUFBQUFBQUFnTDhBQUFBQUFBQUJBQUlBQXdBRUFBVUFCZ0FIQUFnQUNRQUtBQXNBREFBTkFBNEFEd0FRQUJFQUVnQVRBQlFBRlFBV0FCY0FHQUFaQUJvQUd3QWNBQjBBSGdBZkFDQUFJUUFpQUNNQUpBQWxBQ1lBSndBb0FDa0FLZ0FyQUN3QUxRQXVBQzhBTUFBeEFESUFNd0EwQURVQU5nQTNBRGdBT1FBNkFEc0FQQUE5QUQ0QVB3QkFBRUVBUWdCREFFUUFSUUJHQUVjQVNBQkpBRW9BU3dCTUFFMEFUZ0JQQUZBQVVRQlNBRk1BVkFCVkFGWUFWd0JZQUZrQVdnQmJBRndBWFFCZUFGOEFZQUJoQUdJQVl3QmtBR1VBWmdCbkFHZ0FhUUJxQUdzQWJBQnRBRzRBYndCd0FIRUFjZ0J6QUhRQWRRQjJBSGNBZUFCNUFIb0Fld0I4QUgwQWZnQi9BSUFBZ1FDQ0FJTUFoQUNGQUlZQWh3Q0lBSWtBaWdDTEFJd0FqUUNPQUk4QWtBQ1JBSklBa3dDVUFKVUFsZ0NYQUpnQW1RQ2FBSnNBbkFDZEFKNEFud0NnQUtFQW9nQ2pBS1FBcFFDbUFLY0FxQUNwQUtvQXF3Q3NBSzBBcmdDdkFMQUFzUUN5QUxNQXRBQzFBTFlBdHdDNEFMa0F1Z0M3QUx3QXZRQytBTDhBd0FEQkFNSUF3d0RFQU1VQXhnREhBTWdBeVFES0FNc0F6QUROQU00QXp3RFFBTkVBMGdEVEFOUUExUURXQU5jQTJBRFpBTm9BMndEY0FOMEEzZ0RmQU9BQTRRRGlBT01BNUFEbEFPWUE1d0RvQU9rQTZnRHJBT3dBN1FEdUFPOEE4QUR4QVBJQTh3RDBBUFVBOWdEM0FQZ0ErUUQ2QVBzQS9BRDlBUDRBL3dBQUFRRUJBZ0VEQVFRQkJRRUdBUWNCQ0FFSkFRb0JDd0VNQVEwQkRnRVBBUkFCRVFFU0FSTUJGQUVWQVJZQkZ3RVlBUmtCR2dFYkFSd0JIUUVlQVI4QklBRWhBU0lCSXdFa0FTVUJKZ0VuQVNnQktRRXFBU3NCTEFFdEFTNEJMd0V3QVRFQk1nRXpBVFFCTlFFMkFUY0JPQUU1QVRvQk93RThBVDBCUGdFL0FVQUJRUUZDQVVNQlJBRkZBVVlCUndGSUFVa0JTZ0ZMQVV3QlRRRk9BVThCVUFGUkFWSUJVd0ZVQVZVQlZnRlhBVmdCV1FGYUFWc0JYQUZkQVY0Qlh3RmdBV0VCWWdGakFXUUJaUUZtQVdjQiIsCiAgICAgICJieXRlTGVuZ3RoIjogMzYxOTIKICAgIH0KICBdLAogICJidWZmZXJWaWV3cyI6IFsKICAgIHsKICAgICAgImJ1ZmZlciI6IDAsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImJ5dGVMZW5ndGgiOiAzMDI0LAogICAgICAidGFyZ2V0IjogMzQ5NjIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXIiOiAwLAogICAgICAiYnl0ZU9mZnNldCI6IDMwMjQsCiAgICAgICJieXRlTGVuZ3RoIjogMzAyNCwKICAgICAgInRhcmdldCI6IDM0OTYyCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiA2MDQ4LAogICAgICAiYnl0ZUxlbmd0aCI6IDUwNCwKICAgICAgInRhcmdldCI6IDM0OTYzCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiA2NTUyLAogICAgICAiYnl0ZUxlbmd0aCI6IDE3MjgsCiAgICAgICJ0YXJnZXQiOiAzNDk2MgogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlciI6IDAsCiAgICAgICJieXRlT2Zmc2V0IjogODI4MCwKICAgICAgImJ5dGVMZW5ndGgiOiAxNzI4LAogICAgICAidGFyZ2V0IjogMzQ5NjIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXIiOiAwLAogICAgICAiYnl0ZU9mZnNldCI6IDEwMDA4LAogICAgICAiYnl0ZUxlbmd0aCI6IDI4OCwKICAgICAgInRhcmdldCI6IDM0OTYzCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAxMDI5NiwKICAgICAgImJ5dGVMZW5ndGgiOiA4NjQsCiAgICAgICJ0YXJnZXQiOiAzNDk2MgogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlciI6IDAsCiAgICAgICJieXRlT2Zmc2V0IjogMTExNjAsCiAgICAgICJieXRlTGVuZ3RoIjogODY0LAogICAgICAidGFyZ2V0IjogMzQ5NjIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXIiOiAwLAogICAgICAiYnl0ZU9mZnNldCI6IDEyMDI0LAogICAgICAiYnl0ZUxlbmd0aCI6IDE0NCwKICAgICAgInRhcmdldCI6IDM0OTYzCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAxMjE2OCwKICAgICAgImJ5dGVMZW5ndGgiOiA2MTkyLAogICAgICAidGFyZ2V0IjogMzQ5NjIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXIiOiAwLAogICAgICAiYnl0ZU9mZnNldCI6IDE4MzYwLAogICAgICAiYnl0ZUxlbmd0aCI6IDYxOTIsCiAgICAgICJ0YXJnZXQiOiAzNDk2MgogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlciI6IDAsCiAgICAgICJieXRlT2Zmc2V0IjogMjQ1NTIsCiAgICAgICJieXRlTGVuZ3RoIjogMTAzMiwKICAgICAgInRhcmdldCI6IDM0OTYzCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAyNTU4NCwKICAgICAgImJ5dGVMZW5ndGgiOiAxNDQsCiAgICAgICJ0YXJnZXQiOiAzNDk2MgogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlciI6IDAsCiAgICAgICJieXRlT2Zmc2V0IjogMjU3MjgsCiAgICAgICJieXRlTGVuZ3RoIjogMTQ0LAogICAgICAidGFyZ2V0IjogMzQ5NjIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXIiOiAwLAogICAgICAiYnl0ZU9mZnNldCI6IDI1ODcyLAogICAgICAiYnl0ZUxlbmd0aCI6IDI0LAogICAgICAidGFyZ2V0IjogMzQ5NjMKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXIiOiAwLAogICAgICAiYnl0ZU9mZnNldCI6IDI1ODk2LAogICAgICAiYnl0ZUxlbmd0aCI6IDQzMiwKICAgICAgInRhcmdldCI6IDM0OTYyCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAyNjMyOCwKICAgICAgImJ5dGVMZW5ndGgiOiA0MzIsCiAgICAgICJ0YXJnZXQiOiAzNDk2MgogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlciI6IDAsCiAgICAgICJieXRlT2Zmc2V0IjogMjY3NjAsCiAgICAgICJieXRlTGVuZ3RoIjogNzIsCiAgICAgICJ0YXJnZXQiOiAzNDk2MwogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlciI6IDAsCiAgICAgICJieXRlT2Zmc2V0IjogMjY4MzIsCiAgICAgICJieXRlTGVuZ3RoIjogNDMyMCwKICAgICAgInRhcmdldCI6IDM0OTYyCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAzMTE1MiwKICAgICAgImJ5dGVMZW5ndGgiOiA0MzIwLAogICAgICAidGFyZ2V0IjogMzQ5NjIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXIiOiAwLAogICAgICAiYnl0ZU9mZnNldCI6IDM1NDcyLAogICAgICAiYnl0ZUxlbmd0aCI6IDcyMCwKICAgICAgInRhcmdldCI6IDM0OTYzCiAgICB9CiAgXSwKICAiYWNjZXNzb3JzIjogWwogICAgewogICAgICAiYnVmZmVyVmlldyI6IDAsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTI2LAogICAgICAiY291bnQiOiAyNTIsCiAgICAgICJ0eXBlIjogIlZFQzMiLAogICAgICAibWluIjogWwogICAgICAgIC0xLjU4LAogICAgICAgIC0xLjA4LAogICAgICAgIC00LjQKICAgICAgXSwKICAgICAgIm1heCI6IFsKICAgICAgICAxLjU4LAogICAgICAgIDEuMDIsCiAgICAgICAgMy45CiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMSwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjYsCiAgICAgICJjb3VudCI6IDI1MiwKICAgICAgInR5cGUiOiAiVkVDMyIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMiwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjMsCiAgICAgICJjb3VudCI6IDI1MiwKICAgICAgInR5cGUiOiAiU0NBTEFSIiwKICAgICAgIm1pbiI6IFsKICAgICAgICAwCiAgICAgIF0sCiAgICAgICJtYXgiOiBbCiAgICAgICAgMjUxCiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMywKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjYsCiAgICAgICJjb3VudCI6IDE0NCwKICAgICAgInR5cGUiOiAiVkVDMyIsCiAgICAgICJtaW4iOiBbCiAgICAgICAgLTEuNTgsCiAgICAgICAgMC43OCwKICAgICAgICAtNC40CiAgICAgIF0sCiAgICAgICJtYXgiOiBbCiAgICAgICAgMS41OCwKICAgICAgICAxLjU0LAogICAgICAgIDMuOQogICAgICBdCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDQsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTI2LAogICAgICAiY291bnQiOiAxNDQsCiAgICAgICJ0eXBlIjogIlZFQzMiCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDUsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTIzLAogICAgICAiY291bnQiOiAxNDQsCiAgICAgICJ0eXBlIjogIlNDQUxBUiIsCiAgICAgICJtaW4iOiBbCiAgICAgICAgMAogICAgICBdLAogICAgICAibWF4IjogWwogICAgICAgIDE0MwogICAgICBdCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDYsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTI2LAogICAgICAiY291bnQiOiA3MiwKICAgICAgInR5cGUiOiAiVkVDMyIsCiAgICAgICJtaW4iOiBbCiAgICAgICAgLTEuNDgsCiAgICAgICAgMC44NCwKICAgICAgICAtMi4yCiAgICAgIF0sCiAgICAgICJtYXgiOiBbCiAgICAgICAgMS40OCwKICAgICAgICAxLjYyLAogICAgICAgIDIuNAogICAgICBdCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDcsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTI2LAogICAgICAiY291bnQiOiA3MiwKICAgICAgInR5cGUiOiAiVkVDMyIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogOCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjMsCiAgICAgICJjb3VudCI6IDcyLAogICAgICAidHlwZSI6ICJTQ0FMQVIiLAogICAgICAibWluIjogWwogICAgICAgIDAKICAgICAgXSwKICAgICAgIm1heCI6IFsKICAgICAgICA3MQogICAgICBdCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDksCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTI2LAogICAgICAiY291bnQiOiA1MTYsCiAgICAgICJ0eXBlIjogIlZFQzMiLAogICAgICAibWluIjogWwogICAgICAgIC0wLjE2LAogICAgICAgIDAuODQ5OTk5OTk5OTk5OTk5NiwKICAgICAgICAtMwogICAgICBdLAogICAgICAibWF4IjogWwogICAgICAgIDIuMTgsCiAgICAgICAgNi4yNSwKICAgICAgICA1LjA1CiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMTAsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTI2LAogICAgICAiY291bnQiOiA1MTYsCiAgICAgICJ0eXBlIjogIlZFQzMiCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDExLAogICAgICAiYnl0ZU9mZnNldCI6IDAsCiAgICAgICJjb21wb25lbnRUeXBlIjogNTEyMywKICAgICAgImNvdW50IjogNTE2LAogICAgICAidHlwZSI6ICJTQ0FMQVIiLAogICAgICAibWluIjogWwogICAgICAgIDAKICAgICAgXSwKICAgICAgIm1heCI6IFsKICAgICAgICA1MTUKICAgICAgXQogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlclZpZXciOiAxMiwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjYsCiAgICAgICJjb3VudCI6IDEyLAogICAgICAidHlwZSI6ICJWRUMzIiwKICAgICAgIm1pbiI6IFsKICAgICAgICAtMC4wOCwKICAgICAgICAxLjEyLAogICAgICAgIC0yLjk2CiAgICAgIF0sCiAgICAgICJtYXgiOiBbCiAgICAgICAgMS44NiwKICAgICAgICA0LjgyLAogICAgICAgIC0wLjc0CiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMTMsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTI2LAogICAgICAiY291bnQiOiAxMiwKICAgICAgInR5cGUiOiAiVkVDMyIKICAgIH0sCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMTQsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTIzLAogICAgICAiY291bnQiOiAxMiwKICAgICAgInR5cGUiOiAiU0NBTEFSIiwKICAgICAgIm1pbiI6IFsKICAgICAgICAwCiAgICAgIF0sCiAgICAgICJtYXgiOiBbCiAgICAgICAgMTEKICAgICAgXQogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlclZpZXciOiAxNSwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjYsCiAgICAgICJjb3VudCI6IDM2LAogICAgICAidHlwZSI6ICJWRUMzIiwKICAgICAgIm1pbiI6IFsKICAgICAgICAtMC45NiwKICAgICAgICAwLjc4LAogICAgICAgIDEuMjYKICAgICAgXSwKICAgICAgIm1heCI6IFsKICAgICAgICAwLjk2LAogICAgICAgIDAuODgsCiAgICAgICAgMS40NAogICAgICBdCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDE2LAogICAgICAiYnl0ZU9mZnNldCI6IDAsCiAgICAgICJjb21wb25lbnRUeXBlIjogNTEyNiwKICAgICAgImNvdW50IjogMzYsCiAgICAgICJ0eXBlIjogIlZFQzMiCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDE3LAogICAgICAiYnl0ZU9mZnNldCI6IDAsCiAgICAgICJjb21wb25lbnRUeXBlIjogNTEyMywKICAgICAgImNvdW50IjogMzYsCiAgICAgICJ0eXBlIjogIlNDQUxBUiIsCiAgICAgICJtaW4iOiBbCiAgICAgICAgMAogICAgICBdLAogICAgICAibWF4IjogWwogICAgICAgIDM1CiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMTgsCiAgICAgICJieXRlT2Zmc2V0IjogMCwKICAgICAgImNvbXBvbmVudFR5cGUiOiA1MTI2LAogICAgICAiY291bnQiOiAzNjAsCiAgICAgICJ0eXBlIjogIlZFQzMiLAogICAgICAibWluIjogWwogICAgICAgIC0wLjc5OTk5OTk5OTk5OTk5OTksCiAgICAgICAgMS4wNiwKICAgICAgICAtMS42MgogICAgICBdLAogICAgICAibWF4IjogWwogICAgICAgIDAuNzk5OTk5OTk5OTk5OTk5OSwKICAgICAgICAxLjM1OTk5OTk5OTk5OTk5OTksCiAgICAgICAgMS4wNAogICAgICBdCiAgICB9LAogICAgewogICAgICAiYnVmZmVyVmlldyI6IDE5LAogICAgICAiYnl0ZU9mZnNldCI6IDAsCiAgICAgICJjb21wb25lbnRUeXBlIjogNTEyNiwKICAgICAgImNvdW50IjogMzYwLAogICAgICAidHlwZSI6ICJWRUMzIgogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlclZpZXciOiAyMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjMsCiAgICAgICJjb3VudCI6IDM2MCwKICAgICAgInR5cGUiOiAiU0NBTEFSIiwKICAgICAgIm1pbiI6IFsKICAgICAgICAwCiAgICAgIF0sCiAgICAgICJtYXgiOiBbCiAgICAgICAgMzU5CiAgICAgIF0KICAgIH0KICBdCn0K"
32
+ });
33
+ }
34
+ });
35
+
22
36
  // src/asset-url.js
23
- function createInlineShowcaseAssetUrl() {
24
- return new URL(INLINE_BRIGANTINE_GLTF_URL);
37
+ function createInlineShowcaseAssetUrl(assetName) {
38
+ const inlineUrl = INLINE_SHOWCASE_ASSET_URLS[assetName];
39
+ return inlineUrl ? new URL(inlineUrl) : null;
25
40
  }
26
41
  function getBrowserBaseUrl() {
27
42
  if (typeof document !== "undefined" && typeof document.baseURI === "string" && document.baseURI.length > 0) {
@@ -32,27 +47,177 @@ function getBrowserBaseUrl() {
32
47
  }
33
48
  return null;
34
49
  }
35
- function resolveShowcaseAssetUrl(baseUrl2 = import_meta.url) {
50
+ function normalizeAssetName(assetName) {
51
+ return typeof assetName === "string" && assetName in SHOWCASE_ASSET_FILES ? assetName : "brigantine";
52
+ }
53
+ function parseResolveArgs(baseUrlOrAssetName, assetName) {
54
+ if (typeof baseUrlOrAssetName === "string" && baseUrlOrAssetName in SHOWCASE_ASSET_FILES && typeof assetName === "undefined") {
55
+ return {
56
+ baseUrl: import_meta.url,
57
+ assetName: baseUrlOrAssetName
58
+ };
59
+ }
60
+ return {
61
+ baseUrl: baseUrlOrAssetName ?? import_meta.url,
62
+ assetName: normalizeAssetName(assetName)
63
+ };
64
+ }
65
+ function resolveShowcaseAssetUrl(baseUrlOrAssetName, assetName) {
66
+ const resolved = parseResolveArgs(baseUrlOrAssetName, assetName);
67
+ const fileName = SHOWCASE_ASSET_FILES[resolved.assetName];
36
68
  try {
37
- return new URL("../assets/brigantine.gltf", baseUrl2);
69
+ return new URL(`../assets/${fileName}`, resolved.baseUrl);
38
70
  } catch {
39
71
  const browserBaseUrl = getBrowserBaseUrl();
40
72
  if (browserBaseUrl) {
41
73
  try {
42
- const normalizedBaseUrl = new URL(baseUrl2, browserBaseUrl);
43
- return new URL("../assets/brigantine.gltf", normalizedBaseUrl);
74
+ const normalizedBaseUrl = new URL(resolved.baseUrl, browserBaseUrl);
75
+ return new URL(`../assets/${fileName}`, normalizedBaseUrl);
44
76
  } catch {
45
- return createInlineShowcaseAssetUrl();
77
+ const inlineAsset = createInlineShowcaseAssetUrl(resolved.assetName);
78
+ if (inlineAsset) {
79
+ return inlineAsset;
80
+ }
46
81
  }
47
82
  }
48
- return createInlineShowcaseAssetUrl();
83
+ try {
84
+ return new URL(`../assets/${fileName}`, import_meta.url);
85
+ } catch {
86
+ return new URL(`assets/${fileName}`, "file:///");
87
+ }
49
88
  }
50
89
  }
51
- var import_meta, INLINE_BRIGANTINE_GLTF_URL;
90
+ function shouldUseInlineShowcaseFallback(url) {
91
+ const href = url instanceof URL ? url.href : String(url ?? "");
92
+ return href.includes("/assets/");
93
+ }
94
+ var import_meta, SHOWCASE_ASSET_FILES;
52
95
  var init_asset_url = __esm({
53
96
  "src/asset-url.js"() {
97
+ init_showcase_inline_assets();
54
98
  import_meta = {};
55
- INLINE_BRIGANTINE_GLTF_URL = "data:application/json;base64,ewogICJhc3NldCI6IHsKICAgICJ2ZXJzaW9uIjogIjIuMCIsCiAgICAiZ2VuZXJhdG9yIjogIlBsYXNpdXMgZGVtbyBhc3NldCBnZW5lcmF0b3IiCiAgfSwKICAic2NlbmUiOiAwLAogICJzY2VuZXMiOiBbCiAgICB7CiAgICAgICJub2RlcyI6IFswXQogICAgfQogIF0sCiAgIm5vZGVzIjogWwogICAgewogICAgICAibWVzaCI6IDAsCiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUiLAogICAgICAiZXh0cmFzIjogewogICAgICAgICJwaHlzaWNzIjogewogICAgICAgICAgInNoYXBlIjogImJveCIsCiAgICAgICAgICAiaGFsZkV4dGVudHMiOiBbMS4zNSwgMC45NSwgMy45XSwKICAgICAgICAgICJtYXNzIjogMzIwMCwKICAgICAgICAgICJyZXN0aXR1dGlvbiI6IDAuMjIsCiAgICAgICAgICAibGluZWFyRGFtcGluZyI6IDAuMDQsCiAgICAgICAgICAiYW5ndWxhckRhbXBpbmciOiAwLjA4LAogICAgICAgICAgIndhdGVybGluZSI6IDAuNDIKICAgICAgICB9CiAgICAgIH0KICAgIH0KICBdLAogICJtZXNoZXMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogImJyaWdhbnRpbmUtaHVsbCIsCiAgICAgICJwcmltaXRpdmVzIjogWwogICAgICAgIHsKICAgICAgICAgICJhdHRyaWJ1dGVzIjogewogICAgICAgICAgICAiUE9TSVRJT04iOiAwCiAgICAgICAgICB9LAogICAgICAgICAgImluZGljZXMiOiAxLAogICAgICAgICAgIm1hdGVyaWFsIjogMAogICAgICAgIH0KICAgICAgXQogICAgfQogIF0sCiAgIm1hdGVyaWFscyI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAicGFpbnRlZC1odWxsIiwKICAgICAgInBick1ldGFsbGljUm91Z2huZXNzIjogewogICAgICAgICJiYXNlQ29sb3JGYWN0b3IiOiBbMC41NiwgMC4zMywgMC4yMiwgMV0sCiAgICAgICAgIm1ldGFsbGljRmFjdG9yIjogMC4wOCwKICAgICAgICAicm91Z2huZXNzRmFjdG9yIjogMC45MgogICAgICB9CiAgICB9CiAgXSwKICAiYnVmZmVycyI6IFsKICAgIHsKICAgICAgInVyaSI6ICJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsbXBtWnZ3QUFBTC9OekV6QW1wbVpQd0FBQUwvTnpFekF6Y3lzdnpNenM3NHpNN08vemN5c1B6TXpzNzR6TTdPL0FBQ2d2ODNNVEwzTnpNdy9BQUNnUDgzTVRMM056TXcvQUFBQUFPeFJPTDR6TTROQUFBQUFBR1ptNWo0QUFIQkFNek56dnpNenN6NmFtUm5BTXpOelB6TXpzejZhbVJuQXpjeE12ejBLMXo3TnpFdy96Y3hNUHowSzF6N056RXcvQUFBQUFETXpjejltWm1hL0FBQUNBQU1BQUFBREFBRUFBZ0FFQUFVQUFnQUZBQU1BQkFBSEFBVUFCQUFHQUFjQUJRQUhBQVlBQUFBQkFBa0FBQUFKQUFnQUNBQUpBQXdBQWdBSUFBd0FBd0FNQUFrQUFnQU1BQW9BQXdBTEFBd0FBZ0FLQUFRQUF3QUZBQXNBQ2dBTUFBc0FBQUFJQUFJQUFRQURBQWtBQkFBS0FBWUFCUUFHQUFzQUFnQUtBQXNBQWdBTEFBTUEiLAogICAgICAiYnl0ZUxlbmd0aCI6IDI5NAogICAgfQogIF0sCiAgImJ1ZmZlclZpZXdzIjogWwogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiYnl0ZUxlbmd0aCI6IDE1NiwKICAgICAgInRhcmdldCI6IDM0OTYyCiAgICB9LAogICAgewogICAgICAiYnVmZmVyIjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAxNTYsCiAgICAgICJieXRlTGVuZ3RoIjogMTM4LAogICAgICAidGFyZ2V0IjogMzQ5NjMKICAgIH0KICBdLAogICJhY2Nlc3NvcnMiOiBbCiAgICB7CiAgICAgICJidWZmZXJWaWV3IjogMCwKICAgICAgImJ5dGVPZmZzZXQiOiAwLAogICAgICAiY29tcG9uZW50VHlwZSI6IDUxMjYsCiAgICAgICJjb3VudCI6IDEzLAogICAgICAidHlwZSI6ICJWRUMzIiwKICAgICAgIm1pbiI6IFstMS4zNSwgLTAuNSwgLTMuMl0sCiAgICAgICJtYXgiOiBbMS4zNSwgMC45NSwgNC4xXQogICAgfSwKICAgIHsKICAgICAgImJ1ZmZlclZpZXciOiAxLAogICAgICAiYnl0ZU9mZnNldCI6IDAsCiAgICAgICJjb21wb25lbnRUeXBlIjogNTEyMywKICAgICAgImNvdW50IjogNjksCiAgICAgICJ0eXBlIjogIlNDQUxBUiIsCiAgICAgICJtYXgiOiBbMTJdLAogICAgICAibWluIjogWzBdCiAgICB9CiAgXQp9Cg==";
99
+ SHOWCASE_ASSET_FILES = Object.freeze({
100
+ brigantine: "brigantine.gltf",
101
+ cutter: "cutter.gltf",
102
+ lighthouse: "lighthouse.gltf",
103
+ "harbor-dock": "harbor-dock.gltf"
104
+ });
105
+ }
106
+ });
107
+
108
+ // src/translations/en-GB.js
109
+ var gpuSharedEnGbTranslations;
110
+ var init_en_GB = __esm({
111
+ "src/translations/en-GB.js"() {
112
+ gpuSharedEnGbTranslations = Object.freeze({
113
+ "gpuShared.showcase.title": "Flag by the Sea",
114
+ "gpuShared.showcase.subtitle": "Shared 3D validation scene using GLTF ships, cloth, fluid continuity, adaptive performance, and telemetry.",
115
+ "gpuShared.showcase.status.booting": "Booting 3D scene...",
116
+ "gpuShared.showcase.status.live": "3D scene live - {fps} FPS",
117
+ "gpuShared.showcase.details.booting": "Preparing a moonlit harbor scene, GLTF hull data, cloth and fluid continuity plans, and adaptive quality metadata.",
118
+ "gpuShared.showcase.details.physics": "Stable world snapshots are emitted from {snapshotStageId} after the authoritative solver; the heavier hull now carries momentum through mass-aware collision impulses while cloth and fluid remain downstream.",
119
+ "gpuShared.showcase.details.realistic": "Moonlit GLTF ships now mix a brigantine and a cutter against modeled harbor assets; cloth, fluid, and ship-local lighting stay continuous while the governor pressure is {pressureLevel}.",
120
+ "gpuShared.showcase.details.legacy": "Moonlit GLTF ships use the legacy brigantine and placeholder harbor blocks while cloth, fluid, and ship-local lighting stay continuous while the governor pressure is {pressureLevel}.",
121
+ "gpuShared.showcase.action.pause": "Pause",
122
+ "gpuShared.showcase.action.resume": "Resume",
123
+ "gpuShared.showcase.control.stressMode": "Stress mode",
124
+ "gpuShared.showcase.control.focus": "Focus",
125
+ "gpuShared.showcase.focus.integrated": "integrated",
126
+ "gpuShared.showcase.focus.lighting": "lighting",
127
+ "gpuShared.showcase.focus.cloth": "cloth",
128
+ "gpuShared.showcase.focus.fluid": "fluid",
129
+ "gpuShared.showcase.focus.physics": "physics",
130
+ "gpuShared.showcase.focus.performance": "performance",
131
+ "gpuShared.showcase.focus.debug": "debug",
132
+ "gpuShared.showcase.legend.title": "Scene",
133
+ "gpuShared.showcase.legend.shipMetadata": "GLTF ships carry hull mass and damping metadata.",
134
+ "gpuShared.showcase.legend.lighting": "Lanterns and torches warm the moonlit harbor.",
135
+ "gpuShared.showcase.legend.collisions": "Mass-aware collisions stay authoritative near the camera.",
136
+ "gpuShared.showcase.section.sceneState": "Scene State",
137
+ "gpuShared.showcase.section.qualityBudgets": "Quality + Budgets",
138
+ "gpuShared.showcase.section.debugTelemetry": "Debug Telemetry",
139
+ "gpuShared.showcase.section.notes": "Notes",
140
+ "gpuShared.showcase.note.assetLoading": "Ships are loaded from a GLTF asset and carry mass, damping, restitution, and hull extents from node extras.",
141
+ "gpuShared.showcase.note.moonlight": "Moonlight sets the cold ambient read while deck lanterns and harbor torches provide warm local contrast.",
142
+ "gpuShared.showcase.note.continuity": "Cloth and fluid continuity stay coherent across near, mid, far, and horizon bands even in the darker night palette.",
143
+ "gpuShared.showcase.note.performance": "Performance pressure reduces visual detail before mass-weighted authoritative collision motion is touched.",
144
+ "gpuShared.showcase.note.physicsSnapshots": "Stable world snapshots are taken after the authoritative rigid-body commit and before visual follow-up work.",
145
+ "gpuShared.showcase.note.physicsCollisions": "The ships collide with mass-weighted impulses and positional correction, so the heavier hull keeps more of its line.",
146
+ "gpuShared.showcase.note.physicsLighting": "Moonlight keeps the overall read legible while lanterns and torches make collision moments easy to track against the water.",
147
+ "gpuShared.debug.adapter.showcase": "3D showcase",
148
+ "gpuShared.debug.allocation.mainColorBuffer": "Main color buffer",
149
+ "gpuShared.debug.allocation.shadowImpressionAtlas": "Shadow impression atlas"
150
+ });
151
+ }
152
+ });
153
+
154
+ // src/i18n.js
155
+ function formatTranslation(template, args = {}) {
156
+ return template.replace(/\{([A-Za-z0-9_]+)\}/g, (match, name) => {
157
+ if (!Object.prototype.hasOwnProperty.call(args, name)) {
158
+ return match;
159
+ }
160
+ const value = args[name];
161
+ return value == null ? "" : String(value);
162
+ });
163
+ }
164
+ function translateGpuSharedText(key, args, translate) {
165
+ const translated = translate?.(key, args);
166
+ if (translated && translated !== key) {
167
+ return translated;
168
+ }
169
+ const fallback = gpuSharedEnGbTranslations[key];
170
+ return fallback ? formatTranslation(fallback, args) : key;
171
+ }
172
+ function createGpuSharedTranslator(translate) {
173
+ return (key, args) => translateGpuSharedText(key, args, translate);
174
+ }
175
+ var gpuSharedTranslationKeys, gpuSharedTranslations;
176
+ var init_i18n = __esm({
177
+ "src/i18n.js"() {
178
+ init_en_GB();
179
+ gpuSharedTranslationKeys = Object.freeze({
180
+ showcaseTitle: "gpuShared.showcase.title",
181
+ showcaseSubtitle: "gpuShared.showcase.subtitle",
182
+ statusBooting: "gpuShared.showcase.status.booting",
183
+ statusLive: "gpuShared.showcase.status.live",
184
+ detailsBooting: "gpuShared.showcase.details.booting",
185
+ detailsPhysics: "gpuShared.showcase.details.physics",
186
+ detailsRealistic: "gpuShared.showcase.details.realistic",
187
+ detailsLegacy: "gpuShared.showcase.details.legacy",
188
+ pause: "gpuShared.showcase.action.pause",
189
+ resume: "gpuShared.showcase.action.resume",
190
+ stressMode: "gpuShared.showcase.control.stressMode",
191
+ focus: "gpuShared.showcase.control.focus",
192
+ focusIntegrated: "gpuShared.showcase.focus.integrated",
193
+ focusLighting: "gpuShared.showcase.focus.lighting",
194
+ focusCloth: "gpuShared.showcase.focus.cloth",
195
+ focusFluid: "gpuShared.showcase.focus.fluid",
196
+ focusPhysics: "gpuShared.showcase.focus.physics",
197
+ focusPerformance: "gpuShared.showcase.focus.performance",
198
+ focusDebug: "gpuShared.showcase.focus.debug",
199
+ legendTitle: "gpuShared.showcase.legend.title",
200
+ legendShipMetadata: "gpuShared.showcase.legend.shipMetadata",
201
+ legendLighting: "gpuShared.showcase.legend.lighting",
202
+ legendCollisions: "gpuShared.showcase.legend.collisions",
203
+ sceneState: "gpuShared.showcase.section.sceneState",
204
+ qualityBudgets: "gpuShared.showcase.section.qualityBudgets",
205
+ debugTelemetry: "gpuShared.showcase.section.debugTelemetry",
206
+ notes: "gpuShared.showcase.section.notes",
207
+ noteAssetLoading: "gpuShared.showcase.note.assetLoading",
208
+ noteMoonlight: "gpuShared.showcase.note.moonlight",
209
+ noteContinuity: "gpuShared.showcase.note.continuity",
210
+ notePerformance: "gpuShared.showcase.note.performance",
211
+ notePhysicsSnapshots: "gpuShared.showcase.note.physicsSnapshots",
212
+ notePhysicsCollisions: "gpuShared.showcase.note.physicsCollisions",
213
+ notePhysicsLighting: "gpuShared.showcase.note.physicsLighting",
214
+ debugAdapterShowcase: "gpuShared.debug.adapter.showcase",
215
+ debugMainColorBuffer: "gpuShared.debug.allocation.mainColorBuffer",
216
+ debugShadowImpressionAtlas: "gpuShared.debug.allocation.shadowImpressionAtlas"
217
+ });
218
+ gpuSharedTranslations = Object.freeze({
219
+ "en-GB": gpuSharedEnGbTranslations
220
+ });
56
221
  }
57
222
  });
58
223
 
@@ -75,6 +240,8 @@ function decodeDataUri(uri) {
75
240
  }
76
241
  function getComponentArray(componentType, buffer, byteOffset, count) {
77
242
  switch (componentType) {
243
+ case 5121:
244
+ return new Uint8Array(buffer, byteOffset, count);
78
245
  case 5123:
79
246
  return new Uint16Array(buffer, byteOffset, count);
80
247
  case 5125:
@@ -85,6 +252,16 @@ function getComponentArray(componentType, buffer, byteOffset, count) {
85
252
  throw new Error(`Unsupported glTF componentType: ${componentType}`);
86
253
  }
87
254
  }
255
+ function getNormalizationScale(componentType) {
256
+ switch (componentType) {
257
+ case 5121:
258
+ return 255;
259
+ case 5123:
260
+ return 65535;
261
+ default:
262
+ return 1;
263
+ }
264
+ }
88
265
  function getTypeSize(type) {
89
266
  switch (type) {
90
267
  case "SCALAR":
@@ -100,27 +277,59 @@ function getTypeSize(type) {
100
277
  }
101
278
  }
102
279
  function readAccessor(document2, accessorIndex, buffers) {
103
- const accessor = document2.accessors[accessorIndex];
104
- const bufferView = document2.bufferViews[accessor.bufferView];
280
+ const accessor = document2.accessors?.[accessorIndex];
281
+ if (!accessor) {
282
+ throw new Error(`glTF accessor ${accessorIndex} is missing.`);
283
+ }
284
+ const bufferView = document2.bufferViews?.[accessor.bufferView];
285
+ if (!bufferView) {
286
+ throw new Error(`glTF bufferView ${accessor.bufferView} is missing.`);
287
+ }
105
288
  const buffer = buffers[bufferView.buffer];
106
289
  const componentCount = getTypeSize(accessor.type);
107
290
  const byteOffset = (bufferView.byteOffset ?? 0) + (accessor.byteOffset ?? 0);
108
291
  const valueCount = accessor.count * componentCount;
109
- return getComponentArray(accessor.componentType, buffer, byteOffset, valueCount);
292
+ const values = Array.from(
293
+ getComponentArray(accessor.componentType, buffer, byteOffset, valueCount)
294
+ );
295
+ if (accessor.normalized) {
296
+ const scale = getNormalizationScale(accessor.componentType);
297
+ return values.map((value) => value / scale);
298
+ }
299
+ return values;
110
300
  }
111
- function getMaterialColor(document2, primitive) {
301
+ function getMaterialInfo(document2, primitive) {
112
302
  const material = document2.materials?.[primitive.material] ?? null;
113
303
  const factor = material?.pbrMetallicRoughness?.baseColorFactor ?? [0.56, 0.33, 0.22, 1];
114
- return {
115
- r: factor[0],
116
- g: factor[1],
117
- b: factor[2],
118
- a: factor[3] ?? 1
119
- };
304
+ const emissive = material?.emissiveFactor ?? [0, 0, 0];
305
+ return Object.freeze({
306
+ name: material?.name ?? "default-material",
307
+ color: Object.freeze({
308
+ r: factor[0],
309
+ g: factor[1],
310
+ b: factor[2],
311
+ a: factor[3] ?? 1
312
+ }),
313
+ roughness: typeof material?.pbrMetallicRoughness?.roughnessFactor === "number" ? material.pbrMetallicRoughness.roughnessFactor : 0.92,
314
+ metallic: typeof material?.pbrMetallicRoughness?.metallicFactor === "number" ? material.pbrMetallicRoughness.metallicFactor : 0.08,
315
+ emissive: Object.freeze({
316
+ r: emissive[0] ?? 0,
317
+ g: emissive[1] ?? 0,
318
+ b: emissive[2] ?? 0
319
+ })
320
+ });
120
321
  }
121
322
  function computeBounds(positions) {
122
- const min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];
123
- const max = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];
323
+ const min = [
324
+ Number.POSITIVE_INFINITY,
325
+ Number.POSITIVE_INFINITY,
326
+ Number.POSITIVE_INFINITY
327
+ ];
328
+ const max = [
329
+ Number.NEGATIVE_INFINITY,
330
+ Number.NEGATIVE_INFINITY,
331
+ Number.NEGATIVE_INFINITY
332
+ ];
124
333
  for (let index = 0; index < positions.length; index += 3) {
125
334
  min[0] = Math.min(min[0], positions[index]);
126
335
  min[1] = Math.min(min[1], positions[index + 1]);
@@ -129,7 +338,10 @@ function computeBounds(positions) {
129
338
  max[1] = Math.max(max[1], positions[index + 1]);
130
339
  max[2] = Math.max(max[2], positions[index + 2]);
131
340
  }
132
- return { min, max };
341
+ return Object.freeze({
342
+ min: Object.freeze([min[0], min[1], min[2]]),
343
+ max: Object.freeze([max[0], max[1], max[2]])
344
+ });
133
345
  }
134
346
  function resolveBrowserRequestBaseUrl() {
135
347
  if (typeof document !== "undefined" && typeof document.baseURI === "string" && document.baseURI.length > 0) {
@@ -154,16 +366,173 @@ function resolveFetchBaseUrl(requestUrl, responseUrl) {
154
366
  if (browserBaseUrl) {
155
367
  return new URL(requestUrl, browserBaseUrl);
156
368
  }
157
- throw new Error(`Unable to resolve a stable base URL for glTF asset loading: ${String(requestUrl)}`);
369
+ throw new Error(
370
+ `Unable to resolve a stable base URL for glTF asset loading: ${String(requestUrl)}`
371
+ );
158
372
  }
159
373
  }
160
- async function loadGltfModel(url) {
374
+ function createIdentityMatrix() {
375
+ return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
376
+ }
377
+ function multiplyMatrices(a, b) {
378
+ const out = new Array(16).fill(0);
379
+ for (let column = 0; column < 4; column += 1) {
380
+ for (let row = 0; row < 4; row += 1) {
381
+ out[column * 4 + row] = a[0 * 4 + row] * b[column * 4 + 0] + a[1 * 4 + row] * b[column * 4 + 1] + a[2 * 4 + row] * b[column * 4 + 2] + a[3 * 4 + row] * b[column * 4 + 3];
382
+ }
383
+ }
384
+ return out;
385
+ }
386
+ function composeNodeMatrix(node) {
387
+ if (Array.isArray(node.matrix) && node.matrix.length === 16) {
388
+ return [...node.matrix];
389
+ }
390
+ const translation = Array.isArray(node.translation) ? node.translation : [0, 0, 0];
391
+ const rotation = Array.isArray(node.rotation) ? node.rotation : [0, 0, 0, 1];
392
+ const scale = Array.isArray(node.scale) ? node.scale : [1, 1, 1];
393
+ const [x, y, z, w] = rotation;
394
+ const x2 = x + x;
395
+ const y2 = y + y;
396
+ const z2 = z + z;
397
+ const xx = x * x2;
398
+ const xy = x * y2;
399
+ const xz = x * z2;
400
+ const yy = y * y2;
401
+ const yz = y * z2;
402
+ const zz = z * z2;
403
+ const wx = w * x2;
404
+ const wy = w * y2;
405
+ const wz = w * z2;
406
+ return [
407
+ (1 - (yy + zz)) * scale[0],
408
+ (xy + wz) * scale[0],
409
+ (xz - wy) * scale[0],
410
+ 0,
411
+ (xy - wz) * scale[1],
412
+ (1 - (xx + zz)) * scale[1],
413
+ (yz + wx) * scale[1],
414
+ 0,
415
+ (xz + wy) * scale[2],
416
+ (yz - wx) * scale[2],
417
+ (1 - (xx + yy)) * scale[2],
418
+ 0,
419
+ translation[0],
420
+ translation[1],
421
+ translation[2],
422
+ 1
423
+ ];
424
+ }
425
+ function transformPosition(position, matrix) {
426
+ return [
427
+ matrix[0] * position[0] + matrix[4] * position[1] + matrix[8] * position[2] + matrix[12],
428
+ matrix[1] * position[0] + matrix[5] * position[1] + matrix[9] * position[2] + matrix[13],
429
+ matrix[2] * position[0] + matrix[6] * position[1] + matrix[10] * position[2] + matrix[14]
430
+ ];
431
+ }
432
+ function transformNormal(normal, matrix) {
433
+ const transformed = [
434
+ matrix[0] * normal[0] + matrix[4] * normal[1] + matrix[8] * normal[2],
435
+ matrix[1] * normal[0] + matrix[5] * normal[1] + matrix[9] * normal[2],
436
+ matrix[2] * normal[0] + matrix[6] * normal[1] + matrix[10] * normal[2]
437
+ ];
438
+ const length = Math.hypot(transformed[0], transformed[1], transformed[2]) || 1;
439
+ return [transformed[0] / length, transformed[1] / length, transformed[2] / length];
440
+ }
441
+ function collectScenePrimitives(document2, buffers) {
442
+ const scene = document2.scenes?.[document2.scene ?? 0];
443
+ if (!scene || !Array.isArray(scene.nodes) || scene.nodes.length === 0) {
444
+ throw new Error("glTF demo asset must expose a default scene with at least one node.");
445
+ }
446
+ const results = [];
447
+ let modelName = null;
448
+ let physics = null;
449
+ function visit(nodeIndex, parentMatrix) {
450
+ const node = document2.nodes?.[nodeIndex];
451
+ if (!node) {
452
+ throw new Error(`glTF node ${nodeIndex} is missing.`);
453
+ }
454
+ const localMatrix = composeNodeMatrix(node);
455
+ const worldMatrix = multiplyMatrices(parentMatrix, localMatrix);
456
+ if (!modelName && typeof node.name === "string" && node.name.length > 0) {
457
+ modelName = node.name;
458
+ }
459
+ if (!physics && node.extras?.physics && typeof node.extras.physics === "object") {
460
+ physics = Object.freeze({ ...node.extras.physics });
461
+ }
462
+ if (typeof node.mesh === "number") {
463
+ const mesh = document2.meshes?.[node.mesh];
464
+ if (!mesh || !Array.isArray(mesh.primitives)) {
465
+ throw new Error(`glTF mesh ${node.mesh} is missing primitives.`);
466
+ }
467
+ mesh.primitives.forEach((primitive, primitiveIndex) => {
468
+ const positions = readAccessor(document2, primitive.attributes.POSITION, buffers);
469
+ const normals = typeof primitive.attributes.NORMAL === "number" ? readAccessor(document2, primitive.attributes.NORMAL, buffers) : null;
470
+ const colors = typeof primitive.attributes.COLOR_0 === "number" ? readAccessor(document2, primitive.attributes.COLOR_0, buffers) : null;
471
+ const transformedPositions = [];
472
+ const transformedNormals = [];
473
+ for (let index = 0; index < positions.length; index += 3) {
474
+ const point = transformPosition(
475
+ [positions[index], positions[index + 1], positions[index + 2]],
476
+ worldMatrix
477
+ );
478
+ transformedPositions.push(point[0], point[1], point[2]);
479
+ if (normals) {
480
+ const normal = transformNormal(
481
+ [normals[index], normals[index + 1], normals[index + 2]],
482
+ worldMatrix
483
+ );
484
+ transformedNormals.push(normal[0], normal[1], normal[2]);
485
+ }
486
+ }
487
+ const indices = typeof primitive.indices === "number" ? readAccessor(document2, primitive.indices, buffers).map((value) => Number(value)) : Array.from({ length: transformedPositions.length / 3 }, (_, index) => index);
488
+ const material = getMaterialInfo(document2, primitive);
489
+ const primitiveName = `${node.name ?? mesh.name ?? "mesh"}-${primitiveIndex}`;
490
+ results.push(
491
+ Object.freeze({
492
+ name: primitiveName,
493
+ positions: Object.freeze(transformedPositions),
494
+ indices: Object.freeze(indices),
495
+ normals: transformedNormals.length > 0 ? Object.freeze(transformedNormals) : null,
496
+ colors: colors ? Object.freeze(colors) : null,
497
+ material,
498
+ bounds: computeBounds(transformedPositions)
499
+ })
500
+ );
501
+ });
502
+ }
503
+ if (Array.isArray(node.children)) {
504
+ for (const childIndex of node.children) {
505
+ visit(childIndex, worldMatrix);
506
+ }
507
+ }
508
+ }
509
+ for (const rootNodeIndex of scene.nodes) {
510
+ visit(rootNodeIndex, createIdentityMatrix());
511
+ }
512
+ if (results.length === 0) {
513
+ throw new Error("glTF demo asset must contain at least one mesh primitive.");
514
+ }
515
+ return {
516
+ name: modelName ?? "gltf-model",
517
+ physics: physics ?? Object.freeze({}),
518
+ primitives: results
519
+ };
520
+ }
521
+ async function loadGltfDocument(url) {
161
522
  const response = await fetch(url);
162
523
  if (!response.ok) {
163
524
  throw new Error(`Failed to load glTF asset: ${response.status} ${response.statusText}`);
164
525
  }
165
- const document2 = await response.json();
166
- const baseUrl2 = resolveFetchBaseUrl(url, response.url);
526
+ return {
527
+ document: await response.json(),
528
+ baseUrl: resolveFetchBaseUrl(url, response.url)
529
+ };
530
+ }
531
+ async function loadInlineShowcaseDocument() {
532
+ const module2 = await Promise.resolve().then(() => (init_showcase_inline_assets(), showcase_inline_assets_exports));
533
+ return loadGltfDocument(new URL(module2.INLINE_SHOWCASE_ASSET_URLS.brigantine));
534
+ }
535
+ async function buildGltfModel(document2, baseUrl2) {
167
536
  const buffers = await Promise.all(
168
537
  (document2.buffers ?? []).map(async (buffer) => {
169
538
  if (typeof buffer.uri !== "string") {
@@ -179,26 +548,46 @@ async function loadGltfModel(url) {
179
548
  return nested.arrayBuffer();
180
549
  })
181
550
  );
182
- const scene = document2.scenes?.[document2.scene ?? 0];
183
- if (!scene || !Array.isArray(scene.nodes) || scene.nodes.length === 0) {
184
- throw new Error("glTF demo asset must expose a default scene with at least one node.");
185
- }
186
- const node = document2.nodes[scene.nodes[0]];
187
- const mesh = document2.meshes[node.mesh];
188
- const primitive = mesh.primitives[0];
189
- const positions = Array.from(readAccessor(document2, primitive.attributes.POSITION, buffers));
190
- const indices = Array.from(readAccessor(document2, primitive.indices, buffers));
551
+ const scene = collectScenePrimitives(document2, buffers);
552
+ const aggregatePositions = [];
553
+ const aggregateIndices = [];
554
+ for (const primitive of scene.primitives) {
555
+ const vertexOffset = aggregatePositions.length / 3;
556
+ aggregatePositions.push(...primitive.positions);
557
+ aggregateIndices.push(...primitive.indices.map((index) => index + vertexOffset));
558
+ }
559
+ const color = scene.primitives[0]?.material?.color ?? { r: 0.56, g: 0.33, b: 0.22, a: 1 };
191
560
  return Object.freeze({
192
- name: node.name ?? mesh.name ?? "gltf-model",
193
- positions,
194
- indices,
195
- bounds: computeBounds(positions),
196
- color: getMaterialColor(document2, primitive),
197
- physics: Object.freeze({ ...node.extras?.physics ?? {} })
561
+ name: scene.name,
562
+ positions: Object.freeze(aggregatePositions),
563
+ indices: Object.freeze(aggregateIndices),
564
+ bounds: computeBounds(aggregatePositions),
565
+ color: Object.freeze({ ...color }),
566
+ physics: scene.physics,
567
+ primitives: Object.freeze(scene.primitives)
198
568
  });
199
569
  }
570
+ function shouldRetryWithInlineShowcaseFallback(url, error) {
571
+ if (!shouldUseInlineShowcaseFallback(url)) {
572
+ return false;
573
+ }
574
+ return error instanceof TypeError || /^Failed to load glTF asset:/u.test(error.message);
575
+ }
576
+ async function loadGltfModel(url) {
577
+ try {
578
+ const { document: document2, baseUrl: baseUrl2 } = await loadGltfDocument(url);
579
+ return buildGltfModel(document2, baseUrl2);
580
+ } catch (error) {
581
+ if (!shouldRetryWithInlineShowcaseFallback(url, error)) {
582
+ throw error;
583
+ }
584
+ const { document: document2, baseUrl: baseUrl2 } = await loadInlineShowcaseDocument();
585
+ return buildGltfModel(document2, baseUrl2);
586
+ }
587
+ }
200
588
  var init_gltf_loader = __esm({
201
589
  "src/gltf-loader.js"() {
590
+ init_asset_url();
202
591
  }
203
592
  });
204
593
 
@@ -2519,7 +2908,7 @@ function getLightingProfile(name = defaultLightingProfile) {
2519
2908
  }
2520
2909
  return profile;
2521
2910
  }
2522
- var import_meta2, __require, baseUrl, techniqueSpecs, lightingTechniques, lightingTechniqueNames, defaultLightingTechnique, profileSpecs, lightingProfiles, lightingProfileNames, defaultLightingProfile, lightingDistanceBands, lightingWorkerQueueClass, lightingDebugOwner, lightingImportanceLevels, lightingBandPolicySpecs, lightingWorkerSpecPresets, lightingWorkerDagSpecs, lightingWorkerManifests, defaultTechnique, lightingPreludeWgslUrl, lightingJobLabels, lightingJobs;
2911
+ var import_meta2, __require, baseUrl, techniqueSpecs, lightingTechniques, lightingTechniqueNames, defaultLightingTechnique, profileSpecs, lightingProfiles, lightingProfileNames, defaultLightingProfile, lightingProfileModeOrder, defaultAdaptiveLightingProfilePolicy, lightingDistanceBands, lightingWorkerQueueClass, lightingDebugOwner, lightingImportanceLevels, lightingBandPolicySpecs, lightingProfileModeEstimatedCostMs, lightingWorkerSpecPresets, lightingWorkerDagSpecs, lightingWorkerManifests, defaultTechnique, lightingPreludeWgslUrl, lightingJobLabels, lightingJobs;
2523
2912
  var init_dist3 = __esm({
2524
2913
  "node_modules/@plasius/gpu-lighting/dist/index.js"() {
2525
2914
  import_meta2 = {};
@@ -2613,6 +3002,16 @@ var init_dist3 = __esm({
2613
3002
  );
2614
3003
  lightingProfileNames = Object.freeze(Object.keys(lightingProfiles));
2615
3004
  defaultLightingProfile = "realtime";
3005
+ lightingProfileModeOrder = Object.freeze([
3006
+ "realtime",
3007
+ "hybrid",
3008
+ "reference"
3009
+ ]);
3010
+ defaultAdaptiveLightingProfilePolicy = Object.freeze({
3011
+ preferredProfile: "reference",
3012
+ minimumFrameRate: 30,
3013
+ sampleWindowSize: 4
3014
+ });
2616
3015
  lightingDistanceBands = Object.freeze([
2617
3016
  "near",
2618
3017
  "mid",
@@ -2668,6 +3067,11 @@ var init_dist3 = __esm({
2668
3067
  impressionOnly: true
2669
3068
  })
2670
3069
  });
3070
+ lightingProfileModeEstimatedCostMs = Object.freeze({
3071
+ realtime: 4.5,
3072
+ hybrid: 7.5,
3073
+ reference: 12.5
3074
+ });
2671
3075
  lightingWorkerSpecPresets = {
2672
3076
  hybrid: {
2673
3077
  suggestedAllocationIds: [
@@ -6339,10 +6743,19 @@ var init_browser = __esm({
6339
6743
  }
6340
6744
  });
6341
6745
 
6746
+ // src/feature-flags.js
6747
+ var GPU_SHOWCASE_REALISTIC_MODELS_FEATURE;
6748
+ var init_feature_flags = __esm({
6749
+ "src/feature-flags.js"() {
6750
+ GPU_SHOWCASE_REALISTIC_MODELS_FEATURE = "gpu_showcase_realistic_models_v1";
6751
+ }
6752
+ });
6753
+
6342
6754
  // src/showcase-runtime.js
6343
6755
  var showcase_runtime_exports = {};
6344
6756
  __export(showcase_runtime_exports, {
6345
6757
  __testOnlyAdvanceShowcaseClothSimulationState: () => advanceShowcaseClothSimulationState,
6758
+ __testOnlyBuildWaterBands: () => buildWaterBands,
6346
6759
  __testOnlyBuildWaterMotionEffects: () => buildWaterMotionEffects,
6347
6760
  __testOnlyCollectSceneLightSources: () => collectSceneLightSources,
6348
6761
  __testOnlyCreateShowcaseClothSimulationState: () => createShowcaseClothSimulationState,
@@ -6374,6 +6787,11 @@ function injectStyles() {
6374
6787
  radial-gradient(circle at 82% 18%, rgba(240, 188, 103, 0.08), transparent 18%),
6375
6788
  linear-gradient(180deg, #04101d 0%, #0b1930 42%, #081321 100%);
6376
6789
  }
6790
+ .${ROOT_CLASS}.${CAPTURE_CLASS} {
6791
+ min-height: 100vh;
6792
+ overflow: hidden;
6793
+ background: #030710;
6794
+ }
6377
6795
  .${ROOT_CLASS},
6378
6796
  .${ROOT_CLASS} * {
6379
6797
  box-sizing: border-box;
@@ -6453,6 +6871,40 @@ function injectStyles() {
6453
6871
  border: 1px solid rgba(159, 185, 223, 0.12);
6454
6872
  background: linear-gradient(180deg, #071220 0%, #132440 42%, #10344b 42%, #05111d 100%);
6455
6873
  }
6874
+ .${CAPTURE_CLASS} .plasius-demo {
6875
+ width: 100vw;
6876
+ height: 100vh;
6877
+ padding: 0;
6878
+ display: block;
6879
+ }
6880
+ .${CAPTURE_CLASS} .plasius-demo__hero,
6881
+ .${CAPTURE_CLASS} .plasius-demo__toolbar,
6882
+ .${CAPTURE_CLASS} .plasius-demo__legend,
6883
+ .${CAPTURE_CLASS} .plasius-demo__sidebar,
6884
+ .${CAPTURE_CLASS} .plasius-demo__footer {
6885
+ display: none;
6886
+ }
6887
+ .${CAPTURE_CLASS} .plasius-demo__layout {
6888
+ display: block;
6889
+ height: 100%;
6890
+ }
6891
+ .${CAPTURE_CLASS} .plasius-demo__canvas-panel {
6892
+ height: 100%;
6893
+ padding: 0;
6894
+ border: 0;
6895
+ border-radius: 0;
6896
+ background: transparent;
6897
+ box-shadow: none;
6898
+ backdrop-filter: none;
6899
+ }
6900
+ .${CAPTURE_CLASS} .plasius-demo__canvas {
6901
+ width: 100%;
6902
+ height: 100%;
6903
+ aspect-ratio: auto;
6904
+ border: 0;
6905
+ border-radius: 0;
6906
+ background: #030710;
6907
+ }
6456
6908
  .plasius-demo__toolbar {
6457
6909
  position: absolute;
6458
6910
  top: 26px;
@@ -6544,6 +6996,10 @@ function clamp(value, min, max) {
6544
6996
  function mix(a, b, t) {
6545
6997
  return a + (b - a) * t;
6546
6998
  }
6999
+ function smoothstep(min, max, value) {
7000
+ const t = clamp((value - min) / Math.max(1e-4, max - min), 0, 1);
7001
+ return t * t * (3 - 2 * t);
7002
+ }
6547
7003
  function pseudoRandom(seed) {
6548
7004
  const value = Math.sin(seed * 12.9898 + seed * seed * 17e-4) * 43758.5453;
6549
7005
  return value - Math.floor(value);
@@ -6602,6 +7058,11 @@ function transformPoint(point, transform) {
6602
7058
  const rotated = rotateY(scaled, transform.rotationY);
6603
7059
  return addVec3(rotated, transform.position);
6604
7060
  }
7061
+ function transformDirection(direction, transform) {
7062
+ const scale = typeof transform.scale === "number" ? { x: transform.scale, y: transform.scale, z: transform.scale } : transform.scale;
7063
+ const scaled = vec3(direction.x * scale.x, direction.y * scale.y, direction.z * scale.z);
7064
+ return normalizeVec3(rotateY(scaled, transform.rotationY));
7065
+ }
6605
7066
  function projectPoint(point, camera, viewport) {
6606
7067
  const relative = subVec3(point, camera.eye);
6607
7068
  const viewX = dotVec3(relative, camera.right);
@@ -6625,6 +7086,66 @@ function colorToRgba(color, alpha = 1) {
6625
7086
  const b = Math.round(clamp(color.b, 0, 1) * 255);
6626
7087
  return `rgba(${r}, ${g}, ${b}, ${clamp(alpha, 0, 1)})`;
6627
7088
  }
7089
+ function mixColor(a, b, t) {
7090
+ return {
7091
+ r: mix(a.r, b.r, t),
7092
+ g: mix(a.g, b.g, t),
7093
+ b: mix(a.b, b.b, t),
7094
+ a: mix(a.a ?? 1, b.a ?? 1, t)
7095
+ };
7096
+ }
7097
+ function multiplyColor(a, b) {
7098
+ return {
7099
+ r: a.r * b.r,
7100
+ g: a.g * b.g,
7101
+ b: a.b * b.b,
7102
+ a: (a.a ?? 1) * (b.a ?? 1)
7103
+ };
7104
+ }
7105
+ function createLegacyMeshPrimitive(mesh) {
7106
+ return Object.freeze({
7107
+ name: mesh.name ?? "legacy-mesh",
7108
+ positions: mesh.positions,
7109
+ indices: mesh.indices,
7110
+ normals: null,
7111
+ colors: null,
7112
+ material: Object.freeze({
7113
+ name: "legacy-material",
7114
+ color: mesh.color ?? { r: 0.56, g: 0.33, b: 0.22, a: 1 },
7115
+ roughness: 0.88,
7116
+ metallic: 0.08,
7117
+ emissive: Object.freeze({ r: 0, g: 0, b: 0 })
7118
+ })
7119
+ });
7120
+ }
7121
+ function isFeatureEnabled(featureFlags, featureName, fallback = true) {
7122
+ const directValue = typeof featureFlags?.[featureName] === "boolean" ? featureFlags[featureName] : featureFlags?.flags?.[featureName];
7123
+ if (typeof directValue === "boolean") {
7124
+ return directValue;
7125
+ }
7126
+ const enabledValue = typeof featureFlags?.enabled?.[featureName] === "boolean" ? featureFlags.enabled[featureName] : void 0;
7127
+ if (typeof enabledValue === "boolean") {
7128
+ return enabledValue;
7129
+ }
7130
+ return fallback;
7131
+ }
7132
+ function getMeshPrimitives(mesh) {
7133
+ return Array.isArray(mesh?.primitives) && mesh.primitives.length > 0 ? mesh.primitives : [createLegacyMeshPrimitive(mesh)];
7134
+ }
7135
+ function tintPrimitiveColor(material, colorOverride) {
7136
+ if (!colorOverride) {
7137
+ return material.color;
7138
+ }
7139
+ const name = String(material.name ?? "").toLowerCase();
7140
+ if (name.includes("sail") || name.includes("glass") || name.includes("roof")) {
7141
+ return material.color;
7142
+ }
7143
+ const tintAmount = name.includes("hull") ? 0.54 : name.includes("trim") ? 0.22 : name.includes("deck") ? 0.12 : 0;
7144
+ if (tintAmount <= 0) {
7145
+ return material.color;
7146
+ }
7147
+ return mixColor(material.color, multiplyColor(material.color, colorOverride), tintAmount);
7148
+ }
6628
7149
  function projectShadowPoint(point, lightDir, planeY) {
6629
7150
  const shadowDir = scaleVec3(lightDir, -1);
6630
7151
  if (Math.abs(shadowDir.y) < 1e-4) {
@@ -6645,6 +7166,50 @@ function shadeColor(base, normal, lightDir, heightBias = 0, accent = 0) {
6645
7166
  b: clamp(base.b * (brightness + 0.03), 0, 1)
6646
7167
  };
6647
7168
  }
7169
+ function getMaterialSeed(materialName) {
7170
+ let seed = 0;
7171
+ for (let index = 0; index < materialName.length; index += 1) {
7172
+ seed += materialName.charCodeAt(index) * (index + 1);
7173
+ }
7174
+ return seed;
7175
+ }
7176
+ function getMaterialDetailStrength(material, surfaceType) {
7177
+ const name = String(material?.name ?? "").toLowerCase();
7178
+ if (surfaceType === "water" || name.includes("glass")) {
7179
+ return 0.018;
7180
+ }
7181
+ if (name.includes("wood") || name.includes("timber") || name.includes("plank")) {
7182
+ return 0.13;
7183
+ }
7184
+ if (name.includes("stone") || name.includes("concrete") || name.includes("plaster")) {
7185
+ return 0.1;
7186
+ }
7187
+ if (name.includes("roof") || name.includes("crate")) {
7188
+ return 0.09;
7189
+ }
7190
+ if (name.includes("paint")) {
7191
+ return 0.045;
7192
+ }
7193
+ if (name.includes("metal")) {
7194
+ return 0.035;
7195
+ }
7196
+ return 0.04;
7197
+ }
7198
+ function applyMaterialDetail(color, material, worldCenter, normal, surfaceType) {
7199
+ const materialName = String(material?.name ?? surfaceType ?? "material");
7200
+ const detailStrength = getMaterialDetailStrength(material, surfaceType);
7201
+ const sample = worldCenter.x * 3.17 + worldCenter.y * 5.29 + worldCenter.z * 7.83 + getMaterialSeed(materialName) * 0.013;
7202
+ const grain = (pseudoRandom(sample) - 0.5) * detailStrength;
7203
+ const lowerSurface = smoothstep(7.5, -0.8, worldCenter.y);
7204
+ const verticalSurface = 1 - clamp(Math.abs(normal.y), 0, 1);
7205
+ const materialLowerWear = /stone|concrete|plaster|paint|wood|timber|plank|crate/.test(materialName.toLowerCase()) ? lowerSurface * verticalSurface * 0.055 : 0;
7206
+ const wetlineWear = surfaceType === "ship" && worldCenter.y < 0.72 ? smoothstep(0.72, -0.1, worldCenter.y) * 0.05 : 0;
7207
+ return {
7208
+ r: clamp(color.r * (1 + grain) - materialLowerWear - wetlineWear, 0, 1),
7209
+ g: clamp(color.g * (1 + grain * 0.82) - materialLowerWear * 0.9 - wetlineWear, 0, 1),
7210
+ b: clamp(color.b * (1 + grain * 0.62) - materialLowerWear * 0.68 - wetlineWear * 0.75, 0, 1)
7211
+ };
7212
+ }
6648
7213
  function buildCamera(state, canvas) {
6649
7214
  const preset = CAMERA_PRESETS[state.focus] ?? CAMERA_PRESETS.integrated;
6650
7215
  const yaw = state.camera.yaw ?? preset.yaw;
@@ -6669,44 +7234,131 @@ function buildCamera(state, canvas) {
6669
7234
  aspect: canvas.width / canvas.height
6670
7235
  };
6671
7236
  }
6672
- function buildTrianglesFromMesh(mesh, transform, baseColor, camera, viewport, triangles, accent = 0) {
6673
- for (let index = 0; index < mesh.indices.length; index += 3) {
6674
- const aIndex = mesh.indices[index] * 3;
6675
- const bIndex = mesh.indices[index + 1] * 3;
6676
- const cIndex = mesh.indices[index + 2] * 3;
6677
- const a = transformPoint(
6678
- vec3(mesh.positions[aIndex], mesh.positions[aIndex + 1], mesh.positions[aIndex + 2]),
6679
- transform
6680
- );
6681
- const b = transformPoint(
6682
- vec3(mesh.positions[bIndex], mesh.positions[bIndex + 1], mesh.positions[bIndex + 2]),
6683
- transform
6684
- );
6685
- const c = transformPoint(
6686
- vec3(mesh.positions[cIndex], mesh.positions[cIndex + 1], mesh.positions[cIndex + 2]),
6687
- transform
6688
- );
6689
- const ab = subVec3(b, a);
6690
- const ac = subVec3(c, a);
6691
- const normal = normalizeVec3(crossVec3(ab, ac));
6692
- const viewDir = normalizeVec3(subVec3(camera.eye, a));
6693
- if (dotVec3(normal, viewDir) <= 0) {
6694
- continue;
6695
- }
6696
- const projected = [projectPoint(a, camera, viewport), projectPoint(b, camera, viewport), projectPoint(c, camera, viewport)];
6697
- if (projected.some((value) => value === null)) {
6698
- continue;
7237
+ function buildTrianglesFromMesh(mesh, transform, colorOverride, camera, viewport, triangles, options = {}) {
7238
+ const primitives = getMeshPrimitives(mesh);
7239
+ for (const primitive of primitives) {
7240
+ const resolvedColor = tintPrimitiveColor(primitive.material, colorOverride);
7241
+ for (let index = 0; index < primitive.indices.length; index += 3) {
7242
+ const aIndex = primitive.indices[index] * 3;
7243
+ const bIndex = primitive.indices[index + 1] * 3;
7244
+ const cIndex = primitive.indices[index + 2] * 3;
7245
+ const a = transformPoint(
7246
+ vec3(
7247
+ primitive.positions[aIndex],
7248
+ primitive.positions[aIndex + 1],
7249
+ primitive.positions[aIndex + 2]
7250
+ ),
7251
+ transform
7252
+ );
7253
+ const b = transformPoint(
7254
+ vec3(
7255
+ primitive.positions[bIndex],
7256
+ primitive.positions[bIndex + 1],
7257
+ primitive.positions[bIndex + 2]
7258
+ ),
7259
+ transform
7260
+ );
7261
+ const c = transformPoint(
7262
+ vec3(
7263
+ primitive.positions[cIndex],
7264
+ primitive.positions[cIndex + 1],
7265
+ primitive.positions[cIndex + 2]
7266
+ ),
7267
+ transform
7268
+ );
7269
+ const ab = subVec3(b, a);
7270
+ const ac = subVec3(c, a);
7271
+ const faceNormal = normalizeVec3(crossVec3(ab, ac));
7272
+ let normal = faceNormal;
7273
+ if (Array.isArray(primitive.normals)) {
7274
+ const aNormal = transformDirection(
7275
+ vec3(
7276
+ primitive.normals[aIndex],
7277
+ primitive.normals[aIndex + 1],
7278
+ primitive.normals[aIndex + 2]
7279
+ ),
7280
+ transform
7281
+ );
7282
+ const bNormal = transformDirection(
7283
+ vec3(
7284
+ primitive.normals[bIndex],
7285
+ primitive.normals[bIndex + 1],
7286
+ primitive.normals[bIndex + 2]
7287
+ ),
7288
+ transform
7289
+ );
7290
+ const cNormal = transformDirection(
7291
+ vec3(
7292
+ primitive.normals[cIndex],
7293
+ primitive.normals[cIndex + 1],
7294
+ primitive.normals[cIndex + 2]
7295
+ ),
7296
+ transform
7297
+ );
7298
+ normal = normalizeVec3(
7299
+ scaleVec3(addVec3(addVec3(aNormal, bNormal), cNormal), 1 / 3)
7300
+ );
7301
+ }
7302
+ const viewDir = normalizeVec3(subVec3(camera.eye, a));
7303
+ if (dotVec3(faceNormal, viewDir) <= 0) {
7304
+ continue;
7305
+ }
7306
+ const projected = [
7307
+ projectPoint(a, camera, viewport),
7308
+ projectPoint(b, camera, viewport),
7309
+ projectPoint(c, camera, viewport)
7310
+ ];
7311
+ if (projected.some((value) => value === null)) {
7312
+ continue;
7313
+ }
7314
+ triangles.push({
7315
+ points: projected,
7316
+ depth: (projected[0].depth + projected[1].depth + projected[2].depth) / 3,
7317
+ worldCenter: scaleVec3(addVec3(addVec3(a, b), c), 1 / 3),
7318
+ normal,
7319
+ baseColor: resolvedColor,
7320
+ accent: options.accent ?? 0,
7321
+ material: primitive.material,
7322
+ reflection: options.reflection ?? 0,
7323
+ surfaceType: options.surfaceType ?? "solid"
7324
+ });
6699
7325
  }
6700
- triangles.push({
6701
- points: projected,
6702
- depth: (projected[0].depth + projected[1].depth + projected[2].depth) / 3,
6703
- worldCenter: scaleVec3(addVec3(addVec3(a, b), c), 1 / 3),
6704
- normal,
6705
- baseColor,
6706
- accent
6707
- });
6708
7326
  }
6709
7327
  }
7328
+ async function loadShowcaseAssetCatalog() {
7329
+ const [brigantine, cutter, lighthouse, harborDock] = await Promise.all([
7330
+ loadGltfModel(resolveShowcaseAssetUrl("brigantine")),
7331
+ loadGltfModel(resolveShowcaseAssetUrl("cutter")),
7332
+ loadGltfModel(resolveShowcaseAssetUrl("lighthouse")),
7333
+ loadGltfModel(resolveShowcaseAssetUrl("harbor-dock"))
7334
+ ]);
7335
+ return Object.freeze({
7336
+ primaryShipKey: "brigantine",
7337
+ ships: Object.freeze({
7338
+ brigantine,
7339
+ cutter
7340
+ }),
7341
+ environment: Object.freeze({
7342
+ lighthouse,
7343
+ "harbor-dock": harborDock
7344
+ })
7345
+ });
7346
+ }
7347
+ function createLegacyShowcaseAssetCatalog() {
7348
+ const brigantine = loadGltfModel(resolveShowcaseAssetUrl("brigantine"));
7349
+ return Promise.resolve(brigantine).then(
7350
+ (primary) => Object.freeze({
7351
+ primaryShipKey: "brigantine",
7352
+ ships: Object.freeze({
7353
+ brigantine: primary
7354
+ }),
7355
+ environment: Object.freeze({})
7356
+ })
7357
+ );
7358
+ }
7359
+ function resolveShipModel(state, ship, fallbackModel = null) {
7360
+ return state.assetCatalog?.ships?.[ship.modelKey ?? state.assetCatalog?.primaryShipKey ?? "brigantine"] ?? fallbackModel ?? state.shipModel;
7361
+ }
6710
7362
  function createPerformanceGovernor() {
6711
7363
  const fluidDetail = createQualityLadderAdapter({
6712
7364
  id: "fluid-detail",
@@ -6758,6 +7410,7 @@ function createPerformanceGovernor() {
6758
7410
  return { governor, fluidDetail, clothDetail, lightingDetail };
6759
7411
  }
6760
7412
  function buildDemoDom(root, options) {
7413
+ const t = options.translate;
6761
7414
  root.innerHTML = `
6762
7415
  <main class="plasius-demo">
6763
7416
  <section class="plasius-demo__hero">
@@ -6767,56 +7420,52 @@ function buildDemoDom(root, options) {
6767
7420
  <p class="plasius-demo__lead">${options.subtitle}</p>
6768
7421
  </section>
6769
7422
  <section class="plasius-panel plasius-demo__status">
6770
- <p id="demoStatus" class="plasius-demo__status-badge">Booting 3D scene\u2026</p>
7423
+ <p id="demoStatus" class="plasius-demo__status-badge">${t(gpuSharedTranslationKeys.statusBooting)}</p>
6771
7424
  <p id="demoDetails" class="plasius-demo__status-text">
6772
- Preparing a moonlit harbor scene, GLTF hull data, cloth and fluid continuity plans, and adaptive quality metadata.
7425
+ ${t(gpuSharedTranslationKeys.detailsBooting)}
6773
7426
  </p>
6774
7427
  </section>
6775
7428
  </section>
6776
7429
  <section class="plasius-demo__layout">
6777
7430
  <section class="plasius-panel plasius-demo__canvas-panel">
6778
- <canvas id="demoCanvas" class="plasius-demo__canvas" width="1280" height="720"></canvas>
7431
+ <canvas id="demoCanvas" class="plasius-demo__canvas" width="${DEFAULT_CANVAS_WIDTH}" height="${DEFAULT_CANVAS_HEIGHT}"></canvas>
6779
7432
  <div class="plasius-demo__toolbar">
6780
- <button id="pauseButton" type="button">Pause</button>
7433
+ <button id="pauseButton" type="button">${t(gpuSharedTranslationKeys.pause)}</button>
6781
7434
  <label class="plasius-toggle">
6782
7435
  <input id="stressToggle" type="checkbox" />
6783
- Stress mode
7436
+ ${t(gpuSharedTranslationKeys.stressMode)}
6784
7437
  </label>
6785
7438
  <label class="plasius-toggle">
6786
- Focus
7439
+ ${t(gpuSharedTranslationKeys.focus)}
6787
7440
  <select id="focusMode">
6788
- <option value="integrated">integrated</option>
6789
- <option value="lighting">lighting</option>
6790
- <option value="cloth">cloth</option>
6791
- <option value="fluid">fluid</option>
6792
- <option value="physics">physics</option>
6793
- <option value="performance">performance</option>
6794
- <option value="debug">debug</option>
7441
+ ${showcaseFocusModes.map(
7442
+ (mode) => `<option value="${mode}">${t(FOCUS_MODE_TRANSLATION_KEYS[mode])}</option>`
7443
+ ).join("")}
6795
7444
  </select>
6796
7445
  </label>
6797
7446
  </div>
6798
7447
  <div class="plasius-demo__legend">
6799
- <strong>Scene</strong>
6800
- GLTF ships carry hull mass and damping metadata.<br />
6801
- Lanterns and torches warm the moonlit harbor.<br />
6802
- Mass-aware collisions stay authoritative near the camera.
7448
+ <strong>${t(gpuSharedTranslationKeys.legendTitle)}</strong>
7449
+ ${t(gpuSharedTranslationKeys.legendShipMetadata)}<br />
7450
+ ${t(gpuSharedTranslationKeys.legendLighting)}<br />
7451
+ ${t(gpuSharedTranslationKeys.legendCollisions)}
6803
7452
  </div>
6804
7453
  </section>
6805
7454
  <aside class="plasius-demo__sidebar">
6806
7455
  <section class="plasius-panel plasius-demo__card">
6807
- <h2>Scene State</h2>
7456
+ <h2>${t(gpuSharedTranslationKeys.sceneState)}</h2>
6808
7457
  <ul id="sceneMetrics" class="plasius-demo__metrics"></ul>
6809
7458
  </section>
6810
7459
  <section class="plasius-panel plasius-demo__card">
6811
- <h2>Quality + Budgets</h2>
7460
+ <h2>${t(gpuSharedTranslationKeys.qualityBudgets)}</h2>
6812
7461
  <ul id="qualityMetrics" class="plasius-demo__metrics"></ul>
6813
7462
  </section>
6814
7463
  <section class="plasius-panel plasius-demo__card">
6815
- <h2>Debug Telemetry</h2>
7464
+ <h2>${t(gpuSharedTranslationKeys.debugTelemetry)}</h2>
6816
7465
  <ul id="debugMetrics" class="plasius-demo__metrics"></ul>
6817
7466
  </section>
6818
7467
  <section class="plasius-panel plasius-demo__card">
6819
- <h2>Notes</h2>
7468
+ <h2>${t(gpuSharedTranslationKeys.notes)}</h2>
6820
7469
  <ul id="sceneNotes" class="plasius-demo__metrics"></ul>
6821
7470
  </section>
6822
7471
  </aside>
@@ -6840,6 +7489,11 @@ function buildDemoDom(root, options) {
6840
7489
  };
6841
7490
  }
6842
7491
  function buildSceneSnapshot(state, shipModel) {
7492
+ const shipPhysics = Object.freeze(
7493
+ Object.fromEntries(
7494
+ state.ships.map((ship) => [ship.id, resolveShipModel(state, ship, shipModel)?.physics ?? null])
7495
+ )
7496
+ );
6843
7497
  return Object.freeze({
6844
7498
  focus: state.focus,
6845
7499
  frame: state.frame,
@@ -6861,6 +7515,7 @@ function buildSceneSnapshot(state, shipModel) {
6861
7515
  state.ships.map(
6862
7516
  (ship) => Object.freeze({
6863
7517
  id: ship.id,
7518
+ modelKey: ship.modelKey ?? "brigantine",
6864
7519
  position: Object.freeze({ ...ship.position }),
6865
7520
  velocity: Object.freeze({ ...ship.velocity }),
6866
7521
  rotationY: ship.rotationY,
@@ -6881,12 +7536,13 @@ function buildSceneSnapshot(state, shipModel) {
6881
7536
  )
6882
7537
  ),
6883
7538
  shipPhysics: shipModel?.physics ?? null,
7539
+ shipModels: shipPhysics,
6884
7540
  physics: Object.freeze({
6885
7541
  profile: state.physics.profile,
6886
7542
  plan: state.physics.plan,
6887
7543
  manifest: state.physics.manifest,
6888
7544
  snapshot: state.physics.snapshot,
6889
- shipPhysics: shipModel?.physics ?? null
7545
+ shipPhysics
6890
7546
  })
6891
7547
  });
6892
7548
  }
@@ -6921,6 +7577,61 @@ function normalizeColorOverride(color, fallback) {
6921
7577
  function readVisualNumber(value, fallback) {
6922
7578
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
6923
7579
  }
7580
+ function readPositiveNumber3(value, fallback) {
7581
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
7582
+ }
7583
+ function isTruthyCaptureValue(value) {
7584
+ return value === "1" || value === "true" || value === "scene" || value === "video";
7585
+ }
7586
+ function resolveCaptureSettings(options) {
7587
+ const explicitCaptureMode = typeof options.captureMode === "boolean" ? options.captureMode : void 0;
7588
+ let captureMode = explicitCaptureMode ?? false;
7589
+ let renderScale = readPositiveNumber3(options.renderScale, void 0);
7590
+ try {
7591
+ const params = new URLSearchParams(window.location.search);
7592
+ if (explicitCaptureMode === void 0) {
7593
+ captureMode = isTruthyCaptureValue(params.get("capture")) || params.get("presentation") === "capture";
7594
+ }
7595
+ renderScale = readPositiveNumber3(Number(params.get("renderScale")), renderScale);
7596
+ } catch {
7597
+ }
7598
+ return {
7599
+ captureMode,
7600
+ renderScale
7601
+ };
7602
+ }
7603
+ function getCanvasDisplaySize(canvas) {
7604
+ const rect = typeof canvas.getBoundingClientRect === "function" ? canvas.getBoundingClientRect() : null;
7605
+ const width = Math.round(
7606
+ readPositiveNumber3(rect?.width, readPositiveNumber3(canvas.clientWidth, canvas.width))
7607
+ );
7608
+ const height = Math.round(
7609
+ readPositiveNumber3(rect?.height, readPositiveNumber3(canvas.clientHeight, canvas.height))
7610
+ );
7611
+ return {
7612
+ width: Math.max(1, width || DEFAULT_CANVAS_WIDTH),
7613
+ height: Math.max(1, height || DEFAULT_CANVAS_HEIGHT)
7614
+ };
7615
+ }
7616
+ function resizeCanvasToDisplaySize(canvas, state) {
7617
+ const { width, height } = getCanvasDisplaySize(canvas);
7618
+ const deviceScale = readPositiveNumber3(globalThis.devicePixelRatio, 1);
7619
+ const requestedScale = readPositiveNumber3(state.renderScale, deviceScale);
7620
+ const maxScale = state.captureMode ? 2 : 1.5;
7621
+ let scale = clamp(requestedScale, 1, maxScale);
7622
+ const pixelBudget = state.captureMode ? CAPTURE_CANVAS_PIXEL_BUDGET : DEFAULT_CANVAS_WIDTH * DEFAULT_CANVAS_HEIGHT * 1.5;
7623
+ const projectedPixels = width * height * scale * scale;
7624
+ if (projectedPixels > pixelBudget) {
7625
+ scale = Math.sqrt(pixelBudget / Math.max(1, width * height));
7626
+ }
7627
+ const targetWidth = Math.max(1, Math.round(width * scale));
7628
+ const targetHeight = Math.max(1, Math.round(height * scale));
7629
+ if (canvas.width !== targetWidth || canvas.height !== targetHeight) {
7630
+ canvas.width = targetWidth;
7631
+ canvas.height = targetHeight;
7632
+ }
7633
+ state.renderScale = scale;
7634
+ }
6924
7635
  function resolveClothPresentation(state, meshDetail) {
6925
7636
  const clothPlan = createClothRepresentationPlan({
6926
7637
  garmentId: "shore-flag",
@@ -7322,6 +8033,12 @@ function sampleWave(state, x, z, time) {
7322
8033
  const base = Math.sin(along * 0.22 - time * 1.12 * phaseSpeed) * 0.42 + Math.cos(along * 0.11 + cross * 0.07 - time * 0.78 * phaseSpeed) * 0.26 + Math.sin(cross * 0.19 - time * 1.34 * phaseSpeed) * 0.16;
7323
8034
  return base * amplitude + sampleShipWake(state, x, z, time) + sampleWaveImpulses(state, x, z, time);
7324
8035
  }
8036
+ function resolveFluidBandContinuity(continuity, band) {
8037
+ if (continuity?.bands && continuity.bands[band]) {
8038
+ return continuity.bands[band];
8039
+ }
8040
+ return continuity ?? { amplitudeFloor: 1, frequencyFloor: 1 };
8041
+ }
7325
8042
  function buildWaterMotionEffects(state) {
7326
8043
  const wakeTrails = [];
7327
8044
  const rippleRings = state.waveImpulses.map((impulse) => {
@@ -7395,6 +8112,7 @@ function buildWaterBands(state, fluidDetail, visuals) {
7395
8112
  for (const bandSpec of bandExtents) {
7396
8113
  const representation = fluidPlan.representations.find((entry) => entry.band === bandSpec.band) ?? fluidPlan.representations[0];
7397
8114
  const continuity = createFluidContinuityEnvelope({ fluidBodyId: "harbor" });
8115
+ const bandContinuity = resolveFluidBandContinuity(continuity, bandSpec.band);
7398
8116
  const bandResolution = bandSpec.band === "near" ? fluidDetail.nearResolution : bandSpec.band === "mid" ? fluidDetail.midResolution : bandSpec.band === "far" ? 5 : 3;
7399
8117
  const cols = Math.max(4, bandResolution * 2);
7400
8118
  const rows = Math.max(4, bandResolution + 2);
@@ -7408,7 +8126,7 @@ function buildWaterBands(state, fluidDetail, visuals) {
7408
8126
  const v = row / (rows - 1);
7409
8127
  const x = originX + bandSpec.width * u;
7410
8128
  const z = originZ + bandSpec.depth * v;
7411
- const y = bandSpec.y + sampleWave(state, x, z, state.time) * continuity.amplitudeFloor * (bandSpec.band === "near" ? 0.9 : bandSpec.band === "mid" ? 0.55 : 0.3);
8129
+ const y = bandSpec.y + sampleWave(state, x, z, state.time) * bandContinuity.amplitudeFloor * (bandSpec.band === "near" ? 0.9 : bandSpec.band === "mid" ? 0.55 : 0.3);
7412
8130
  positions.push(vec3(x, y, z));
7413
8131
  }
7414
8132
  }
@@ -7424,7 +8142,7 @@ function buildWaterBands(state, fluidDetail, visuals) {
7424
8142
  bandMeshes.push({
7425
8143
  band: bandSpec.band,
7426
8144
  representation,
7427
- continuity,
8145
+ continuity: bandContinuity,
7428
8146
  rows,
7429
8147
  cols,
7430
8148
  positions,
@@ -7443,6 +8161,7 @@ function buildWaterBands(state, fluidDetail, visuals) {
7443
8161
  return { fluidPlan, bandMeshes };
7444
8162
  }
7445
8163
  function createSceneState(options) {
8164
+ const translate = options.translate;
7446
8165
  const { governor, fluidDetail, clothDetail, lightingDetail } = createPerformanceGovernor();
7447
8166
  const physicsProfile = defaultPhysicsWorkerProfile;
7448
8167
  const physicsPlan = createPhysicsSimulationPlan(physicsProfile);
@@ -7450,7 +8169,7 @@ function createSceneState(options) {
7450
8169
  const debugSession = createGpuDebugSession({
7451
8170
  enabled: true,
7452
8171
  adapter: {
7453
- label: "3D showcase",
8172
+ label: translate(gpuSharedTranslationKeys.debugAdapterShowcase),
7454
8173
  memoryCapacityHintBytes: 6 * 1024 * 1024 * 1024,
7455
8174
  coreCountHint: 12
7456
8175
  }
@@ -7460,22 +8179,26 @@ function createSceneState(options) {
7460
8179
  owner: "renderer",
7461
8180
  category: "texture",
7462
8181
  sizeBytes: 1280 * 720 * 4,
7463
- label: "Main color buffer"
8182
+ label: translate(gpuSharedTranslationKeys.debugMainColorBuffer)
7464
8183
  });
7465
8184
  debugSession.trackAllocation({
7466
8185
  id: "showcase.shadow-impression",
7467
8186
  owner: "lighting",
7468
8187
  category: "texture",
7469
8188
  sizeBytes: 12 * 1024 * 1024,
7470
- label: "Shadow impression atlas"
8189
+ label: translate(gpuSharedTranslationKeys.debugShadowImpressionAtlas)
7471
8190
  });
7472
8191
  return {
8192
+ translate,
7473
8193
  focus: options.focus,
7474
8194
  governor,
7475
8195
  fluidDetail,
7476
8196
  clothDetail,
7477
8197
  lightingDetail,
7478
8198
  debugSession,
8199
+ showcaseRealisticModelsEnabled: options.realisticModelsEnabled !== false,
8200
+ captureMode: options.captureMode === true,
8201
+ renderScale: readPositiveNumber3(options.renderScale, void 0),
7479
8202
  packageState: void 0,
7480
8203
  demoDescription: null,
7481
8204
  demoVisuals: null,
@@ -7490,6 +8213,7 @@ function createSceneState(options) {
7490
8213
  ships: [
7491
8214
  {
7492
8215
  id: "northwind",
8216
+ modelKey: "brigantine",
7493
8217
  position: vec3(-5.2, 0, 7.2),
7494
8218
  velocity: vec3(2.35, 0, -1.08),
7495
8219
  rotationY: 0.58,
@@ -7500,17 +8224,18 @@ function createSceneState(options) {
7500
8224
  throttleResponse: 0.46,
7501
8225
  rudderResponse: 0.54,
7502
8226
  wanderPhase: 0.35,
7503
- lanterns: SHIP_LANTERNS,
8227
+ lanterns: CUTTER_LANTERNS,
7504
8228
  lanternStrength: 1.06,
7505
8229
  collisionRadiusScale: 1.04
7506
8230
  },
7507
8231
  {
7508
8232
  id: "tidecaller",
8233
+ modelKey: "cutter",
7509
8234
  position: vec3(4.8, 0, 4.4),
7510
8235
  velocity: vec3(-2.15, 0, 1.74),
7511
8236
  rotationY: -2.48,
7512
8237
  angularVelocity: -0.2,
7513
- tint: { r: 0.48, g: 0.28, b: 0.19 },
8238
+ tint: { r: 0.58, g: 0.24, b: 0.16 },
7514
8239
  massScale: 0.84,
7515
8240
  cruiseSpeed: 2.68,
7516
8241
  throttleResponse: 0.7,
@@ -7534,6 +8259,7 @@ function createSceneState(options) {
7534
8259
  manifest: physicsManifest,
7535
8260
  snapshot: null
7536
8261
  },
8262
+ assetCatalog: null,
7537
8263
  shipModel: null
7538
8264
  };
7539
8265
  }
@@ -7609,10 +8335,38 @@ function drawSkyAndShore(ctx, canvas, state, nearLighting, reflectionStrength, s
7609
8335
  ctx.fillRect(0, 0, canvas.width, canvas.height);
7610
8336
  }
7611
8337
  }
7612
- function drawTriangles(ctx, triangles, lightDir, reflectionStrength, camera, shadowStrength) {
8338
+ function resolveLocalLightContribution(triangle, lightSources) {
8339
+ const contribution = { r: 0, g: 0, b: 0 };
8340
+ if (!Array.isArray(lightSources) || triangle.surfaceType === "water") {
8341
+ return contribution;
8342
+ }
8343
+ const normal = normalizeVec3(triangle.normal);
8344
+ for (const source of lightSources.slice(0, 8)) {
8345
+ const delta = subVec3(source.point, triangle.worldCenter);
8346
+ const distance = lengthVec3(delta);
8347
+ const attenuation = (source.glowScale ?? 1) / Math.max(1, 0.68 + distance * distance * 0.2);
8348
+ if (attenuation < 0.012) {
8349
+ continue;
8350
+ }
8351
+ const lightDir = normalizeVec3(delta);
8352
+ const facing = clamp(dotVec3(normal, lightDir), 0, 1);
8353
+ const response = attenuation * (0.18 + facing * 0.82);
8354
+ const glowColor = source.glowColor ?? source.coreColor ?? { r: 1, g: 0.72, b: 0.4 };
8355
+ contribution.r += glowColor.r * response * 0.32;
8356
+ contribution.g += glowColor.g * response * 0.26;
8357
+ contribution.b += glowColor.b * response * 0.18;
8358
+ }
8359
+ return contribution;
8360
+ }
8361
+ function drawTriangles(ctx, triangles, lightDir, reflectionStrength, camera, shadowStrength, localLights = []) {
7613
8362
  triangles.sort((left, right) => right.depth - left.depth);
7614
8363
  for (const triangle of triangles) {
7615
8364
  const surfaceNormal = normalizeVec3(triangle.normal);
8365
+ const material = triangle.material ?? {
8366
+ roughness: 0.88,
8367
+ metallic: 0.08,
8368
+ emissive: { r: 0, g: 0, b: 0 }
8369
+ };
7616
8370
  const shaded = shadeColor(
7617
8371
  triangle.baseColor,
7618
8372
  surfaceNormal,
@@ -7620,19 +8374,41 @@ function drawTriangles(ctx, triangles, lightDir, reflectionStrength, camera, sha
7620
8374
  clamp((triangle.worldCenter.y + 3) / 10, 0, 1),
7621
8375
  triangle.accent
7622
8376
  );
7623
- const reflection = triangle.worldCenter.y < 0.8 ? reflectionStrength : 0;
8377
+ const reflection = reflectionStrength * (triangle.reflection ?? 0);
7624
8378
  const viewDir = normalizeVec3(subVec3(camera.eye, triangle.worldCenter));
7625
8379
  const reflectedLight = reflectVec3(scaleVec3(lightDir, -1), surfaceNormal);
7626
- const gloss = triangle.worldCenter.y < 0.9 ? 1 : triangle.accent > 0.05 ? 0.55 : 0.3;
7627
- const specular = Math.pow(clamp(dotVec3(reflectedLight, viewDir), 0, 1), triangle.worldCenter.y < 0.9 ? 18 : 12) * gloss;
7628
- const occlusion = triangle.worldCenter.y < 0.9 ? shadowStrength * 0.035 : 0;
7629
- const fill = colorToRgba(
8380
+ const gloss = mix(0.78, 0.14, clamp(material.roughness ?? 0.88, 0, 1)) + (material.metallic ?? 0) * 0.18;
8381
+ const specularPower = mix(26, 7, clamp(material.roughness ?? 0.88, 0, 1));
8382
+ const specular = Math.pow(clamp(dotVec3(reflectedLight, viewDir), 0, 1), specularPower) * gloss;
8383
+ const emissive = material.emissive ?? { r: 0, g: 0, b: 0 };
8384
+ const localLight = resolveLocalLightContribution(triangle, localLights);
8385
+ const occlusion = triangle.surfaceType === "water" ? shadowStrength * 0.018 : shadowStrength * 0.04;
8386
+ const detailed = applyMaterialDetail(
7630
8387
  {
7631
- r: clamp(shaded.r + reflection * 0.08 + specular * 0.14 - occlusion, 0, 1),
7632
- g: clamp(shaded.g + reflection * 0.08 + specular * 0.15 - occlusion, 0, 1),
7633
- b: clamp(shaded.b + reflection * 0.16 + specular * 0.2 - occlusion * 0.5, 0, 1)
8388
+ r: clamp(
8389
+ shaded.r + reflection * 0.08 + specular * 0.16 + emissive.r * 0.42 + localLight.r - occlusion,
8390
+ 0,
8391
+ 1
8392
+ ),
8393
+ g: clamp(
8394
+ shaded.g + reflection * 0.08 + specular * 0.16 + emissive.g * 0.42 + localLight.g - occlusion,
8395
+ 0,
8396
+ 1
8397
+ ),
8398
+ b: clamp(
8399
+ shaded.b + reflection * 0.16 + specular * 0.22 + emissive.b * 0.46 + localLight.b - occlusion * 0.5,
8400
+ 0,
8401
+ 1
8402
+ )
7634
8403
  },
7635
- 0.98
8404
+ material,
8405
+ triangle.worldCenter,
8406
+ surfaceNormal,
8407
+ triangle.surfaceType
8408
+ );
8409
+ const fill = colorToRgba(
8410
+ detailed,
8411
+ triangle.baseColor.a ?? 0.98
7636
8412
  );
7637
8413
  ctx.fillStyle = fill;
7638
8414
  ctx.beginPath();
@@ -7663,74 +8439,100 @@ function renderProjectedShadow(ctx, worldPoints, camera, viewport, lightDir, opt
7663
8439
  ctx.fill();
7664
8440
  ctx.restore();
7665
8441
  }
7666
- function pushHarborGeometry(camera, viewport, triangles, visuals) {
7667
- const harborObjects = [
7668
- {
7669
- position: vec3(-8.2, 1.1, -0.9),
7670
- rotationY: -0.16,
7671
- scale: { x: 5.4, y: 2.4, z: 4.2 },
7672
- color: visuals.harborWall,
7673
- accent: 0.06
7674
- },
7675
- {
7676
- position: vec3(-5.7, 0.45, 1.4),
7677
- rotationY: -0.08,
7678
- scale: { x: 6.8, y: 0.3, z: 2.1 },
7679
- color: visuals.harborDeck,
7680
- accent: 0.04
7681
- },
7682
- {
7683
- position: vec3(-10.4, 0.28, 0.8),
7684
- rotationY: 0.22,
7685
- scale: { x: 1.2, y: 0.9, z: 1.2 },
7686
- color: visuals.harborTower,
7687
- accent: 0.02
8442
+ function pushHarborGeometry(camera, viewport, triangles, state) {
8443
+ if (!state.showcaseRealisticModelsEnabled) {
8444
+ for (const object of LEGACY_HARBOR_LAYOUT) {
8445
+ buildTrianglesFromMesh(
8446
+ { positions: [object], indices: [0], normals: null, colors: null, material: createLegacyMeshPrimitive({})?.material, bounds: null, name: "legacy-structure" },
8447
+ {
8448
+ position: object.position,
8449
+ rotationY: object.rotationY,
8450
+ scale: object.scale
8451
+ },
8452
+ object.color,
8453
+ camera,
8454
+ viewport,
8455
+ triangles,
8456
+ {
8457
+ accent: object.accent,
8458
+ reflection: 0,
8459
+ surfaceType: "structure"
8460
+ }
8461
+ );
8462
+ }
8463
+ return;
8464
+ }
8465
+ for (const placement of SHOWCASE_ENVIRONMENT_LAYOUT) {
8466
+ const mesh = state.assetCatalog?.environment?.[placement.assetKey] ?? null;
8467
+ if (!mesh) {
8468
+ continue;
7688
8469
  }
7689
- ];
7690
- for (const object of harborObjects) {
7691
8470
  buildTrianglesFromMesh(
7692
- UNIT_BOX_MESH,
8471
+ mesh,
7693
8472
  {
7694
- position: object.position,
7695
- rotationY: object.rotationY,
7696
- scale: object.scale
8473
+ position: vec3(placement.position.x, placement.position.y, placement.position.z),
8474
+ rotationY: placement.rotationY,
8475
+ scale: placement.scale
7697
8476
  },
7698
- object.color,
8477
+ null,
7699
8478
  camera,
7700
8479
  viewport,
7701
8480
  triangles,
7702
- object.accent
8481
+ {
8482
+ accent: placement.accent,
8483
+ reflection: 0,
8484
+ surfaceType: "structure"
8485
+ }
7703
8486
  );
7704
8487
  }
7705
8488
  }
7706
8489
  function renderShipRigging(ctx, ship, camera, viewport) {
7707
8490
  const transform = { position: ship.position, rotationY: ship.rotationY, scale: SHIP_SCALE };
7708
- const mastBase = transformPoint(vec3(0, 0.38, -0.4), transform);
7709
- const mastTop = transformPoint(vec3(0, 3.8, -0.2), transform);
7710
- const aftBase = transformPoint(vec3(-0.25, 0.32, -1.9), transform);
7711
- const aftTop = transformPoint(vec3(-0.15, 2.7, -1.75), transform);
7712
- const sailA = transformPoint(vec3(0.08, 3.2, -0.2), transform);
7713
- const sailB = transformPoint(vec3(0.12, 1.2, -0.5), transform);
7714
- const sailC = transformPoint(vec3(2.25, 2.25, 0.15), transform);
7715
- const projected = [mastBase, mastTop, aftBase, aftTop, sailA, sailB, sailC].map(
7716
- (point) => projectPoint(point, camera, viewport)
7717
- );
8491
+ const layout = ship.modelKey === "cutter" ? {
8492
+ lineColor: "rgba(85, 89, 97, 0.92)",
8493
+ sailColor: "rgba(218, 232, 244, 0.28)",
8494
+ points: [
8495
+ vec3(0, 0.88, -0.32),
8496
+ vec3(0, 2.4, -0.28),
8497
+ vec3(0.1, 1.92, -0.3),
8498
+ vec3(1.18, 1.72, -0.18),
8499
+ vec3(1.04, 1.08, -0.12)
8500
+ ],
8501
+ mastPairs: [[0, 1], [2, 3]],
8502
+ sailTriangle: [2, 3, 4]
8503
+ } : {
8504
+ lineColor: "rgba(73, 54, 45, 0.94)",
8505
+ sailColor: "rgba(238, 232, 214, 0.88)",
8506
+ points: [
8507
+ vec3(0, 0.38, -0.4),
8508
+ vec3(0, 3.8, -0.2),
8509
+ vec3(-0.25, 0.32, -1.9),
8510
+ vec3(-0.15, 2.7, -1.75),
8511
+ vec3(0.08, 3.2, -0.2),
8512
+ vec3(0.12, 1.2, -0.5),
8513
+ vec3(2.25, 2.25, 0.15)
8514
+ ],
8515
+ mastPairs: [[0, 1], [2, 3]],
8516
+ sailTriangle: [4, 5, 6]
8517
+ };
8518
+ const projected = layout.points.map((point) => transformPoint(point, transform)).map((point) => projectPoint(point, camera, viewport));
7718
8519
  if (projected.some((value) => value === null)) {
7719
8520
  return;
7720
8521
  }
7721
- ctx.strokeStyle = "rgba(73, 54, 45, 0.94)";
7722
- ctx.lineWidth = 3.5;
8522
+ ctx.strokeStyle = layout.lineColor;
8523
+ ctx.lineWidth = ship.modelKey === "cutter" ? 2.2 : 3.5;
7723
8524
  ctx.beginPath();
7724
- ctx.moveTo(projected[0].x, projected[0].y);
7725
- ctx.lineTo(projected[1].x, projected[1].y);
7726
- ctx.moveTo(projected[2].x, projected[2].y);
7727
- ctx.lineTo(projected[3].x, projected[3].y);
8525
+ for (const [from, to] of layout.mastPairs) {
8526
+ ctx.moveTo(projected[from].x, projected[from].y);
8527
+ ctx.lineTo(projected[to].x, projected[to].y);
8528
+ }
7728
8529
  ctx.stroke();
7729
- ctx.fillStyle = "rgba(238, 232, 214, 0.88)";
8530
+ const [a, b, c] = layout.sailTriangle;
8531
+ ctx.fillStyle = layout.sailColor;
7730
8532
  ctx.beginPath();
7731
- ctx.moveTo(projected[4].x, projected[4].y);
7732
- ctx.lineTo(projected[5].x, projected[5].y);
7733
- ctx.lineTo(projected[6].x, projected[6].y);
8533
+ ctx.moveTo(projected[a].x, projected[a].y);
8534
+ ctx.lineTo(projected[b].x, projected[b].y);
8535
+ ctx.lineTo(projected[c].x, projected[c].y);
7734
8536
  ctx.closePath();
7735
8537
  ctx.fill();
7736
8538
  }
@@ -7948,10 +8750,10 @@ function resolveBoundaryCollision(ship, state, shipModel) {
7948
8750
  }
7949
8751
  }
7950
8752
  }
7951
- function resolveShipCollision(state, a, b, shipModel) {
8753
+ function resolveShipCollision(state, a, b, shipModelA, shipModelB) {
7952
8754
  const delta = subVec3(b.position, a.position);
7953
- const radiusA = getShipCollisionRadius(a, shipModel);
7954
- const radiusB = getShipCollisionRadius(b, shipModel);
8755
+ const radiusA = getShipCollisionRadius(a, shipModelA);
8756
+ const radiusB = getShipCollisionRadius(b, shipModelB);
7955
8757
  const distance = Math.hypot(delta.x, delta.z);
7956
8758
  const minDistance = radiusA + radiusB;
7957
8759
  if (distance >= minDistance) {
@@ -7960,15 +8762,15 @@ function resolveShipCollision(state, a, b, shipModel) {
7960
8762
  const normal = distance > 1e-4 ? normalizeVec3(vec3(delta.x / distance, 0, delta.z / distance)) : normalizeVec3(vec3(Math.cos(state.time * 5.2), 0, Math.sin(state.time * 4.8)));
7961
8763
  const tangent = vec3(-normal.z, 0, normal.x);
7962
8764
  const penetration = minDistance - distance;
7963
- const invMassA = getShipInverseMass(a, shipModel);
7964
- const invMassB = getShipInverseMass(b, shipModel);
8765
+ const invMassA = getShipInverseMass(a, shipModelA);
8766
+ const invMassB = getShipInverseMass(b, shipModelB);
7965
8767
  const invMassSum = invMassA + invMassB;
7966
8768
  const correction = scaleVec3(normal, penetration / Math.max(1e-4, invMassSum) * 0.72);
7967
8769
  a.position = subVec3(a.position, scaleVec3(correction, invMassA));
7968
8770
  b.position = addVec3(b.position, scaleVec3(correction, invMassB));
7969
8771
  const relativeVelocity = subVec3(b.velocity, a.velocity);
7970
8772
  const velocityAlongNormal = dotVec3(relativeVelocity, normal);
7971
- const restitution = readPhysicsNumber(shipModel.physics, "restitution", 0.22) * 0.88;
8773
+ const restitution = (readPhysicsNumber(shipModelA.physics, "restitution", 0.22) + readPhysicsNumber(shipModelB.physics, "restitution", 0.22)) / 2 * 0.88;
7972
8774
  if (velocityAlongNormal < 0) {
7973
8775
  const impulseMagnitude = -(1 + restitution) * velocityAlongNormal / Math.max(1e-4, invMassSum);
7974
8776
  const impulse = scaleVec3(normal, impulseMagnitude);
@@ -7983,8 +8785,8 @@ function resolveShipCollision(state, a, b, shipModel) {
7983
8785
  const frictionImpulse = scaleVec3(tangent, frictionMagnitude);
7984
8786
  a.velocity = subVec3(a.velocity, scaleVec3(frictionImpulse, invMassA));
7985
8787
  b.velocity = addVec3(b.velocity, scaleVec3(frictionImpulse, invMassB));
7986
- a.angularVelocity -= tangentSpeed * radiusA * getShipInverseInertia(a, shipModel) * 0.2 + impulseMagnitude * 24e-5;
7987
- b.angularVelocity += tangentSpeed * radiusB * getShipInverseInertia(b, shipModel) * 0.2 + impulseMagnitude * 24e-5;
8788
+ a.angularVelocity -= tangentSpeed * radiusA * getShipInverseInertia(a, shipModelA) * 0.2 + impulseMagnitude * 24e-5;
8789
+ b.angularVelocity += tangentSpeed * radiusB * getShipInverseInertia(b, shipModelB) * 0.2 + impulseMagnitude * 24e-5;
7988
8790
  const impactSpeed = Math.abs(velocityAlongNormal);
7989
8791
  if (impactSpeed > 0.18 && Math.max(readVisualNumber(a.collisionCooldown, 0), readVisualNumber(b.collisionCooldown, 0)) <= 0) {
7990
8792
  const contactPoint = vec3(
@@ -8016,12 +8818,17 @@ function updateShips(state, dt, shipModel) {
8016
8818
  let collided = false;
8017
8819
  state.contactCount = 0;
8018
8820
  for (const ship of state.ships) {
8019
- updateShipMotion(state, ship, dt, shipModel);
8020
- resolveBoundaryCollision(ship, state, shipModel);
8821
+ const activeShipModel = resolveShipModel(state, ship, shipModel);
8822
+ updateShipMotion(state, ship, dt, activeShipModel);
8823
+ resolveBoundaryCollision(ship, state, activeShipModel);
8021
8824
  }
8022
8825
  for (let index = 0; index < state.ships.length; index += 1) {
8023
8826
  for (let otherIndex = index + 1; otherIndex < state.ships.length; otherIndex += 1) {
8024
- collided = resolveShipCollision(state, state.ships[index], state.ships[otherIndex], shipModel) || collided;
8827
+ const shipA = state.ships[index];
8828
+ const shipB = state.ships[otherIndex];
8829
+ const shipModelA = resolveShipModel(state, shipA, shipModel);
8830
+ const shipModelB = resolveShipModel(state, shipB, shipModel);
8831
+ collided = resolveShipCollision(state, shipA, shipB, shipModelA, shipModelB) || collided;
8025
8832
  }
8026
8833
  }
8027
8834
  state.collisionFlash = collided ? Math.max(0.12, state.collisionFlash) : Math.max(0, state.collisionFlash - dt * 1.3);
@@ -8285,6 +9092,101 @@ function renderWaterLightReflection(ctx, source, state, camera, viewport) {
8285
9092
  ctx.fill();
8286
9093
  ctx.restore();
8287
9094
  }
9095
+ function renderLighthouseBeam(ctx, state, camera, viewport, visuals) {
9096
+ const lighthousePlacement = SHOWCASE_ENVIRONMENT_LAYOUT.find(
9097
+ (placement) => placement.assetKey === "lighthouse"
9098
+ );
9099
+ if (!lighthousePlacement || !state.showcaseRealisticModelsEnabled) {
9100
+ return;
9101
+ }
9102
+ const source = transformPoint(
9103
+ vec3(0, 11.34, 0),
9104
+ {
9105
+ position: vec3(
9106
+ lighthousePlacement.position.x,
9107
+ lighthousePlacement.position.y,
9108
+ lighthousePlacement.position.z
9109
+ ),
9110
+ rotationY: lighthousePlacement.rotationY,
9111
+ scale: lighthousePlacement.scale
9112
+ }
9113
+ );
9114
+ const sweep = state.time * 0.22 + 0.8;
9115
+ const direction = normalizeVec3(vec3(Math.sin(sweep), -0.07, Math.cos(sweep)));
9116
+ const spread = perpendicularOnWater(direction);
9117
+ const farCenter = addVec3(source, scaleVec3(direction, 34));
9118
+ const left = addVec3(farCenter, scaleVec3(spread, 7.4));
9119
+ const right = addVec3(farCenter, scaleVec3(spread, -7.4));
9120
+ const projectedSource = projectPoint(source, camera, viewport);
9121
+ const projectedLeft = projectPoint(left, camera, viewport);
9122
+ const projectedRight = projectPoint(right, camera, viewport);
9123
+ if (!projectedSource || !projectedLeft || !projectedRight) {
9124
+ return;
9125
+ }
9126
+ const pulse = 0.72 + Math.sin(state.time * 1.7) * 0.08;
9127
+ ctx.save();
9128
+ ctx.globalCompositeOperation = "screen";
9129
+ ctx.fillStyle = colorToRgba(visuals.torchCore, 0.055 * pulse);
9130
+ ctx.beginPath();
9131
+ ctx.moveTo(projectedSource.x, projectedSource.y);
9132
+ ctx.lineTo(projectedLeft.x, projectedLeft.y);
9133
+ ctx.lineTo(projectedRight.x, projectedRight.y);
9134
+ ctx.closePath();
9135
+ ctx.fill();
9136
+ const beamLength = Math.hypot(
9137
+ projectedLeft.x - projectedSource.x,
9138
+ projectedLeft.y - projectedSource.y
9139
+ );
9140
+ const core = ctx.createRadialGradient(
9141
+ projectedSource.x,
9142
+ projectedSource.y,
9143
+ 2,
9144
+ projectedSource.x,
9145
+ projectedSource.y,
9146
+ clamp(beamLength * 0.22, 18, 80)
9147
+ );
9148
+ core.addColorStop(0, colorToRgba(visuals.torchCore, 0.58));
9149
+ core.addColorStop(0.5, colorToRgba(visuals.torchGlow, 0.18));
9150
+ core.addColorStop(1, colorToRgba(visuals.torchGlow, 0));
9151
+ ctx.fillStyle = core;
9152
+ ctx.beginPath();
9153
+ ctx.arc(projectedSource.x, projectedSource.y, clamp(beamLength * 0.18, 14, 64), 0, Math.PI * 2);
9154
+ ctx.fill();
9155
+ ctx.restore();
9156
+ }
9157
+ function renderAtmosphericGrade(ctx, canvas, state, visuals) {
9158
+ const vignette = ctx.createRadialGradient(
9159
+ canvas.width * 0.5,
9160
+ canvas.height * 0.48,
9161
+ canvas.width * 0.2,
9162
+ canvas.width * 0.5,
9163
+ canvas.height * 0.5,
9164
+ canvas.width * 0.72
9165
+ );
9166
+ vignette.addColorStop(0, "rgba(0, 0, 0, 0)");
9167
+ vignette.addColorStop(0.68, "rgba(0, 0, 0, 0.08)");
9168
+ vignette.addColorStop(1, "rgba(0, 0, 0, 0.32)");
9169
+ ctx.fillStyle = vignette;
9170
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
9171
+ const seaHaze = ctx.createLinearGradient(0, canvas.height * 0.34, 0, canvas.height);
9172
+ seaHaze.addColorStop(0, "rgba(0, 0, 0, 0)");
9173
+ seaHaze.addColorStop(0.5, visuals.ambientMist);
9174
+ seaHaze.addColorStop(1, "rgba(3, 8, 16, 0.18)");
9175
+ ctx.fillStyle = seaHaze;
9176
+ ctx.fillRect(0, canvas.height * 0.34, canvas.width, canvas.height * 0.66);
9177
+ if (state.captureMode) {
9178
+ ctx.save();
9179
+ ctx.globalCompositeOperation = "screen";
9180
+ for (let index = 0; index < 70; index += 1) {
9181
+ const x = pseudoRandom(index * 19 + 3) * canvas.width;
9182
+ const y = pseudoRandom(index * 23 + 7) * canvas.height;
9183
+ const alpha = 8e-3 + pseudoRandom(index * 31 + 11) * 0.012;
9184
+ ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
9185
+ ctx.fillRect(x, y, 1.1, 1.1);
9186
+ }
9187
+ ctx.restore();
9188
+ }
9189
+ }
8288
9190
  function renderWaterMotionEffects(ctx, effects, camera, viewport) {
8289
9191
  ctx.save();
8290
9192
  ctx.globalCompositeOperation = "screen";
@@ -8403,13 +9305,22 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8403
9305
  worldCenter: scaleVec3(addVec3(addVec3(a, b), c), 1 / 3),
8404
9306
  normal,
8405
9307
  baseColor: bandMesh.color,
8406
- accent: bandAccent
9308
+ accent: bandAccent,
9309
+ material: {
9310
+ name: "water-surface",
9311
+ color: bandMesh.color,
9312
+ roughness: 0.2,
9313
+ metallic: 0,
9314
+ emissive: { r: 0, g: 0, b: 0 }
9315
+ },
9316
+ reflection: 1,
9317
+ surfaceType: "water"
8407
9318
  });
8408
9319
  }
8409
9320
  }
8410
9321
  const waterMotionEffects = buildWaterMotionEffects(state);
8411
9322
  const lightSources = collectSceneLightSources(state, visuals);
8412
- pushHarborGeometry(camera, viewport, sceneTriangles, visuals);
9323
+ pushHarborGeometry(camera, viewport, sceneTriangles, state);
8413
9324
  const cloth = buildClothSurface(
8414
9325
  state,
8415
9326
  state,
@@ -8431,23 +9342,46 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8431
9342
  worldCenter: scaleVec3(addVec3(addVec3(a, b), c), 1 / 3),
8432
9343
  normal,
8433
9344
  baseColor: cloth.color,
8434
- accent: cloth.band === "near" ? 0.1 : 0.04
9345
+ accent: cloth.band === "near" ? 0.1 : 0.04,
9346
+ material: {
9347
+ name: "flag-cloth",
9348
+ color: cloth.color,
9349
+ roughness: 0.94,
9350
+ metallic: 0,
9351
+ emissive: { r: 0, g: 0, b: 0 }
9352
+ },
9353
+ reflection: 0,
9354
+ surfaceType: "cloth"
8435
9355
  });
8436
9356
  }
8437
9357
  for (const ship of state.ships) {
9358
+ const activeShipModel = resolveShipModel(state, ship, shipModel);
8438
9359
  buildTrianglesFromMesh(
8439
- shipModel,
9360
+ activeShipModel,
8440
9361
  { position: ship.position, rotationY: ship.rotationY, scale: SHIP_SCALE },
8441
9362
  ship.tint,
8442
9363
  camera,
8443
9364
  viewport,
8444
9365
  sceneTriangles,
8445
- nearLighting.rtParticipation.directShadows === "premium" ? 0.08 : 0.02
9366
+ {
9367
+ accent: nearLighting.rtParticipation.directShadows === "premium" ? 0.08 : 0.02,
9368
+ reflection: 0,
9369
+ surfaceType: "ship"
9370
+ }
8446
9371
  );
8447
9372
  }
8448
9373
  drawTriangles(ctx, waterTriangles, lightDir, reflectionStrength, camera, shadowStrength);
8449
9374
  for (const ship of state.ships) {
8450
- renderShipShadow(ctx, shipModel, ship, state, camera, viewport, lightDir, shadowStrength);
9375
+ renderShipShadow(
9376
+ ctx,
9377
+ resolveShipModel(state, ship, shipModel),
9378
+ ship,
9379
+ state,
9380
+ camera,
9381
+ viewport,
9382
+ lightDir,
9383
+ shadowStrength
9384
+ );
8451
9385
  }
8452
9386
  renderFlagShadow(ctx, cloth, camera, viewport, lightDir, shadowStrength);
8453
9387
  for (const source of lightSources.reflectionLights) {
@@ -8455,9 +9389,18 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8455
9389
  }
8456
9390
  renderWaterMotionEffects(ctx, waterMotionEffects, camera, viewport);
8457
9391
  renderWaterHighlights(ctx, water.bandMeshes, camera, viewport);
8458
- drawTriangles(ctx, sceneTriangles, lightDir, reflectionStrength, camera, shadowStrength);
9392
+ drawTriangles(
9393
+ ctx,
9394
+ sceneTriangles,
9395
+ lightDir,
9396
+ reflectionStrength,
9397
+ camera,
9398
+ shadowStrength,
9399
+ lightSources.directLights
9400
+ );
8459
9401
  renderFlagPole(ctx, camera, viewport);
8460
9402
  renderClothAccent(ctx, cloth, camera, viewport);
9403
+ renderLighthouseBeam(ctx, state, camera, viewport, visuals);
8461
9404
  for (const source of lightSources.directLights) {
8462
9405
  renderDirectLightGlow(ctx, source, camera, viewport);
8463
9406
  }
@@ -8465,6 +9408,7 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8465
9408
  renderShipRigging(ctx, ship, camera, viewport);
8466
9409
  }
8467
9410
  renderSprays(ctx, state.sprays, camera, viewport);
9411
+ renderAtmosphericGrade(ctx, canvas, state, visuals);
8468
9412
  const debugSnapshot = state.debugSession.getSnapshot();
8469
9413
  const quality = {
8470
9414
  fluid: state.fluidDetail.getSnapshot(),
@@ -8473,11 +9417,11 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8473
9417
  };
8474
9418
  const sceneMetrics = [
8475
9419
  `focus: ${state.focus}`,
8476
- `ships: ${state.ships.length} active GLTF hulls`,
8477
- `moonlight: cold overhead key + ${HARBOR_TORCHES.length + state.ships.length * SHIP_LANTERNS.length} warm deck and harbor lights`,
9420
+ `ships: ${state.ships.length} active GLTF hulls across ${new Set(state.ships.map((ship) => ship.modelKey)).size} model families`,
9421
+ `moonlight: cold overhead key + ${HARBOR_TORCHES.length + state.ships.reduce((total, ship) => total + (Array.isArray(ship.lanterns) ? ship.lanterns.length : 0), 0)} warm deck and harbor lights`,
8478
9422
  `physics snapshot: ${state.physics.snapshot.stage} (${state.physics.snapshot.stability})`,
8479
9423
  `physics contacts: ${state.contactCount}`,
8480
- `mass split: ${state.ships.map((ship) => `${ship.id} ${(getShipMass(ship, shipModel) / 1e3).toFixed(1)}t`).join(" \xB7 ")}`,
9424
+ `mass split: ${state.ships.map((ship) => `${ship.id} ${(getShipMass(ship, resolveShipModel(state, ship, shipModel)) / 1e3).toFixed(1)}t`).join(" \xB7 ")}`,
8481
9425
  `cloth band: ${cloth.band} -> ${cloth.representation.output}`,
8482
9426
  `fluid near band: ${water.bandMeshes[0].representation.output}`,
8483
9427
  `lighting profile: ${lightingPlan.profile} (${lightingDistanceBands.length} bands)`
@@ -8498,11 +9442,7 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8498
9442
  `pipeline samples: ${debugSnapshot.pipeline.sampleCount}`,
8499
9443
  `tracked memory: ${(debugSnapshot.memory.totalTrackedBytes / (1024 * 1024)).toFixed(1)} MB`
8500
9444
  ];
8501
- const sceneNotes = state.focus === "physics" ? [
8502
- "Stable world snapshots are taken after the authoritative rigid-body commit and before visual follow-up work.",
8503
- "The ships collide with mass-weighted impulses and positional correction, so the heavier hull keeps more of its line.",
8504
- "Moonlight keeps the overall read legible while lanterns and torches make collision moments easy to track against the water."
8505
- ] : SCENE_NOTES;
9445
+ const sceneNotes = state.focus === "physics" ? PHYSICS_SCENE_NOTE_KEYS.map((key) => state.translate(key)) : SCENE_NOTE_KEYS.map((key) => state.translate(key));
8506
9446
  const custom = state.demoDescription ?? null;
8507
9447
  setListContent(
8508
9448
  dom.sceneMetrics,
@@ -8517,8 +9457,16 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8517
9457
  Array.isArray(custom?.debugMetrics) ? custom.debugMetrics : debugMetrics
8518
9458
  );
8519
9459
  setListContent(dom.sceneNotes, Array.isArray(custom?.notes) ? custom.notes : sceneNotes);
8520
- dom.status.textContent = typeof custom?.status === "string" ? custom.status : `3D scene live \xB7 ${state.lastDecision.metrics.fps.toFixed(1)} FPS`;
8521
- dom.details.textContent = typeof custom?.details === "string" ? custom.details : state.focus === "physics" ? `Stable world snapshots are emitted from ${state.physics.plan.snapshotStageId} after the authoritative solver; the heavier hull now carries momentum through mass-aware collision impulses while cloth and fluid remain downstream.` : `Moonlit GLTF ships collide on ${shipModel.physics.shape ?? "box"} physics volumes; lantern reflections, cloth, and fluid remain continuous while the governor pressure is ${state.lastDecision.pressureLevel}.`;
9460
+ dom.status.textContent = typeof custom?.status === "string" ? custom.status : state.translate(gpuSharedTranslationKeys.statusLive, {
9461
+ fps: state.lastDecision.metrics.fps.toFixed(1)
9462
+ });
9463
+ dom.details.textContent = typeof custom?.details === "string" ? custom.details : state.focus === "physics" ? state.translate(gpuSharedTranslationKeys.detailsPhysics, {
9464
+ snapshotStageId: state.physics.plan.snapshotStageId
9465
+ }) : state.showcaseRealisticModelsEnabled ? state.translate(gpuSharedTranslationKeys.detailsRealistic, {
9466
+ pressureLevel: state.lastDecision.pressureLevel
9467
+ }) : state.translate(gpuSharedTranslationKeys.detailsLegacy, {
9468
+ pressureLevel: state.lastDecision.pressureLevel
9469
+ });
8522
9470
  }
8523
9471
  function updateSceneState(state, dt, shipModel) {
8524
9472
  updateShips(state, dt, shipModel);
@@ -8548,15 +9496,18 @@ function syncTextState(state, shipModel) {
8548
9496
  stress: state.stress,
8549
9497
  ships: state.ships.map((ship) => ({
8550
9498
  id: ship.id,
9499
+ modelKey: ship.modelKey ?? "brigantine",
8551
9500
  x: Number(ship.position.x.toFixed(2)),
8552
9501
  y: Number(ship.position.y.toFixed(2)),
8553
9502
  z: Number(ship.position.z.toFixed(2)),
8554
9503
  vx: Number(ship.velocity.x.toFixed(2)),
8555
9504
  vz: Number(ship.velocity.z.toFixed(2)),
8556
- massKg: Math.round(getShipMass(ship, shipModel)),
9505
+ massKg: Math.round(getShipMass(ship, resolveShipModel(state, ship, shipModel))),
8557
9506
  lanterns: Array.isArray(ship.lanterns) ? ship.lanterns.length : 0
8558
9507
  })),
8559
- shipPhysics: shipModel.physics,
9508
+ shipPhysics: Object.fromEntries(
9509
+ state.ships.map((ship) => [ship.id, resolveShipModel(state, ship, shipModel)?.physics ?? null])
9510
+ ),
8560
9511
  sprays: state.sprays.length,
8561
9512
  waveImpulses: state.waveImpulses.length,
8562
9513
  pressure: state.lastDecision?.pressureLevel ?? "stable",
@@ -8579,22 +9530,36 @@ function syncTextState(state, shipModel) {
8579
9530
  }
8580
9531
  };
8581
9532
  }
8582
- async function mountGpuShowcase(options = {}) {
9533
+ async function mountGpuShowcase(options = {}, featureFlags = null) {
8583
9534
  injectStyles();
8584
9535
  const root = options.root ?? document.body;
8585
9536
  root.classList?.add?.(ROOT_CLASS);
9537
+ const captureSettings = resolveCaptureSettings(options);
9538
+ if (captureSettings.captureMode) {
9539
+ root.classList?.add?.(CAPTURE_CLASS);
9540
+ }
8586
9541
  const previousMarkup = root.innerHTML;
8587
9542
  const previousRenderGameToText = window.render_game_to_text;
8588
9543
  const previousAdvanceTime = window.advanceTime;
8589
9544
  const focus = options.focus ?? new URLSearchParams(window.location.search).get("focus") ?? "integrated";
9545
+ const translate = createGpuSharedTranslator(options.translate);
8590
9546
  const dom = buildDemoDom(root, {
8591
9547
  packageName: options.packageName ?? "@plasius/gpu-demo-viewer",
8592
- title: options.title ?? DEFAULT_TITLE,
8593
- subtitle: options.subtitle ?? DEFAULT_SUBTITLE
9548
+ title: options.title ?? translate(gpuSharedTranslationKeys.showcaseTitle),
9549
+ subtitle: options.subtitle ?? translate(gpuSharedTranslationKeys.showcaseSubtitle),
9550
+ translate
8594
9551
  });
8595
9552
  dom.focusMode.value = focus;
8596
- const state = createSceneState({ focus });
8597
- const shipModel = await loadGltfModel(resolveShowcaseAssetUrl());
9553
+ const state = createSceneState({
9554
+ focus,
9555
+ translate,
9556
+ realisticModelsEnabled: isFeatureEnabled(featureFlags, GPU_SHOWCASE_REALISTIC_MODELS_FEATURE, true),
9557
+ captureMode: captureSettings.captureMode,
9558
+ renderScale: captureSettings.renderScale
9559
+ });
9560
+ const assetCatalog = await (state.showcaseRealisticModelsEnabled ? loadShowcaseAssetCatalog() : createLegacyShowcaseAssetCatalog());
9561
+ const shipModel = assetCatalog.ships[assetCatalog.primaryShipKey];
9562
+ state.assetCatalog = assetCatalog;
8598
9563
  state.shipModel = shipModel;
8599
9564
  state.packageState = typeof options.createState === "function" ? options.createState() : void 0;
8600
9565
  updatePhysicsSnapshot(state, shipModel);
@@ -8605,6 +9570,8 @@ async function mountGpuShowcase(options = {}) {
8605
9570
  if (!ctx) {
8606
9571
  throw new Error("2D canvas context is required for the shared showcase.");
8607
9572
  }
9573
+ ctx.imageSmoothingEnabled = true;
9574
+ ctx.imageSmoothingQuality = "high";
8608
9575
  let animationFrameId = 0;
8609
9576
  let destroyed = false;
8610
9577
  const renderFrame = (nowMs) => {
@@ -8625,13 +9592,14 @@ async function mountGpuShowcase(options = {}) {
8625
9592
  state.lastDecision = recordTelemetry(state, syntheticFrame);
8626
9593
  }
8627
9594
  state.demoDescription = resolveSceneDescription(state, options, shipModel).description;
9595
+ resizeCanvasToDisplaySize(dom.canvas, state);
8628
9596
  renderScene(ctx, dom.canvas, state, shipModel, dom);
8629
9597
  syncTextState(state, shipModel);
8630
9598
  animationFrameId = requestAnimationFrame(renderFrame);
8631
9599
  };
8632
9600
  const handlePauseClick = () => {
8633
9601
  state.paused = !state.paused;
8634
- dom.pauseButton.textContent = state.paused ? "Resume" : "Pause";
9602
+ dom.pauseButton.textContent = state.paused ? state.translate(gpuSharedTranslationKeys.resume) : state.translate(gpuSharedTranslationKeys.pause);
8635
9603
  };
8636
9604
  const handleStressChange = () => {
8637
9605
  state.stress = dom.stressToggle.checked;
@@ -8666,6 +9634,7 @@ async function mountGpuShowcase(options = {}) {
8666
9634
  state.packageState = void 0;
8667
9635
  }
8668
9636
  root.classList?.remove?.(ROOT_CLASS);
9637
+ root.classList?.remove?.(CAPTURE_CLASS);
8669
9638
  root.innerHTML = previousMarkup;
8670
9639
  if (typeof previousRenderGameToText === "function") {
8671
9640
  window.render_game_to_text = previousRenderGameToText;
@@ -8686,6 +9655,12 @@ async function mountGpuShowcase(options = {}) {
8686
9655
  };
8687
9656
  }
8688
9657
  function updatePhysicsSnapshot(state, shipModel) {
9658
+ const rigidBodyShapes = Object.fromEntries(
9659
+ state.ships.map((ship) => [
9660
+ ship.id,
9661
+ resolveShipModel(state, ship, shipModel)?.physics?.shape ?? "box"
9662
+ ])
9663
+ );
8689
9664
  state.physics.snapshot = createPhysicsWorldSnapshot({
8690
9665
  frameId: `showcase-${state.frame}`,
8691
9666
  tick: state.frame,
@@ -8701,11 +9676,12 @@ function updatePhysicsSnapshot(state, shipModel) {
8701
9676
  collisionCount: state.collisionCount,
8702
9677
  contactCount: state.contactCount,
8703
9678
  snapshotStageId: state.physics.plan.snapshotStageId,
8704
- rigidBodyShape: shipModel.physics.shape ?? "box"
9679
+ rigidBodyShape: shipModel.physics.shape ?? "box",
9680
+ rigidBodyShapes
8705
9681
  }
8706
9682
  });
8707
9683
  }
8708
- var STYLE_ID, ROOT_CLASS, DEFAULT_TITLE, DEFAULT_SUBTITLE, SHIP_SCALE, HARBOR_BOUNDS, CAMERA_PRESETS, showcaseFocusModes, SCENE_NOTES, UNIT_BOX_MESH, SHIP_LANTERNS, HARBOR_TORCHES, FLAG_LAYOUT;
9684
+ var STYLE_ID, ROOT_CLASS, CAPTURE_CLASS, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT, CAPTURE_CANVAS_PIXEL_BUDGET, SHIP_SCALE, HARBOR_BOUNDS, CAMERA_PRESETS, showcaseFocusModes, FOCUS_MODE_TRANSLATION_KEYS, SCENE_NOTE_KEYS, PHYSICS_SCENE_NOTE_KEYS, LEGACY_HARBOR_LAYOUT, SHOWCASE_ENVIRONMENT_LAYOUT, SHIP_LANTERNS, CUTTER_LANTERNS, HARBOR_TORCHES, FLAG_LAYOUT;
8709
9685
  var init_showcase_runtime = __esm({
8710
9686
  "src/showcase-runtime.js"() {
8711
9687
  init_dist();
@@ -8716,10 +9692,14 @@ var init_showcase_runtime = __esm({
8716
9692
  init_browser();
8717
9693
  init_asset_url();
8718
9694
  init_gltf_loader();
9695
+ init_feature_flags();
9696
+ init_i18n();
8719
9697
  STYLE_ID = "plasius-shared-3d-showcase-style";
8720
9698
  ROOT_CLASS = "plasius-showcase-root";
8721
- DEFAULT_TITLE = "Flag by the Sea";
8722
- DEFAULT_SUBTITLE = "Shared 3D validation scene using GLTF ships, cloth, fluid continuity, adaptive performance, and telemetry.";
9699
+ CAPTURE_CLASS = "plasius-showcase-root--capture";
9700
+ DEFAULT_CANVAS_WIDTH = 1280;
9701
+ DEFAULT_CANVAS_HEIGHT = 720;
9702
+ CAPTURE_CANVAS_PIXEL_BUDGET = 1920 * 1080;
8723
9703
  SHIP_SCALE = 1.1;
8724
9704
  HARBOR_BOUNDS = Object.freeze({
8725
9705
  minX: -11.2,
@@ -8737,84 +9717,75 @@ var init_showcase_runtime = __esm({
8737
9717
  debug: Object.freeze({ yaw: -0.7, pitch: 0.32, distance: 24, target: [0, 2.2, 0] })
8738
9718
  });
8739
9719
  showcaseFocusModes = Object.freeze(Object.keys(CAMERA_PRESETS));
8740
- SCENE_NOTES = Object.freeze([
8741
- "Ships are loaded from a GLTF asset and carry mass, damping, restitution, and hull extents from node extras.",
8742
- "Moonlight sets the cold ambient read while deck lanterns and harbor torches provide warm local contrast.",
8743
- "Cloth and fluid continuity stay coherent across near, mid, far, and horizon bands even in the darker night palette.",
8744
- "Performance pressure reduces visual detail before mass-weighted authoritative collision motion is touched."
8745
- ]);
8746
- UNIT_BOX_MESH = Object.freeze({
8747
- positions: Object.freeze([
8748
- -0.5,
8749
- -0.5,
8750
- -0.5,
8751
- 0.5,
8752
- -0.5,
8753
- -0.5,
8754
- 0.5,
8755
- 0.5,
8756
- -0.5,
8757
- -0.5,
8758
- 0.5,
8759
- -0.5,
8760
- -0.5,
8761
- -0.5,
8762
- 0.5,
8763
- 0.5,
8764
- -0.5,
8765
- 0.5,
8766
- 0.5,
8767
- 0.5,
8768
- 0.5,
8769
- -0.5,
8770
- 0.5,
8771
- 0.5
8772
- ]),
8773
- indices: Object.freeze([
8774
- 0,
8775
- 1,
8776
- 2,
8777
- 0,
8778
- 2,
8779
- 3,
8780
- 5,
8781
- 4,
8782
- 7,
8783
- 5,
8784
- 7,
8785
- 6,
8786
- 4,
8787
- 0,
8788
- 3,
8789
- 4,
8790
- 3,
8791
- 7,
8792
- 1,
8793
- 5,
8794
- 6,
8795
- 1,
8796
- 6,
8797
- 2,
8798
- 3,
8799
- 2,
8800
- 6,
8801
- 3,
8802
- 6,
8803
- 7,
8804
- 4,
8805
- 5,
8806
- 1,
8807
- 4,
8808
- 1,
8809
- 0
8810
- ])
9720
+ FOCUS_MODE_TRANSLATION_KEYS = Object.freeze({
9721
+ integrated: gpuSharedTranslationKeys.focusIntegrated,
9722
+ lighting: gpuSharedTranslationKeys.focusLighting,
9723
+ cloth: gpuSharedTranslationKeys.focusCloth,
9724
+ fluid: gpuSharedTranslationKeys.focusFluid,
9725
+ physics: gpuSharedTranslationKeys.focusPhysics,
9726
+ performance: gpuSharedTranslationKeys.focusPerformance,
9727
+ debug: gpuSharedTranslationKeys.focusDebug
8811
9728
  });
9729
+ SCENE_NOTE_KEYS = Object.freeze([
9730
+ gpuSharedTranslationKeys.noteAssetLoading,
9731
+ gpuSharedTranslationKeys.noteMoonlight,
9732
+ gpuSharedTranslationKeys.noteContinuity,
9733
+ gpuSharedTranslationKeys.notePerformance
9734
+ ]);
9735
+ PHYSICS_SCENE_NOTE_KEYS = Object.freeze([
9736
+ gpuSharedTranslationKeys.notePhysicsSnapshots,
9737
+ gpuSharedTranslationKeys.notePhysicsCollisions,
9738
+ gpuSharedTranslationKeys.notePhysicsLighting
9739
+ ]);
9740
+ LEGACY_HARBOR_LAYOUT = Object.freeze([
9741
+ Object.freeze({
9742
+ position: Object.freeze({ x: -8.2, y: 1.1, z: -0.9 }),
9743
+ rotationY: -0.16,
9744
+ scale: 5.4,
9745
+ color: { r: 0.32, g: 0.27, b: 0.23, a: 1 },
9746
+ accent: 0.06
9747
+ }),
9748
+ Object.freeze({
9749
+ position: Object.freeze({ x: -5.7, y: 0.45, z: 1.4 }),
9750
+ rotationY: -0.08,
9751
+ scale: { x: 6.8, y: 0.3, z: 2.1 },
9752
+ color: { r: 0.31, g: 0.31, b: 0.34, a: 1 },
9753
+ accent: 0.04
9754
+ }),
9755
+ Object.freeze({
9756
+ position: Object.freeze({ x: -10.4, y: 0.28, z: 0.8 }),
9757
+ rotationY: 0.22,
9758
+ scale: { x: 1.2, y: 0.9, z: 1.2 },
9759
+ color: { r: 0.31, g: 0.35, b: 0.39, a: 1 },
9760
+ accent: 0.02
9761
+ })
9762
+ ]);
9763
+ SHOWCASE_ENVIRONMENT_LAYOUT = Object.freeze([
9764
+ Object.freeze({
9765
+ assetKey: "harbor-dock",
9766
+ position: Object.freeze({ x: -4.6, y: 0.16, z: 0.7 }),
9767
+ rotationY: -0.08,
9768
+ scale: 0.84,
9769
+ accent: 0.04
9770
+ }),
9771
+ Object.freeze({
9772
+ assetKey: "lighthouse",
9773
+ position: Object.freeze({ x: -9.8, y: 0, z: -0.58 }),
9774
+ rotationY: 0.12,
9775
+ scale: 0.56,
9776
+ accent: 0.08
9777
+ })
9778
+ ]);
8812
9779
  SHIP_LANTERNS = Object.freeze([
8813
9780
  Object.freeze({ x: 0.94, y: 1.54, z: 2.52, glow: 1 }),
8814
9781
  Object.freeze({ x: -0.9, y: 1.58, z: 2.44, glow: 0.92 }),
8815
9782
  Object.freeze({ x: 0.62, y: 1.42, z: -2.18, glow: 0.88 }),
8816
9783
  Object.freeze({ x: -0.58, y: 1.46, z: -2.04, glow: 0.84 })
8817
9784
  ]);
9785
+ CUTTER_LANTERNS = Object.freeze([
9786
+ Object.freeze({ x: 0.42, y: 1.04, z: 1.18, glow: 0.94 }),
9787
+ Object.freeze({ x: -0.42, y: 1.04, z: 1.12, glow: 0.88 })
9788
+ ]);
8818
9789
  HARBOR_TORCHES = Object.freeze([
8819
9790
  Object.freeze({ x: -5.2, y: 1.25, z: 1.36, glow: 1.1 }),
8820
9791
  Object.freeze({ x: -8.6, y: 2.48, z: -0.72, glow: 1 }),
@@ -8832,13 +9803,20 @@ var init_showcase_runtime = __esm({
8832
9803
  // src/index.js
8833
9804
  var index_exports = {};
8834
9805
  __export(index_exports, {
9806
+ createGpuSharedTranslator: () => createGpuSharedTranslator,
9807
+ gpuSharedEnGbTranslations: () => gpuSharedEnGbTranslations,
9808
+ gpuSharedTranslationKeys: () => gpuSharedTranslationKeys,
9809
+ gpuSharedTranslations: () => gpuSharedTranslations,
8835
9810
  loadGltfModel: () => loadGltfModel2,
8836
9811
  mountGpuShowcase: () => mountGpuShowcase2,
8837
9812
  resolveShowcaseAssetUrl: () => resolveShowcaseAssetUrl,
8838
- showcaseFocusModes: () => showcaseFocusModes2
9813
+ showcaseFocusModes: () => showcaseFocusModes2,
9814
+ translateGpuSharedText: () => translateGpuSharedText
8839
9815
  });
8840
9816
  module.exports = __toCommonJS(index_exports);
8841
9817
  init_asset_url();
9818
+ init_i18n();
9819
+ init_en_GB();
8842
9820
  var showcaseFocusModes2 = Object.freeze([
8843
9821
  "integrated",
8844
9822
  "lighting",
@@ -8860,13 +9838,19 @@ async function mountGpuShowcase2(options = {}) {
8860
9838
  }
8861
9839
  const publicOptions = { ...options };
8862
9840
  delete publicOptions.__runtimeLoader;
8863
- return module2.mountGpuShowcase(publicOptions);
9841
+ delete publicOptions.__featureFlags;
9842
+ return module2.mountGpuShowcase(publicOptions, options.__featureFlags);
8864
9843
  }
8865
9844
  // Annotate the CommonJS export names for ESM import in node:
8866
9845
  0 && (module.exports = {
9846
+ createGpuSharedTranslator,
9847
+ gpuSharedEnGbTranslations,
9848
+ gpuSharedTranslationKeys,
9849
+ gpuSharedTranslations,
8867
9850
  loadGltfModel,
8868
9851
  mountGpuShowcase,
8869
9852
  resolveShowcaseAssetUrl,
8870
- showcaseFocusModes
9853
+ showcaseFocusModes,
9854
+ translateGpuSharedText
8871
9855
  });
8872
9856
  //# sourceMappingURL=index.cjs.map