@playpilot/tpi 8.10.1 → 8.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playpilot/tpi",
3
- "version": "8.10.1",
3
+ "version": "8.10.3",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -1,6 +1,4 @@
1
1
  import { PUBLIC_YOUTUBE_AVAILABILITY_URL } from '$env/static/public'
2
- import { TrackingEvent } from '$lib/enums/TrackingEvent'
3
- import { track } from '$lib/tracking'
4
2
 
5
3
  export async function isYouTubeVideoAvailableInRegion(videoId: string): Promise<boolean> {
6
4
  const region = window.PlayPilotLinkInjections?.region?.toUpperCase()
@@ -18,8 +16,9 @@ export async function isYouTubeVideoAvailableInRegion(videoId: string): Promise<
18
16
  if (!data.blocked && !!data.allowed && !data.allowed?.includes(region)) return false
19
17
 
20
18
  return true
21
- } catch (error: any) {
22
- track(TrackingEvent.YouTubeAvailabilityRequestFailed, null, { message: error.message })
19
+ } catch {
20
+ // Silently fail for now
21
+ // track(TrackingEvent.YouTubeAvailabilityRequestFailed, null, { message: error.message })
23
22
 
24
23
  return false
25
24
  }
@@ -169,7 +169,6 @@ export function injectLinksInDocument(elements: HTMLElement[], injections: LinkI
169
169
  if (document.querySelector(keySelector)) insertInTextDisclaimer(elements)
170
170
 
171
171
  return mergedInjections.filter(i => i.title_details).map((injection, index) => {
172
- // Favour manual injections over AI injections
173
172
  const hasManualEquivalent = !injection.manual && isAvailableAsManualInjection(injection, index, mergedInjections)
174
173
  const duplicate = injection.duplicate ?? hasManualEquivalent
175
174
 
@@ -307,9 +306,6 @@ function addCSSVariablesToLinks(): void {
307
306
  }
308
307
  }
309
308
 
310
- /**
311
- * Add event listeners to all injected links. These events are for both the popover and the modal.
312
- */
313
309
  function addLinkInjectionEventListeners(injections: LinkInjection[]): void {
314
310
  window.addEventListener('mousemove', destroyLinkPopoverOnMouseleave)
315
311
  window.addEventListener('click', (event) => openModalForInjectedLink(event, injections))
@@ -341,10 +337,6 @@ export function clearLinkInjections(): void {
341
337
  destroyLinkPopover(false)
342
338
  }
343
339
 
344
- /**
345
- * Clear specific link injection from the page
346
- * @param key Given of the injection to be removed from the page
347
- */
348
340
  export function clearLinkInjection(key: string): void {
349
341
  const element: HTMLAnchorElement | null = document.querySelector(`[${keyDataAttribute}="${key}"]`)
350
342
  if (!element) return
package/src/lib/meta.ts CHANGED
@@ -68,7 +68,8 @@ export function getDatetime(datetime: string): string | null {
68
68
  }
69
69
 
70
70
  export function getSchemaJson(): Record<string, any> {
71
- const schemaElement = document.querySelector('[type="application/ld+json"]')
71
+ const schemaElements = Array.from(document.querySelectorAll('[type="application/ld+json"]'))
72
+ const schemaElement = schemaElements.find(element => element.textContent.includes('dateModified') || element.textContent.includes('datePublished'))
72
73
 
73
74
  if (!schemaElement) return {}
74
75
 
@@ -128,9 +128,14 @@
128
128
  line-height: 1.8;
129
129
 
130
130
  nav {
131
- display: flex;
131
+ display: grid;
132
+ grid-template-columns: 1fr 1fr;
132
133
  gap: margin(1);
133
134
 
135
+ @include desktop {
136
+ display: flex;
137
+ }
138
+
134
139
  a {
135
140
  padding: margin(0.25) margin(0.75);
136
141
  border: 1px solid currentColor;
@@ -1,8 +1,6 @@
1
1
  import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
  import { isYouTubeVideoAvailableInRegion } from '$lib/api/youtubeAvailability'
3
3
  import { fakeFetch } from '../../helpers'
4
- import { track } from '$lib/tracking'
5
- import { TrackingEvent } from '$lib/enums/TrackingEvent'
6
4
 
7
5
  vi.mock('$lib/tracking', () => ({
8
6
  track: vi.fn(),
@@ -64,7 +62,9 @@ describe('youtubeAvailability', () => {
64
62
  fakeFetch({ ok: false, status: 500 })
65
63
 
66
64
  expect(await isYouTubeVideoAvailableInRegion('video-id')).toBe(false)
67
- expect(track).toHaveBeenCalledWith(TrackingEvent.YouTubeAvailabilityRequestFailed, null, { message: expect.any(String) })
65
+
66
+ // For now it's silently failing on purpose
67
+ // expect(track).toHaveBeenCalledWith(TrackingEvent.YouTubeAvailabilityRequestFailed, null, { message: expect.any(String) })
68
68
  })
69
69
  })
70
70
  })
@@ -240,9 +240,9 @@ describe('meta.js', () => {
240
240
  })
241
241
 
242
242
  it('Should return schema relevant object', () => {
243
- document.body.innerHTML = '<script type="application/ld+json">{ "key": "value" }</script>'
243
+ document.body.innerHTML = '<script type="application/ld+json">{ "key": "value", "dateModified": "a" }</script>'
244
244
 
245
- expect(getSchemaJson()).toEqual({ key: 'value' })
245
+ expect(getSchemaJson()).toEqual({ key: 'value', dateModified: 'a' })
246
246
  })
247
247
 
248
248
  it('Should return empty object when json object is invalid', () => {
@@ -261,5 +261,14 @@ describe('meta.js', () => {
261
261
  document.body.innerHTML = '<script type="application/ld+json">{ "key": "Some "unescaped" value" }</script>'
262
262
  expect(getSchemaJson()).toEqual({})
263
263
  })
264
+
265
+ it('Should return script with dateModified if multiple scripts are present', () => {
266
+ document.body.innerHTML = `
267
+ <script type="application/ld+json"></script>
268
+ <script type="application/ld+json">{ "dateModified": "a" }</script>
269
+ `
270
+
271
+ expect(getSchemaJson()).toEqual({ dateModified: 'a' })
272
+ })
264
273
  })
265
274
  })
@@ -0,0 +1,105 @@
1
+ // vite._mount.config.js
2
+ import path from "path";
3
+ import * as dotenv from "file:///C:/Sites/playpilot-link-injection/node_modules/dotenv/lib/main.js";
4
+ import { defineConfig } from "file:///C:/Sites/playpilot-link-injection/node_modules/vitest/dist/config.js";
5
+ import { svelte } from "file:///C:/Sites/playpilot-link-injection/node_modules/@sveltejs/vite-plugin-svelte/src/index.js";
6
+ import cssInjectedByJsPlugin from "file:///C:/Sites/playpilot-link-injection/node_modules/vite-plugin-css-injected-by-js/dist/esm/index.js";
7
+
8
+ // package.json
9
+ var package_default = {
10
+ name: "@playpilot/tpi",
11
+ version: "8.10.3",
12
+ type: "module",
13
+ scripts: {
14
+ dev: "vite dev",
15
+ "dev-build": "npx http-server . /build.html -p 3000",
16
+ build: "vite build --config vite._main.config.js && vite build --config vite._mount.config.js && vite build --config vite._mount.config.js --mode editorial",
17
+ preview: "vite preview",
18
+ check: "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
19
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
20
+ format: "prettier --write .",
21
+ lint: "prettier --check . && eslint .",
22
+ "test:unit": "vitest",
23
+ test: "npm run test:unit -- --run",
24
+ release: "node release.js"
25
+ },
26
+ devDependencies: {
27
+ "@playpilot/retargeting-tracking": "^0.1.0",
28
+ "@sveltejs/adapter-auto": "^7.0.1",
29
+ "@sveltejs/kit": "^2.56.1",
30
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
31
+ "@testing-library/svelte": "^5.2.6",
32
+ "@types/node": "^25.5.2",
33
+ "@typescript-eslint/eslint-plugin": "^8.32.1",
34
+ "@typescript-eslint/parser": "^8.32.1",
35
+ dotenv: "^17.4.1",
36
+ eslint: "^9.27.0",
37
+ "eslint-config-prettier": "^9.1.0",
38
+ "eslint-plugin-svelte": "^3.15.0",
39
+ globals: "^15.0.0",
40
+ "happy-dom": "^16.8.1",
41
+ prettier: "^3.8.3",
42
+ "prettier-plugin-svelte": "^3.2.6",
43
+ sass: "^1.99.0",
44
+ svelte: "5.44.1",
45
+ "svelte-check": "^4.0.0",
46
+ "svelte-preprocess": "^6.0.3",
47
+ "svelte-tiny-slider": "^2.7.1",
48
+ typescript: "^5.9.3",
49
+ "typescript-eslint": "^8.59.2",
50
+ vite: "^5.4.21",
51
+ "vite-plugin-css-injected-by-js": "^4.0.1",
52
+ vitest: "^2.1.9"
53
+ }
54
+ };
55
+
56
+ // vite._mount.config.js
57
+ var __vite_injected_original_dirname = "C:\\Sites\\playpilot-link-injection";
58
+ dotenv.config({ path: ".env" });
59
+ var vite_mount_config_default = defineConfig(({ mode }) => {
60
+ const isEditiorial = mode === "editorial";
61
+ return {
62
+ plugins: [
63
+ svelte(),
64
+ cssInjectedByJsPlugin(),
65
+ injectEnvVariables
66
+ ],
67
+ build: {
68
+ emptyOutDir: false,
69
+ rollupOptions: {
70
+ input: "./src/mount.ts",
71
+ output: {
72
+ format: "iife",
73
+ name: "PlayPilotMount",
74
+ entryFileNames: isEditiorial ? "editorial.mount.js" : "mount.js"
75
+ }
76
+ }
77
+ },
78
+ resolve: {
79
+ alias: {
80
+ "$lib": path.resolve(__vite_injected_original_dirname, "./src/lib")
81
+ }
82
+ },
83
+ define: {
84
+ __SCRIPT_VERSION__: JSON.stringify(package_default.version),
85
+ __IS_EDITORIAL_SCRIPT__: JSON.stringify(isEditiorial)
86
+ }
87
+ };
88
+ });
89
+ var injectEnvVariables = {
90
+ name: "resolve-env-variables",
91
+ /** @param {string} id */
92
+ resolveId(id) {
93
+ if (id === "$env/static/public") return "\0$env/static/public";
94
+ },
95
+ /** @param {string} id */
96
+ load(id) {
97
+ if (id === "\0$env/static/public") {
98
+ return Object.entries(process.env).filter(([key]) => key.startsWith("PUBLIC_")).map(([key, value]) => `export const ${key} = ${JSON.stringify(value)};`).join("\n");
99
+ }
100
+ }
101
+ };
102
+ export {
103
+ vite_mount_config_default as default
104
+ };
105
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5fbW91bnQuY29uZmlnLmpzIiwgInBhY2thZ2UuanNvbiJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIkM6XFxcXFNpdGVzXFxcXHBsYXlwaWxvdC1saW5rLWluamVjdGlvblwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiQzpcXFxcU2l0ZXNcXFxccGxheXBpbG90LWxpbmstaW5qZWN0aW9uXFxcXHZpdGUuX21vdW50LmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vQzovU2l0ZXMvcGxheXBpbG90LWxpbmstaW5qZWN0aW9uL3ZpdGUuX21vdW50LmNvbmZpZy5qc1wiO2ltcG9ydCBwYXRoIGZyb20gJ3BhdGgnXHJcbmltcG9ydCAqIGFzIGRvdGVudiBmcm9tICdkb3RlbnYnXHJcbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGVzdC9jb25maWcnXHJcbmltcG9ydCB7IHN2ZWx0ZSB9IGZyb20gJ0BzdmVsdGVqcy92aXRlLXBsdWdpbi1zdmVsdGUnXHJcbmltcG9ydCBjc3NJbmplY3RlZEJ5SnNQbHVnaW4gZnJvbSAndml0ZS1wbHVnaW4tY3NzLWluamVjdGVkLWJ5LWpzJ1xyXG5pbXBvcnQgcGFja2FnZUpzb24gZnJvbSAnLi9wYWNrYWdlLmpzb24nXHJcblxyXG5kb3RlbnYuY29uZmlnKHsgcGF0aDogJy5lbnYnIH0pXHJcblxyXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoKHsgbW9kZSB9KSA9PiB7XHJcbiAgY29uc3QgaXNFZGl0aW9yaWFsID0gbW9kZSA9PT0gJ2VkaXRvcmlhbCdcclxuXHJcbiAgcmV0dXJuIHtcclxuICAgIHBsdWdpbnM6IFtcclxuICAgICAgc3ZlbHRlKCksXHJcbiAgICAgIGNzc0luamVjdGVkQnlKc1BsdWdpbigpLFxyXG4gICAgICBpbmplY3RFbnZWYXJpYWJsZXMsXHJcbiAgICBdLFxyXG5cclxuICAgIGJ1aWxkOiB7XHJcbiAgICAgIGVtcHR5T3V0RGlyOiBmYWxzZSxcclxuICAgICAgcm9sbHVwT3B0aW9uczoge1xyXG4gICAgICAgIGlucHV0OiAnLi9zcmMvbW91bnQudHMnLFxyXG4gICAgICAgIG91dHB1dDoge1xyXG4gICAgICAgICAgZm9ybWF0OiAnaWlmZScsXHJcbiAgICAgICAgICBuYW1lOiAnUGxheVBpbG90TW91bnQnLFxyXG4gICAgICAgICAgZW50cnlGaWxlTmFtZXM6IGlzRWRpdGlvcmlhbCA/ICdlZGl0b3JpYWwubW91bnQuanMnIDogJ21vdW50LmpzJyxcclxuICAgICAgICB9LFxyXG4gICAgICB9LFxyXG4gICAgfSxcclxuXHJcbiAgICByZXNvbHZlOiB7XHJcbiAgICAgIGFsaWFzOiB7XHJcbiAgICAgICAgJyRsaWInOiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi9zcmMvbGliJyksXHJcbiAgICAgIH0sXHJcbiAgICB9LFxyXG5cclxuICAgIGRlZmluZToge1xyXG4gICAgICBfX1NDUklQVF9WRVJTSU9OX186IEpTT04uc3RyaW5naWZ5KHBhY2thZ2VKc29uLnZlcnNpb24pLFxyXG4gICAgICBfX0lTX0VESVRPUklBTF9TQ1JJUFRfXzogSlNPTi5zdHJpbmdpZnkoaXNFZGl0aW9yaWFsKSxcclxuICAgIH0sXHJcbiAgfVxyXG59KVxyXG5cclxuY29uc3QgaW5qZWN0RW52VmFyaWFibGVzID0ge1xyXG4gIG5hbWU6ICdyZXNvbHZlLWVudi12YXJpYWJsZXMnLFxyXG4gIC8qKiBAcGFyYW0ge3N0cmluZ30gaWQgKi9cclxuICByZXNvbHZlSWQoaWQpIHtcclxuICAgIGlmIChpZCA9PT0gJyRlbnYvc3RhdGljL3B1YmxpYycpIHJldHVybiAnXFwwJGVudi9zdGF0aWMvcHVibGljJ1xyXG4gIH0sXHJcbiAgLyoqIEBwYXJhbSB7c3RyaW5nfSBpZCAqL1xyXG4gIGxvYWQoaWQpIHtcclxuICAgIGlmIChpZCA9PT0gJ1xcMCRlbnYvc3RhdGljL3B1YmxpYycpIHtcclxuICAgICAgcmV0dXJuIE9iamVjdC5lbnRyaWVzKHByb2Nlc3MuZW52KVxyXG4gICAgICAgIC5maWx0ZXIoKFtrZXldKSA9PiBrZXkuc3RhcnRzV2l0aCgnUFVCTElDXycpKVxyXG4gICAgICAgIC5tYXAoKFtrZXksIHZhbHVlXSkgPT4gYGV4cG9ydCBjb25zdCAke2tleX0gPSAke0pTT04uc3RyaW5naWZ5KHZhbHVlKX07YClcclxuICAgICAgICAuam9pbignXFxuJylcclxuICAgIH1cclxuICB9LFxyXG59XHJcbiIsICJ7XHJcblx0XCJuYW1lXCI6IFwiQHBsYXlwaWxvdC90cGlcIixcclxuXHRcInZlcnNpb25cIjogXCI4LjEwLjNcIixcclxuXHRcInR5cGVcIjogXCJtb2R1bGVcIixcclxuXHRcInNjcmlwdHNcIjoge1xyXG5cdFx0XCJkZXZcIjogXCJ2aXRlIGRldlwiLFxyXG5cdFx0XCJkZXYtYnVpbGRcIjogXCJucHggaHR0cC1zZXJ2ZXIgLiAvYnVpbGQuaHRtbCAtcCAzMDAwXCIsXHJcblx0XHRcImJ1aWxkXCI6IFwidml0ZSBidWlsZCAtLWNvbmZpZyB2aXRlLl9tYWluLmNvbmZpZy5qcyAmJiB2aXRlIGJ1aWxkIC0tY29uZmlnIHZpdGUuX21vdW50LmNvbmZpZy5qcyAmJiB2aXRlIGJ1aWxkIC0tY29uZmlnIHZpdGUuX21vdW50LmNvbmZpZy5qcyAtLW1vZGUgZWRpdG9yaWFsXCIsXHJcblx0XHRcInByZXZpZXdcIjogXCJ2aXRlIHByZXZpZXdcIixcclxuXHRcdFwiY2hlY2tcIjogXCJzdmVsdGUta2l0IHN5bmMgJiYgc3ZlbHRlLWNoZWNrIC0tdHNjb25maWcgLi9qc2NvbmZpZy5qc29uXCIsXHJcblx0XHRcImNoZWNrOndhdGNoXCI6IFwic3ZlbHRlLWtpdCBzeW5jICYmIHN2ZWx0ZS1jaGVjayAtLXRzY29uZmlnIC4vanNjb25maWcuanNvbiAtLXdhdGNoXCIsXHJcblx0XHRcImZvcm1hdFwiOiBcInByZXR0aWVyIC0td3JpdGUgLlwiLFxyXG5cdFx0XCJsaW50XCI6IFwicHJldHRpZXIgLS1jaGVjayAuICYmIGVzbGludCAuXCIsXHJcblx0XHRcInRlc3Q6dW5pdFwiOiBcInZpdGVzdFwiLFxyXG5cdFx0XCJ0ZXN0XCI6IFwibnBtIHJ1biB0ZXN0OnVuaXQgLS0gLS1ydW5cIixcclxuXHRcdFwicmVsZWFzZVwiOiBcIm5vZGUgcmVsZWFzZS5qc1wiXHJcblx0fSxcclxuXHRcImRldkRlcGVuZGVuY2llc1wiOiB7XHJcblx0XHRcIkBwbGF5cGlsb3QvcmV0YXJnZXRpbmctdHJhY2tpbmdcIjogXCJeMC4xLjBcIixcclxuXHRcdFwiQHN2ZWx0ZWpzL2FkYXB0ZXItYXV0b1wiOiBcIl43LjAuMVwiLFxyXG5cdFx0XCJAc3ZlbHRlanMva2l0XCI6IFwiXjIuNTYuMVwiLFxyXG5cdFx0XCJAc3ZlbHRlanMvdml0ZS1wbHVnaW4tc3ZlbHRlXCI6IFwiXjQuMC4wXCIsXHJcblx0XHRcIkB0ZXN0aW5nLWxpYnJhcnkvc3ZlbHRlXCI6IFwiXjUuMi42XCIsXHJcblx0XHRcIkB0eXBlcy9ub2RlXCI6IFwiXjI1LjUuMlwiLFxyXG5cdFx0XCJAdHlwZXNjcmlwdC1lc2xpbnQvZXNsaW50LXBsdWdpblwiOiBcIl44LjMyLjFcIixcclxuXHRcdFwiQHR5cGVzY3JpcHQtZXNsaW50L3BhcnNlclwiOiBcIl44LjMyLjFcIixcclxuXHRcdFwiZG90ZW52XCI6IFwiXjE3LjQuMVwiLFxyXG5cdFx0XCJlc2xpbnRcIjogXCJeOS4yNy4wXCIsXHJcblx0XHRcImVzbGludC1jb25maWctcHJldHRpZXJcIjogXCJeOS4xLjBcIixcclxuXHRcdFwiZXNsaW50LXBsdWdpbi1zdmVsdGVcIjogXCJeMy4xNS4wXCIsXHJcblx0XHRcImdsb2JhbHNcIjogXCJeMTUuMC4wXCIsXHJcblx0XHRcImhhcHB5LWRvbVwiOiBcIl4xNi44LjFcIixcclxuXHRcdFwicHJldHRpZXJcIjogXCJeMy44LjNcIixcclxuXHRcdFwicHJldHRpZXItcGx1Z2luLXN2ZWx0ZVwiOiBcIl4zLjIuNlwiLFxyXG5cdFx0XCJzYXNzXCI6IFwiXjEuOTkuMFwiLFxyXG5cdFx0XCJzdmVsdGVcIjogXCI1LjQ0LjFcIixcclxuXHRcdFwic3ZlbHRlLWNoZWNrXCI6IFwiXjQuMC4wXCIsXHJcblx0XHRcInN2ZWx0ZS1wcmVwcm9jZXNzXCI6IFwiXjYuMC4zXCIsXHJcblx0XHRcInN2ZWx0ZS10aW55LXNsaWRlclwiOiBcIl4yLjcuMVwiLFxyXG5cdFx0XCJ0eXBlc2NyaXB0XCI6IFwiXjUuOS4zXCIsXHJcblx0XHRcInR5cGVzY3JpcHQtZXNsaW50XCI6IFwiXjguNTkuMlwiLFxyXG5cdFx0XCJ2aXRlXCI6IFwiXjUuNC4yMVwiLFxyXG5cdFx0XCJ2aXRlLXBsdWdpbi1jc3MtaW5qZWN0ZWQtYnktanNcIjogXCJeNC4wLjFcIixcclxuXHRcdFwidml0ZXN0XCI6IFwiXjIuMS45XCJcclxuXHR9XHJcbn1cclxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUF5UyxPQUFPLFVBQVU7QUFDMVQsWUFBWSxZQUFZO0FBQ3hCLFNBQVMsb0JBQW9CO0FBQzdCLFNBQVMsY0FBYztBQUN2QixPQUFPLDJCQUEyQjs7O0FDSmxDO0FBQUEsRUFDQyxNQUFRO0FBQUEsRUFDUixTQUFXO0FBQUEsRUFDWCxNQUFRO0FBQUEsRUFDUixTQUFXO0FBQUEsSUFDVixLQUFPO0FBQUEsSUFDUCxhQUFhO0FBQUEsSUFDYixPQUFTO0FBQUEsSUFDVCxTQUFXO0FBQUEsSUFDWCxPQUFTO0FBQUEsSUFDVCxlQUFlO0FBQUEsSUFDZixRQUFVO0FBQUEsSUFDVixNQUFRO0FBQUEsSUFDUixhQUFhO0FBQUEsSUFDYixNQUFRO0FBQUEsSUFDUixTQUFXO0FBQUEsRUFDWjtBQUFBLEVBQ0EsaUJBQW1CO0FBQUEsSUFDbEIsbUNBQW1DO0FBQUEsSUFDbkMsMEJBQTBCO0FBQUEsSUFDMUIsaUJBQWlCO0FBQUEsSUFDakIsZ0NBQWdDO0FBQUEsSUFDaEMsMkJBQTJCO0FBQUEsSUFDM0IsZUFBZTtBQUFBLElBQ2Ysb0NBQW9DO0FBQUEsSUFDcEMsNkJBQTZCO0FBQUEsSUFDN0IsUUFBVTtBQUFBLElBQ1YsUUFBVTtBQUFBLElBQ1YsMEJBQTBCO0FBQUEsSUFDMUIsd0JBQXdCO0FBQUEsSUFDeEIsU0FBVztBQUFBLElBQ1gsYUFBYTtBQUFBLElBQ2IsVUFBWTtBQUFBLElBQ1osMEJBQTBCO0FBQUEsSUFDMUIsTUFBUTtBQUFBLElBQ1IsUUFBVTtBQUFBLElBQ1YsZ0JBQWdCO0FBQUEsSUFDaEIscUJBQXFCO0FBQUEsSUFDckIsc0JBQXNCO0FBQUEsSUFDdEIsWUFBYztBQUFBLElBQ2QscUJBQXFCO0FBQUEsSUFDckIsTUFBUTtBQUFBLElBQ1Isa0NBQWtDO0FBQUEsSUFDbEMsUUFBVTtBQUFBLEVBQ1g7QUFDRDs7O0FEN0NBLElBQU0sbUNBQW1DO0FBT2xDLGNBQU8sRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUU5QixJQUFPLDRCQUFRLGFBQWEsQ0FBQyxFQUFFLEtBQUssTUFBTTtBQUN4QyxRQUFNLGVBQWUsU0FBUztBQUU5QixTQUFPO0FBQUEsSUFDTCxTQUFTO0FBQUEsTUFDUCxPQUFPO0FBQUEsTUFDUCxzQkFBc0I7QUFBQSxNQUN0QjtBQUFBLElBQ0Y7QUFBQSxJQUVBLE9BQU87QUFBQSxNQUNMLGFBQWE7QUFBQSxNQUNiLGVBQWU7QUFBQSxRQUNiLE9BQU87QUFBQSxRQUNQLFFBQVE7QUFBQSxVQUNOLFFBQVE7QUFBQSxVQUNSLE1BQU07QUFBQSxVQUNOLGdCQUFnQixlQUFlLHVCQUF1QjtBQUFBLFFBQ3hEO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxJQUVBLFNBQVM7QUFBQSxNQUNQLE9BQU87QUFBQSxRQUNMLFFBQVEsS0FBSyxRQUFRLGtDQUFXLFdBQVc7QUFBQSxNQUM3QztBQUFBLElBQ0Y7QUFBQSxJQUVBLFFBQVE7QUFBQSxNQUNOLG9CQUFvQixLQUFLLFVBQVUsZ0JBQVksT0FBTztBQUFBLE1BQ3RELHlCQUF5QixLQUFLLFVBQVUsWUFBWTtBQUFBLElBQ3REO0FBQUEsRUFDRjtBQUNGLENBQUM7QUFFRCxJQUFNLHFCQUFxQjtBQUFBLEVBQ3pCLE1BQU07QUFBQTtBQUFBLEVBRU4sVUFBVSxJQUFJO0FBQ1osUUFBSSxPQUFPLHFCQUFzQixRQUFPO0FBQUEsRUFDMUM7QUFBQTtBQUFBLEVBRUEsS0FBSyxJQUFJO0FBQ1AsUUFBSSxPQUFPLHdCQUF3QjtBQUNqQyxhQUFPLE9BQU8sUUFBUSxRQUFRLEdBQUcsRUFDOUIsT0FBTyxDQUFDLENBQUMsR0FBRyxNQUFNLElBQUksV0FBVyxTQUFTLENBQUMsRUFDM0MsSUFBSSxDQUFDLENBQUMsS0FBSyxLQUFLLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxLQUFLLFVBQVUsS0FBSyxDQUFDLEdBQUcsRUFDdkUsS0FBSyxJQUFJO0FBQUEsSUFDZDtBQUFBLEVBQ0Y7QUFDRjsiLAogICJuYW1lcyI6IFtdCn0K