@plasius/gpu-shared 0.1.11 → 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 +36 -3
  2. package/README.md +55 -1
  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 +1255 -279
  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-2ZNPKD7D.js → showcase-runtime-PN7N3FZY.js} +808 -237
  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 +912 -188
  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-2ZNPKD7D.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,6 +6743,14 @@ 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, {
@@ -6375,6 +6787,11 @@ function injectStyles() {
6375
6787
  radial-gradient(circle at 82% 18%, rgba(240, 188, 103, 0.08), transparent 18%),
6376
6788
  linear-gradient(180deg, #04101d 0%, #0b1930 42%, #081321 100%);
6377
6789
  }
6790
+ .${ROOT_CLASS}.${CAPTURE_CLASS} {
6791
+ min-height: 100vh;
6792
+ overflow: hidden;
6793
+ background: #030710;
6794
+ }
6378
6795
  .${ROOT_CLASS},
6379
6796
  .${ROOT_CLASS} * {
6380
6797
  box-sizing: border-box;
@@ -6454,6 +6871,40 @@ function injectStyles() {
6454
6871
  border: 1px solid rgba(159, 185, 223, 0.12);
6455
6872
  background: linear-gradient(180deg, #071220 0%, #132440 42%, #10344b 42%, #05111d 100%);
6456
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
+ }
6457
6908
  .plasius-demo__toolbar {
6458
6909
  position: absolute;
6459
6910
  top: 26px;
@@ -6545,6 +6996,10 @@ function clamp(value, min, max) {
6545
6996
  function mix(a, b, t) {
6546
6997
  return a + (b - a) * t;
6547
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
+ }
6548
7003
  function pseudoRandom(seed) {
6549
7004
  const value = Math.sin(seed * 12.9898 + seed * seed * 17e-4) * 43758.5453;
6550
7005
  return value - Math.floor(value);
@@ -6603,6 +7058,11 @@ function transformPoint(point, transform) {
6603
7058
  const rotated = rotateY(scaled, transform.rotationY);
6604
7059
  return addVec3(rotated, transform.position);
6605
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
+ }
6606
7066
  function projectPoint(point, camera, viewport) {
6607
7067
  const relative = subVec3(point, camera.eye);
6608
7068
  const viewX = dotVec3(relative, camera.right);
@@ -6626,6 +7086,66 @@ function colorToRgba(color, alpha = 1) {
6626
7086
  const b = Math.round(clamp(color.b, 0, 1) * 255);
6627
7087
  return `rgba(${r}, ${g}, ${b}, ${clamp(alpha, 0, 1)})`;
6628
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
+ }
6629
7149
  function projectShadowPoint(point, lightDir, planeY) {
6630
7150
  const shadowDir = scaleVec3(lightDir, -1);
6631
7151
  if (Math.abs(shadowDir.y) < 1e-4) {
@@ -6646,6 +7166,50 @@ function shadeColor(base, normal, lightDir, heightBias = 0, accent = 0) {
6646
7166
  b: clamp(base.b * (brightness + 0.03), 0, 1)
6647
7167
  };
6648
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
+ }
6649
7213
  function buildCamera(state, canvas) {
6650
7214
  const preset = CAMERA_PRESETS[state.focus] ?? CAMERA_PRESETS.integrated;
6651
7215
  const yaw = state.camera.yaw ?? preset.yaw;
@@ -6670,44 +7234,131 @@ function buildCamera(state, canvas) {
6670
7234
  aspect: canvas.width / canvas.height
6671
7235
  };
6672
7236
  }
6673
- function buildTrianglesFromMesh(mesh, transform, baseColor, camera, viewport, triangles, accent = 0) {
6674
- for (let index = 0; index < mesh.indices.length; index += 3) {
6675
- const aIndex = mesh.indices[index] * 3;
6676
- const bIndex = mesh.indices[index + 1] * 3;
6677
- const cIndex = mesh.indices[index + 2] * 3;
6678
- const a = transformPoint(
6679
- vec3(mesh.positions[aIndex], mesh.positions[aIndex + 1], mesh.positions[aIndex + 2]),
6680
- transform
6681
- );
6682
- const b = transformPoint(
6683
- vec3(mesh.positions[bIndex], mesh.positions[bIndex + 1], mesh.positions[bIndex + 2]),
6684
- transform
6685
- );
6686
- const c = transformPoint(
6687
- vec3(mesh.positions[cIndex], mesh.positions[cIndex + 1], mesh.positions[cIndex + 2]),
6688
- transform
6689
- );
6690
- const ab = subVec3(b, a);
6691
- const ac = subVec3(c, a);
6692
- const normal = normalizeVec3(crossVec3(ab, ac));
6693
- const viewDir = normalizeVec3(subVec3(camera.eye, a));
6694
- if (dotVec3(normal, viewDir) <= 0) {
6695
- continue;
6696
- }
6697
- const projected = [projectPoint(a, camera, viewport), projectPoint(b, camera, viewport), projectPoint(c, camera, viewport)];
6698
- if (projected.some((value) => value === null)) {
6699
- 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
+ });
6700
7325
  }
6701
- triangles.push({
6702
- points: projected,
6703
- depth: (projected[0].depth + projected[1].depth + projected[2].depth) / 3,
6704
- worldCenter: scaleVec3(addVec3(addVec3(a, b), c), 1 / 3),
6705
- normal,
6706
- baseColor,
6707
- accent
6708
- });
6709
7326
  }
6710
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
+ }
6711
7362
  function createPerformanceGovernor() {
6712
7363
  const fluidDetail = createQualityLadderAdapter({
6713
7364
  id: "fluid-detail",
@@ -6759,6 +7410,7 @@ function createPerformanceGovernor() {
6759
7410
  return { governor, fluidDetail, clothDetail, lightingDetail };
6760
7411
  }
6761
7412
  function buildDemoDom(root, options) {
7413
+ const t = options.translate;
6762
7414
  root.innerHTML = `
6763
7415
  <main class="plasius-demo">
6764
7416
  <section class="plasius-demo__hero">
@@ -6768,56 +7420,52 @@ function buildDemoDom(root, options) {
6768
7420
  <p class="plasius-demo__lead">${options.subtitle}</p>
6769
7421
  </section>
6770
7422
  <section class="plasius-panel plasius-demo__status">
6771
- <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>
6772
7424
  <p id="demoDetails" class="plasius-demo__status-text">
6773
- Preparing a moonlit harbor scene, GLTF hull data, cloth and fluid continuity plans, and adaptive quality metadata.
7425
+ ${t(gpuSharedTranslationKeys.detailsBooting)}
6774
7426
  </p>
6775
7427
  </section>
6776
7428
  </section>
6777
7429
  <section class="plasius-demo__layout">
6778
7430
  <section class="plasius-panel plasius-demo__canvas-panel">
6779
- <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>
6780
7432
  <div class="plasius-demo__toolbar">
6781
- <button id="pauseButton" type="button">Pause</button>
7433
+ <button id="pauseButton" type="button">${t(gpuSharedTranslationKeys.pause)}</button>
6782
7434
  <label class="plasius-toggle">
6783
7435
  <input id="stressToggle" type="checkbox" />
6784
- Stress mode
7436
+ ${t(gpuSharedTranslationKeys.stressMode)}
6785
7437
  </label>
6786
7438
  <label class="plasius-toggle">
6787
- Focus
7439
+ ${t(gpuSharedTranslationKeys.focus)}
6788
7440
  <select id="focusMode">
6789
- <option value="integrated">integrated</option>
6790
- <option value="lighting">lighting</option>
6791
- <option value="cloth">cloth</option>
6792
- <option value="fluid">fluid</option>
6793
- <option value="physics">physics</option>
6794
- <option value="performance">performance</option>
6795
- <option value="debug">debug</option>
7441
+ ${showcaseFocusModes.map(
7442
+ (mode) => `<option value="${mode}">${t(FOCUS_MODE_TRANSLATION_KEYS[mode])}</option>`
7443
+ ).join("")}
6796
7444
  </select>
6797
7445
  </label>
6798
7446
  </div>
6799
7447
  <div class="plasius-demo__legend">
6800
- <strong>Scene</strong>
6801
- GLTF ships carry hull mass and damping metadata.<br />
6802
- Lanterns and torches warm the moonlit harbor.<br />
6803
- 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)}
6804
7452
  </div>
6805
7453
  </section>
6806
7454
  <aside class="plasius-demo__sidebar">
6807
7455
  <section class="plasius-panel plasius-demo__card">
6808
- <h2>Scene State</h2>
7456
+ <h2>${t(gpuSharedTranslationKeys.sceneState)}</h2>
6809
7457
  <ul id="sceneMetrics" class="plasius-demo__metrics"></ul>
6810
7458
  </section>
6811
7459
  <section class="plasius-panel plasius-demo__card">
6812
- <h2>Quality + Budgets</h2>
7460
+ <h2>${t(gpuSharedTranslationKeys.qualityBudgets)}</h2>
6813
7461
  <ul id="qualityMetrics" class="plasius-demo__metrics"></ul>
6814
7462
  </section>
6815
7463
  <section class="plasius-panel plasius-demo__card">
6816
- <h2>Debug Telemetry</h2>
7464
+ <h2>${t(gpuSharedTranslationKeys.debugTelemetry)}</h2>
6817
7465
  <ul id="debugMetrics" class="plasius-demo__metrics"></ul>
6818
7466
  </section>
6819
7467
  <section class="plasius-panel plasius-demo__card">
6820
- <h2>Notes</h2>
7468
+ <h2>${t(gpuSharedTranslationKeys.notes)}</h2>
6821
7469
  <ul id="sceneNotes" class="plasius-demo__metrics"></ul>
6822
7470
  </section>
6823
7471
  </aside>
@@ -6841,6 +7489,11 @@ function buildDemoDom(root, options) {
6841
7489
  };
6842
7490
  }
6843
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
+ );
6844
7497
  return Object.freeze({
6845
7498
  focus: state.focus,
6846
7499
  frame: state.frame,
@@ -6862,6 +7515,7 @@ function buildSceneSnapshot(state, shipModel) {
6862
7515
  state.ships.map(
6863
7516
  (ship) => Object.freeze({
6864
7517
  id: ship.id,
7518
+ modelKey: ship.modelKey ?? "brigantine",
6865
7519
  position: Object.freeze({ ...ship.position }),
6866
7520
  velocity: Object.freeze({ ...ship.velocity }),
6867
7521
  rotationY: ship.rotationY,
@@ -6882,12 +7536,13 @@ function buildSceneSnapshot(state, shipModel) {
6882
7536
  )
6883
7537
  ),
6884
7538
  shipPhysics: shipModel?.physics ?? null,
7539
+ shipModels: shipPhysics,
6885
7540
  physics: Object.freeze({
6886
7541
  profile: state.physics.profile,
6887
7542
  plan: state.physics.plan,
6888
7543
  manifest: state.physics.manifest,
6889
7544
  snapshot: state.physics.snapshot,
6890
- shipPhysics: shipModel?.physics ?? null
7545
+ shipPhysics
6891
7546
  })
6892
7547
  });
6893
7548
  }
@@ -6922,6 +7577,61 @@ function normalizeColorOverride(color, fallback) {
6922
7577
  function readVisualNumber(value, fallback) {
6923
7578
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
6924
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
+ }
6925
7635
  function resolveClothPresentation(state, meshDetail) {
6926
7636
  const clothPlan = createClothRepresentationPlan({
6927
7637
  garmentId: "shore-flag",
@@ -7451,6 +8161,7 @@ function buildWaterBands(state, fluidDetail, visuals) {
7451
8161
  return { fluidPlan, bandMeshes };
7452
8162
  }
7453
8163
  function createSceneState(options) {
8164
+ const translate = options.translate;
7454
8165
  const { governor, fluidDetail, clothDetail, lightingDetail } = createPerformanceGovernor();
7455
8166
  const physicsProfile = defaultPhysicsWorkerProfile;
7456
8167
  const physicsPlan = createPhysicsSimulationPlan(physicsProfile);
@@ -7458,7 +8169,7 @@ function createSceneState(options) {
7458
8169
  const debugSession = createGpuDebugSession({
7459
8170
  enabled: true,
7460
8171
  adapter: {
7461
- label: "3D showcase",
8172
+ label: translate(gpuSharedTranslationKeys.debugAdapterShowcase),
7462
8173
  memoryCapacityHintBytes: 6 * 1024 * 1024 * 1024,
7463
8174
  coreCountHint: 12
7464
8175
  }
@@ -7468,22 +8179,26 @@ function createSceneState(options) {
7468
8179
  owner: "renderer",
7469
8180
  category: "texture",
7470
8181
  sizeBytes: 1280 * 720 * 4,
7471
- label: "Main color buffer"
8182
+ label: translate(gpuSharedTranslationKeys.debugMainColorBuffer)
7472
8183
  });
7473
8184
  debugSession.trackAllocation({
7474
8185
  id: "showcase.shadow-impression",
7475
8186
  owner: "lighting",
7476
8187
  category: "texture",
7477
8188
  sizeBytes: 12 * 1024 * 1024,
7478
- label: "Shadow impression atlas"
8189
+ label: translate(gpuSharedTranslationKeys.debugShadowImpressionAtlas)
7479
8190
  });
7480
8191
  return {
8192
+ translate,
7481
8193
  focus: options.focus,
7482
8194
  governor,
7483
8195
  fluidDetail,
7484
8196
  clothDetail,
7485
8197
  lightingDetail,
7486
8198
  debugSession,
8199
+ showcaseRealisticModelsEnabled: options.realisticModelsEnabled !== false,
8200
+ captureMode: options.captureMode === true,
8201
+ renderScale: readPositiveNumber3(options.renderScale, void 0),
7487
8202
  packageState: void 0,
7488
8203
  demoDescription: null,
7489
8204
  demoVisuals: null,
@@ -7498,6 +8213,7 @@ function createSceneState(options) {
7498
8213
  ships: [
7499
8214
  {
7500
8215
  id: "northwind",
8216
+ modelKey: "brigantine",
7501
8217
  position: vec3(-5.2, 0, 7.2),
7502
8218
  velocity: vec3(2.35, 0, -1.08),
7503
8219
  rotationY: 0.58,
@@ -7508,17 +8224,18 @@ function createSceneState(options) {
7508
8224
  throttleResponse: 0.46,
7509
8225
  rudderResponse: 0.54,
7510
8226
  wanderPhase: 0.35,
7511
- lanterns: SHIP_LANTERNS,
8227
+ lanterns: CUTTER_LANTERNS,
7512
8228
  lanternStrength: 1.06,
7513
8229
  collisionRadiusScale: 1.04
7514
8230
  },
7515
8231
  {
7516
8232
  id: "tidecaller",
8233
+ modelKey: "cutter",
7517
8234
  position: vec3(4.8, 0, 4.4),
7518
8235
  velocity: vec3(-2.15, 0, 1.74),
7519
8236
  rotationY: -2.48,
7520
8237
  angularVelocity: -0.2,
7521
- tint: { r: 0.48, g: 0.28, b: 0.19 },
8238
+ tint: { r: 0.58, g: 0.24, b: 0.16 },
7522
8239
  massScale: 0.84,
7523
8240
  cruiseSpeed: 2.68,
7524
8241
  throttleResponse: 0.7,
@@ -7542,6 +8259,7 @@ function createSceneState(options) {
7542
8259
  manifest: physicsManifest,
7543
8260
  snapshot: null
7544
8261
  },
8262
+ assetCatalog: null,
7545
8263
  shipModel: null
7546
8264
  };
7547
8265
  }
@@ -7617,10 +8335,38 @@ function drawSkyAndShore(ctx, canvas, state, nearLighting, reflectionStrength, s
7617
8335
  ctx.fillRect(0, 0, canvas.width, canvas.height);
7618
8336
  }
7619
8337
  }
7620
- 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 = []) {
7621
8362
  triangles.sort((left, right) => right.depth - left.depth);
7622
8363
  for (const triangle of triangles) {
7623
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
+ };
7624
8370
  const shaded = shadeColor(
7625
8371
  triangle.baseColor,
7626
8372
  surfaceNormal,
@@ -7628,19 +8374,41 @@ function drawTriangles(ctx, triangles, lightDir, reflectionStrength, camera, sha
7628
8374
  clamp((triangle.worldCenter.y + 3) / 10, 0, 1),
7629
8375
  triangle.accent
7630
8376
  );
7631
- const reflection = triangle.worldCenter.y < 0.8 ? reflectionStrength : 0;
8377
+ const reflection = reflectionStrength * (triangle.reflection ?? 0);
7632
8378
  const viewDir = normalizeVec3(subVec3(camera.eye, triangle.worldCenter));
7633
8379
  const reflectedLight = reflectVec3(scaleVec3(lightDir, -1), surfaceNormal);
7634
- const gloss = triangle.worldCenter.y < 0.9 ? 1 : triangle.accent > 0.05 ? 0.55 : 0.3;
7635
- const specular = Math.pow(clamp(dotVec3(reflectedLight, viewDir), 0, 1), triangle.worldCenter.y < 0.9 ? 18 : 12) * gloss;
7636
- const occlusion = triangle.worldCenter.y < 0.9 ? shadowStrength * 0.035 : 0;
7637
- 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(
7638
8387
  {
7639
- r: clamp(shaded.r + reflection * 0.08 + specular * 0.14 - occlusion, 0, 1),
7640
- g: clamp(shaded.g + reflection * 0.08 + specular * 0.15 - occlusion, 0, 1),
7641
- 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
+ )
7642
8403
  },
7643
- 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
7644
8412
  );
7645
8413
  ctx.fillStyle = fill;
7646
8414
  ctx.beginPath();
@@ -7671,74 +8439,100 @@ function renderProjectedShadow(ctx, worldPoints, camera, viewport, lightDir, opt
7671
8439
  ctx.fill();
7672
8440
  ctx.restore();
7673
8441
  }
7674
- function pushHarborGeometry(camera, viewport, triangles, visuals) {
7675
- const harborObjects = [
7676
- {
7677
- position: vec3(-8.2, 1.1, -0.9),
7678
- rotationY: -0.16,
7679
- scale: { x: 5.4, y: 2.4, z: 4.2 },
7680
- color: visuals.harborWall,
7681
- accent: 0.06
7682
- },
7683
- {
7684
- position: vec3(-5.7, 0.45, 1.4),
7685
- rotationY: -0.08,
7686
- scale: { x: 6.8, y: 0.3, z: 2.1 },
7687
- color: visuals.harborDeck,
7688
- accent: 0.04
7689
- },
7690
- {
7691
- position: vec3(-10.4, 0.28, 0.8),
7692
- rotationY: 0.22,
7693
- scale: { x: 1.2, y: 0.9, z: 1.2 },
7694
- color: visuals.harborTower,
7695
- 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;
7696
8469
  }
7697
- ];
7698
- for (const object of harborObjects) {
7699
8470
  buildTrianglesFromMesh(
7700
- UNIT_BOX_MESH,
8471
+ mesh,
7701
8472
  {
7702
- position: object.position,
7703
- rotationY: object.rotationY,
7704
- scale: object.scale
8473
+ position: vec3(placement.position.x, placement.position.y, placement.position.z),
8474
+ rotationY: placement.rotationY,
8475
+ scale: placement.scale
7705
8476
  },
7706
- object.color,
8477
+ null,
7707
8478
  camera,
7708
8479
  viewport,
7709
8480
  triangles,
7710
- object.accent
8481
+ {
8482
+ accent: placement.accent,
8483
+ reflection: 0,
8484
+ surfaceType: "structure"
8485
+ }
7711
8486
  );
7712
8487
  }
7713
8488
  }
7714
8489
  function renderShipRigging(ctx, ship, camera, viewport) {
7715
8490
  const transform = { position: ship.position, rotationY: ship.rotationY, scale: SHIP_SCALE };
7716
- const mastBase = transformPoint(vec3(0, 0.38, -0.4), transform);
7717
- const mastTop = transformPoint(vec3(0, 3.8, -0.2), transform);
7718
- const aftBase = transformPoint(vec3(-0.25, 0.32, -1.9), transform);
7719
- const aftTop = transformPoint(vec3(-0.15, 2.7, -1.75), transform);
7720
- const sailA = transformPoint(vec3(0.08, 3.2, -0.2), transform);
7721
- const sailB = transformPoint(vec3(0.12, 1.2, -0.5), transform);
7722
- const sailC = transformPoint(vec3(2.25, 2.25, 0.15), transform);
7723
- const projected = [mastBase, mastTop, aftBase, aftTop, sailA, sailB, sailC].map(
7724
- (point) => projectPoint(point, camera, viewport)
7725
- );
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));
7726
8519
  if (projected.some((value) => value === null)) {
7727
8520
  return;
7728
8521
  }
7729
- ctx.strokeStyle = "rgba(73, 54, 45, 0.94)";
7730
- ctx.lineWidth = 3.5;
8522
+ ctx.strokeStyle = layout.lineColor;
8523
+ ctx.lineWidth = ship.modelKey === "cutter" ? 2.2 : 3.5;
7731
8524
  ctx.beginPath();
7732
- ctx.moveTo(projected[0].x, projected[0].y);
7733
- ctx.lineTo(projected[1].x, projected[1].y);
7734
- ctx.moveTo(projected[2].x, projected[2].y);
7735
- 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
+ }
7736
8529
  ctx.stroke();
7737
- ctx.fillStyle = "rgba(238, 232, 214, 0.88)";
8530
+ const [a, b, c] = layout.sailTriangle;
8531
+ ctx.fillStyle = layout.sailColor;
7738
8532
  ctx.beginPath();
7739
- ctx.moveTo(projected[4].x, projected[4].y);
7740
- ctx.lineTo(projected[5].x, projected[5].y);
7741
- 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);
7742
8536
  ctx.closePath();
7743
8537
  ctx.fill();
7744
8538
  }
@@ -7956,10 +8750,10 @@ function resolveBoundaryCollision(ship, state, shipModel) {
7956
8750
  }
7957
8751
  }
7958
8752
  }
7959
- function resolveShipCollision(state, a, b, shipModel) {
8753
+ function resolveShipCollision(state, a, b, shipModelA, shipModelB) {
7960
8754
  const delta = subVec3(b.position, a.position);
7961
- const radiusA = getShipCollisionRadius(a, shipModel);
7962
- const radiusB = getShipCollisionRadius(b, shipModel);
8755
+ const radiusA = getShipCollisionRadius(a, shipModelA);
8756
+ const radiusB = getShipCollisionRadius(b, shipModelB);
7963
8757
  const distance = Math.hypot(delta.x, delta.z);
7964
8758
  const minDistance = radiusA + radiusB;
7965
8759
  if (distance >= minDistance) {
@@ -7968,15 +8762,15 @@ function resolveShipCollision(state, a, b, shipModel) {
7968
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)));
7969
8763
  const tangent = vec3(-normal.z, 0, normal.x);
7970
8764
  const penetration = minDistance - distance;
7971
- const invMassA = getShipInverseMass(a, shipModel);
7972
- const invMassB = getShipInverseMass(b, shipModel);
8765
+ const invMassA = getShipInverseMass(a, shipModelA);
8766
+ const invMassB = getShipInverseMass(b, shipModelB);
7973
8767
  const invMassSum = invMassA + invMassB;
7974
8768
  const correction = scaleVec3(normal, penetration / Math.max(1e-4, invMassSum) * 0.72);
7975
8769
  a.position = subVec3(a.position, scaleVec3(correction, invMassA));
7976
8770
  b.position = addVec3(b.position, scaleVec3(correction, invMassB));
7977
8771
  const relativeVelocity = subVec3(b.velocity, a.velocity);
7978
8772
  const velocityAlongNormal = dotVec3(relativeVelocity, normal);
7979
- 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;
7980
8774
  if (velocityAlongNormal < 0) {
7981
8775
  const impulseMagnitude = -(1 + restitution) * velocityAlongNormal / Math.max(1e-4, invMassSum);
7982
8776
  const impulse = scaleVec3(normal, impulseMagnitude);
@@ -7991,8 +8785,8 @@ function resolveShipCollision(state, a, b, shipModel) {
7991
8785
  const frictionImpulse = scaleVec3(tangent, frictionMagnitude);
7992
8786
  a.velocity = subVec3(a.velocity, scaleVec3(frictionImpulse, invMassA));
7993
8787
  b.velocity = addVec3(b.velocity, scaleVec3(frictionImpulse, invMassB));
7994
- a.angularVelocity -= tangentSpeed * radiusA * getShipInverseInertia(a, shipModel) * 0.2 + impulseMagnitude * 24e-5;
7995
- 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;
7996
8790
  const impactSpeed = Math.abs(velocityAlongNormal);
7997
8791
  if (impactSpeed > 0.18 && Math.max(readVisualNumber(a.collisionCooldown, 0), readVisualNumber(b.collisionCooldown, 0)) <= 0) {
7998
8792
  const contactPoint = vec3(
@@ -8024,12 +8818,17 @@ function updateShips(state, dt, shipModel) {
8024
8818
  let collided = false;
8025
8819
  state.contactCount = 0;
8026
8820
  for (const ship of state.ships) {
8027
- updateShipMotion(state, ship, dt, shipModel);
8028
- resolveBoundaryCollision(ship, state, shipModel);
8821
+ const activeShipModel = resolveShipModel(state, ship, shipModel);
8822
+ updateShipMotion(state, ship, dt, activeShipModel);
8823
+ resolveBoundaryCollision(ship, state, activeShipModel);
8029
8824
  }
8030
8825
  for (let index = 0; index < state.ships.length; index += 1) {
8031
8826
  for (let otherIndex = index + 1; otherIndex < state.ships.length; otherIndex += 1) {
8032
- 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;
8033
8832
  }
8034
8833
  }
8035
8834
  state.collisionFlash = collided ? Math.max(0.12, state.collisionFlash) : Math.max(0, state.collisionFlash - dt * 1.3);
@@ -8293,6 +9092,101 @@ function renderWaterLightReflection(ctx, source, state, camera, viewport) {
8293
9092
  ctx.fill();
8294
9093
  ctx.restore();
8295
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
+ }
8296
9190
  function renderWaterMotionEffects(ctx, effects, camera, viewport) {
8297
9191
  ctx.save();
8298
9192
  ctx.globalCompositeOperation = "screen";
@@ -8411,13 +9305,22 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8411
9305
  worldCenter: scaleVec3(addVec3(addVec3(a, b), c), 1 / 3),
8412
9306
  normal,
8413
9307
  baseColor: bandMesh.color,
8414
- 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"
8415
9318
  });
8416
9319
  }
8417
9320
  }
8418
9321
  const waterMotionEffects = buildWaterMotionEffects(state);
8419
9322
  const lightSources = collectSceneLightSources(state, visuals);
8420
- pushHarborGeometry(camera, viewport, sceneTriangles, visuals);
9323
+ pushHarborGeometry(camera, viewport, sceneTriangles, state);
8421
9324
  const cloth = buildClothSurface(
8422
9325
  state,
8423
9326
  state,
@@ -8439,23 +9342,46 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8439
9342
  worldCenter: scaleVec3(addVec3(addVec3(a, b), c), 1 / 3),
8440
9343
  normal,
8441
9344
  baseColor: cloth.color,
8442
- 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"
8443
9355
  });
8444
9356
  }
8445
9357
  for (const ship of state.ships) {
9358
+ const activeShipModel = resolveShipModel(state, ship, shipModel);
8446
9359
  buildTrianglesFromMesh(
8447
- shipModel,
9360
+ activeShipModel,
8448
9361
  { position: ship.position, rotationY: ship.rotationY, scale: SHIP_SCALE },
8449
9362
  ship.tint,
8450
9363
  camera,
8451
9364
  viewport,
8452
9365
  sceneTriangles,
8453
- 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
+ }
8454
9371
  );
8455
9372
  }
8456
9373
  drawTriangles(ctx, waterTriangles, lightDir, reflectionStrength, camera, shadowStrength);
8457
9374
  for (const ship of state.ships) {
8458
- 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
+ );
8459
9385
  }
8460
9386
  renderFlagShadow(ctx, cloth, camera, viewport, lightDir, shadowStrength);
8461
9387
  for (const source of lightSources.reflectionLights) {
@@ -8463,9 +9389,18 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8463
9389
  }
8464
9390
  renderWaterMotionEffects(ctx, waterMotionEffects, camera, viewport);
8465
9391
  renderWaterHighlights(ctx, water.bandMeshes, camera, viewport);
8466
- 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
+ );
8467
9401
  renderFlagPole(ctx, camera, viewport);
8468
9402
  renderClothAccent(ctx, cloth, camera, viewport);
9403
+ renderLighthouseBeam(ctx, state, camera, viewport, visuals);
8469
9404
  for (const source of lightSources.directLights) {
8470
9405
  renderDirectLightGlow(ctx, source, camera, viewport);
8471
9406
  }
@@ -8473,6 +9408,7 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8473
9408
  renderShipRigging(ctx, ship, camera, viewport);
8474
9409
  }
8475
9410
  renderSprays(ctx, state.sprays, camera, viewport);
9411
+ renderAtmosphericGrade(ctx, canvas, state, visuals);
8476
9412
  const debugSnapshot = state.debugSession.getSnapshot();
8477
9413
  const quality = {
8478
9414
  fluid: state.fluidDetail.getSnapshot(),
@@ -8481,11 +9417,11 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8481
9417
  };
8482
9418
  const sceneMetrics = [
8483
9419
  `focus: ${state.focus}`,
8484
- `ships: ${state.ships.length} active GLTF hulls`,
8485
- `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`,
8486
9422
  `physics snapshot: ${state.physics.snapshot.stage} (${state.physics.snapshot.stability})`,
8487
9423
  `physics contacts: ${state.contactCount}`,
8488
- `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 ")}`,
8489
9425
  `cloth band: ${cloth.band} -> ${cloth.representation.output}`,
8490
9426
  `fluid near band: ${water.bandMeshes[0].representation.output}`,
8491
9427
  `lighting profile: ${lightingPlan.profile} (${lightingDistanceBands.length} bands)`
@@ -8506,11 +9442,7 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8506
9442
  `pipeline samples: ${debugSnapshot.pipeline.sampleCount}`,
8507
9443
  `tracked memory: ${(debugSnapshot.memory.totalTrackedBytes / (1024 * 1024)).toFixed(1)} MB`
8508
9444
  ];
8509
- const sceneNotes = state.focus === "physics" ? [
8510
- "Stable world snapshots are taken after the authoritative rigid-body commit and before visual follow-up work.",
8511
- "The ships collide with mass-weighted impulses and positional correction, so the heavier hull keeps more of its line.",
8512
- "Moonlight keeps the overall read legible while lanterns and torches make collision moments easy to track against the water."
8513
- ] : 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));
8514
9446
  const custom = state.demoDescription ?? null;
8515
9447
  setListContent(
8516
9448
  dom.sceneMetrics,
@@ -8525,8 +9457,16 @@ function renderScene(ctx, canvas, state, shipModel, dom) {
8525
9457
  Array.isArray(custom?.debugMetrics) ? custom.debugMetrics : debugMetrics
8526
9458
  );
8527
9459
  setListContent(dom.sceneNotes, Array.isArray(custom?.notes) ? custom.notes : sceneNotes);
8528
- dom.status.textContent = typeof custom?.status === "string" ? custom.status : `3D scene live \xB7 ${state.lastDecision.metrics.fps.toFixed(1)} FPS`;
8529
- 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
+ });
8530
9470
  }
8531
9471
  function updateSceneState(state, dt, shipModel) {
8532
9472
  updateShips(state, dt, shipModel);
@@ -8556,15 +9496,18 @@ function syncTextState(state, shipModel) {
8556
9496
  stress: state.stress,
8557
9497
  ships: state.ships.map((ship) => ({
8558
9498
  id: ship.id,
9499
+ modelKey: ship.modelKey ?? "brigantine",
8559
9500
  x: Number(ship.position.x.toFixed(2)),
8560
9501
  y: Number(ship.position.y.toFixed(2)),
8561
9502
  z: Number(ship.position.z.toFixed(2)),
8562
9503
  vx: Number(ship.velocity.x.toFixed(2)),
8563
9504
  vz: Number(ship.velocity.z.toFixed(2)),
8564
- massKg: Math.round(getShipMass(ship, shipModel)),
9505
+ massKg: Math.round(getShipMass(ship, resolveShipModel(state, ship, shipModel))),
8565
9506
  lanterns: Array.isArray(ship.lanterns) ? ship.lanterns.length : 0
8566
9507
  })),
8567
- shipPhysics: shipModel.physics,
9508
+ shipPhysics: Object.fromEntries(
9509
+ state.ships.map((ship) => [ship.id, resolveShipModel(state, ship, shipModel)?.physics ?? null])
9510
+ ),
8568
9511
  sprays: state.sprays.length,
8569
9512
  waveImpulses: state.waveImpulses.length,
8570
9513
  pressure: state.lastDecision?.pressureLevel ?? "stable",
@@ -8587,22 +9530,36 @@ function syncTextState(state, shipModel) {
8587
9530
  }
8588
9531
  };
8589
9532
  }
8590
- async function mountGpuShowcase(options = {}) {
9533
+ async function mountGpuShowcase(options = {}, featureFlags = null) {
8591
9534
  injectStyles();
8592
9535
  const root = options.root ?? document.body;
8593
9536
  root.classList?.add?.(ROOT_CLASS);
9537
+ const captureSettings = resolveCaptureSettings(options);
9538
+ if (captureSettings.captureMode) {
9539
+ root.classList?.add?.(CAPTURE_CLASS);
9540
+ }
8594
9541
  const previousMarkup = root.innerHTML;
8595
9542
  const previousRenderGameToText = window.render_game_to_text;
8596
9543
  const previousAdvanceTime = window.advanceTime;
8597
9544
  const focus = options.focus ?? new URLSearchParams(window.location.search).get("focus") ?? "integrated";
9545
+ const translate = createGpuSharedTranslator(options.translate);
8598
9546
  const dom = buildDemoDom(root, {
8599
9547
  packageName: options.packageName ?? "@plasius/gpu-demo-viewer",
8600
- title: options.title ?? DEFAULT_TITLE,
8601
- subtitle: options.subtitle ?? DEFAULT_SUBTITLE
9548
+ title: options.title ?? translate(gpuSharedTranslationKeys.showcaseTitle),
9549
+ subtitle: options.subtitle ?? translate(gpuSharedTranslationKeys.showcaseSubtitle),
9550
+ translate
8602
9551
  });
8603
9552
  dom.focusMode.value = focus;
8604
- const state = createSceneState({ focus });
8605
- 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;
8606
9563
  state.shipModel = shipModel;
8607
9564
  state.packageState = typeof options.createState === "function" ? options.createState() : void 0;
8608
9565
  updatePhysicsSnapshot(state, shipModel);
@@ -8613,6 +9570,8 @@ async function mountGpuShowcase(options = {}) {
8613
9570
  if (!ctx) {
8614
9571
  throw new Error("2D canvas context is required for the shared showcase.");
8615
9572
  }
9573
+ ctx.imageSmoothingEnabled = true;
9574
+ ctx.imageSmoothingQuality = "high";
8616
9575
  let animationFrameId = 0;
8617
9576
  let destroyed = false;
8618
9577
  const renderFrame = (nowMs) => {
@@ -8633,13 +9592,14 @@ async function mountGpuShowcase(options = {}) {
8633
9592
  state.lastDecision = recordTelemetry(state, syntheticFrame);
8634
9593
  }
8635
9594
  state.demoDescription = resolveSceneDescription(state, options, shipModel).description;
9595
+ resizeCanvasToDisplaySize(dom.canvas, state);
8636
9596
  renderScene(ctx, dom.canvas, state, shipModel, dom);
8637
9597
  syncTextState(state, shipModel);
8638
9598
  animationFrameId = requestAnimationFrame(renderFrame);
8639
9599
  };
8640
9600
  const handlePauseClick = () => {
8641
9601
  state.paused = !state.paused;
8642
- dom.pauseButton.textContent = state.paused ? "Resume" : "Pause";
9602
+ dom.pauseButton.textContent = state.paused ? state.translate(gpuSharedTranslationKeys.resume) : state.translate(gpuSharedTranslationKeys.pause);
8643
9603
  };
8644
9604
  const handleStressChange = () => {
8645
9605
  state.stress = dom.stressToggle.checked;
@@ -8674,6 +9634,7 @@ async function mountGpuShowcase(options = {}) {
8674
9634
  state.packageState = void 0;
8675
9635
  }
8676
9636
  root.classList?.remove?.(ROOT_CLASS);
9637
+ root.classList?.remove?.(CAPTURE_CLASS);
8677
9638
  root.innerHTML = previousMarkup;
8678
9639
  if (typeof previousRenderGameToText === "function") {
8679
9640
  window.render_game_to_text = previousRenderGameToText;
@@ -8694,6 +9655,12 @@ async function mountGpuShowcase(options = {}) {
8694
9655
  };
8695
9656
  }
8696
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
+ );
8697
9664
  state.physics.snapshot = createPhysicsWorldSnapshot({
8698
9665
  frameId: `showcase-${state.frame}`,
8699
9666
  tick: state.frame,
@@ -8709,11 +9676,12 @@ function updatePhysicsSnapshot(state, shipModel) {
8709
9676
  collisionCount: state.collisionCount,
8710
9677
  contactCount: state.contactCount,
8711
9678
  snapshotStageId: state.physics.plan.snapshotStageId,
8712
- rigidBodyShape: shipModel.physics.shape ?? "box"
9679
+ rigidBodyShape: shipModel.physics.shape ?? "box",
9680
+ rigidBodyShapes
8713
9681
  }
8714
9682
  });
8715
9683
  }
8716
- 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;
8717
9685
  var init_showcase_runtime = __esm({
8718
9686
  "src/showcase-runtime.js"() {
8719
9687
  init_dist();
@@ -8724,10 +9692,14 @@ var init_showcase_runtime = __esm({
8724
9692
  init_browser();
8725
9693
  init_asset_url();
8726
9694
  init_gltf_loader();
9695
+ init_feature_flags();
9696
+ init_i18n();
8727
9697
  STYLE_ID = "plasius-shared-3d-showcase-style";
8728
9698
  ROOT_CLASS = "plasius-showcase-root";
8729
- DEFAULT_TITLE = "Flag by the Sea";
8730
- 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;
8731
9703
  SHIP_SCALE = 1.1;
8732
9704
  HARBOR_BOUNDS = Object.freeze({
8733
9705
  minX: -11.2,
@@ -8745,84 +9717,75 @@ var init_showcase_runtime = __esm({
8745
9717
  debug: Object.freeze({ yaw: -0.7, pitch: 0.32, distance: 24, target: [0, 2.2, 0] })
8746
9718
  });
8747
9719
  showcaseFocusModes = Object.freeze(Object.keys(CAMERA_PRESETS));
8748
- SCENE_NOTES = Object.freeze([
8749
- "Ships are loaded from a GLTF asset and carry mass, damping, restitution, and hull extents from node extras.",
8750
- "Moonlight sets the cold ambient read while deck lanterns and harbor torches provide warm local contrast.",
8751
- "Cloth and fluid continuity stay coherent across near, mid, far, and horizon bands even in the darker night palette.",
8752
- "Performance pressure reduces visual detail before mass-weighted authoritative collision motion is touched."
8753
- ]);
8754
- UNIT_BOX_MESH = Object.freeze({
8755
- positions: Object.freeze([
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
- -0.5,
8773
- 0.5,
8774
- 0.5,
8775
- 0.5,
8776
- 0.5,
8777
- -0.5,
8778
- 0.5,
8779
- 0.5
8780
- ]),
8781
- indices: Object.freeze([
8782
- 0,
8783
- 1,
8784
- 2,
8785
- 0,
8786
- 2,
8787
- 3,
8788
- 5,
8789
- 4,
8790
- 7,
8791
- 5,
8792
- 7,
8793
- 6,
8794
- 4,
8795
- 0,
8796
- 3,
8797
- 4,
8798
- 3,
8799
- 7,
8800
- 1,
8801
- 5,
8802
- 6,
8803
- 1,
8804
- 6,
8805
- 2,
8806
- 3,
8807
- 2,
8808
- 6,
8809
- 3,
8810
- 6,
8811
- 7,
8812
- 4,
8813
- 5,
8814
- 1,
8815
- 4,
8816
- 1,
8817
- 0
8818
- ])
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
8819
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
+ ]);
8820
9779
  SHIP_LANTERNS = Object.freeze([
8821
9780
  Object.freeze({ x: 0.94, y: 1.54, z: 2.52, glow: 1 }),
8822
9781
  Object.freeze({ x: -0.9, y: 1.58, z: 2.44, glow: 0.92 }),
8823
9782
  Object.freeze({ x: 0.62, y: 1.42, z: -2.18, glow: 0.88 }),
8824
9783
  Object.freeze({ x: -0.58, y: 1.46, z: -2.04, glow: 0.84 })
8825
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
+ ]);
8826
9789
  HARBOR_TORCHES = Object.freeze([
8827
9790
  Object.freeze({ x: -5.2, y: 1.25, z: 1.36, glow: 1.1 }),
8828
9791
  Object.freeze({ x: -8.6, y: 2.48, z: -0.72, glow: 1 }),
@@ -8840,13 +9803,20 @@ var init_showcase_runtime = __esm({
8840
9803
  // src/index.js
8841
9804
  var index_exports = {};
8842
9805
  __export(index_exports, {
9806
+ createGpuSharedTranslator: () => createGpuSharedTranslator,
9807
+ gpuSharedEnGbTranslations: () => gpuSharedEnGbTranslations,
9808
+ gpuSharedTranslationKeys: () => gpuSharedTranslationKeys,
9809
+ gpuSharedTranslations: () => gpuSharedTranslations,
8843
9810
  loadGltfModel: () => loadGltfModel2,
8844
9811
  mountGpuShowcase: () => mountGpuShowcase2,
8845
9812
  resolveShowcaseAssetUrl: () => resolveShowcaseAssetUrl,
8846
- showcaseFocusModes: () => showcaseFocusModes2
9813
+ showcaseFocusModes: () => showcaseFocusModes2,
9814
+ translateGpuSharedText: () => translateGpuSharedText
8847
9815
  });
8848
9816
  module.exports = __toCommonJS(index_exports);
8849
9817
  init_asset_url();
9818
+ init_i18n();
9819
+ init_en_GB();
8850
9820
  var showcaseFocusModes2 = Object.freeze([
8851
9821
  "integrated",
8852
9822
  "lighting",
@@ -8868,13 +9838,19 @@ async function mountGpuShowcase2(options = {}) {
8868
9838
  }
8869
9839
  const publicOptions = { ...options };
8870
9840
  delete publicOptions.__runtimeLoader;
8871
- return module2.mountGpuShowcase(publicOptions);
9841
+ delete publicOptions.__featureFlags;
9842
+ return module2.mountGpuShowcase(publicOptions, options.__featureFlags);
8872
9843
  }
8873
9844
  // Annotate the CommonJS export names for ESM import in node:
8874
9845
  0 && (module.exports = {
9846
+ createGpuSharedTranslator,
9847
+ gpuSharedEnGbTranslations,
9848
+ gpuSharedTranslationKeys,
9849
+ gpuSharedTranslations,
8875
9850
  loadGltfModel,
8876
9851
  mountGpuShowcase,
8877
9852
  resolveShowcaseAssetUrl,
8878
- showcaseFocusModes
9853
+ showcaseFocusModes,
9854
+ translateGpuSharedText
8879
9855
  });
8880
9856
  //# sourceMappingURL=index.cjs.map