@sjvair/monitor-map 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/lib/LoadScreen.js +4 -4
  2. package/dist/lib/components/MapLayersDisplayOptions.js +30 -23
  3. package/dist/lib/hms/hms.svelte.js +12 -12
  4. package/dist/lib/map/integrations/map-display-option.svelte.js +3 -2
  5. package/dist/lib/map/integrations/map-icon-manager.js +1 -1
  6. package/dist/lib/monitors/components/MonitorsDisplayOptions.js +35 -26
  7. package/dist/lib/monitors/monitors-icon-manager.svelte.js +16 -9
  8. package/dist/lib/monitors/monitors-map-integration.svelte.js +30 -24
  9. package/dist/lib/sjvair-air.webp +0 -0
  10. package/dist/lib/sjvair-air2.webp +0 -0
  11. package/dist/lib/sjvair-icon.avif +0 -0
  12. package/dist/lib/sjvair-icon.png +0 -0
  13. package/dist/lib/sjvair-icon2.avif +0 -0
  14. package/dist/lib/sjvair-icon2.png +0 -0
  15. package/dist/monitor-map/assets/{MonitorDetailPanel-DmN3xPui.js → MonitorDetailPanel-BU_pXZjp.js} +2 -2
  16. package/dist/monitor-map/sjvairMonitorMap.css +1 -1
  17. package/dist/monitor-map/sjvairMonitorMap.js +41 -41
  18. package/package.json +1 -1
  19. package/src/lib/components/MapLayersDisplayOptions.svelte +23 -10
  20. package/src/lib/ev-stations/components/EvStationsDisplayOptions.svelte +14 -2
  21. package/src/lib/ev-stations/ev-stations-map-integration.svelte.ts +4 -4
  22. package/src/lib/map/integrations/map-display-option.svelte.ts +5 -1
  23. package/src/lib/map/integrations/map-icon-manager.ts +4 -3
  24. package/src/lib/monitors/components/MonitorsDisplayOptions.svelte +4 -1
  25. package/src/lib/monitors/monitors-icon-manager.svelte.ts +3 -1
  26. package/src/lib/monitors/monitors-map-integration.svelte.ts +9 -9
@@ -18,13 +18,13 @@ function a(n) {
18
18
  };
19
19
  var a = e.comment(), o = e.first_child(a), s = (n) => {
20
20
  var a = i(), o = e.child(a), s = e.child(o), c = e.child(s);
21
- e.set_attribute(c, "srcset", "/sjvair-icon2.avif 229w, /sjvair-icon.avif 458w");
21
+ e.set_attribute(c, "srcset", "/sjvair-icon.avif 229w, /sjvair-icon2.avif 458w");
22
22
  var l = e.sibling(c);
23
23
  e.set_attribute(l, "srcset", "/sjvair-icon.webp 229w, /sjvair-icon2.webp 458w");
24
24
  var u = e.sibling(l);
25
- e.set_attribute(u, "srcset", "/sjvair-icon2.png 229w, /sjvair-icon.png 458w");
25
+ e.set_attribute(u, "srcset", "/sjvair-icon.png 229w, /sjvair-icon2.png 458w");
26
26
  var d = e.sibling(u);
27
- e.set_attribute(d, "src", "/sjvair-icon.png");
27
+ e.set_attribute(d, "src", "/sjvair-icon2.png");
28
28
  let f;
29
29
  e.reset(s);
30
30
  var p = e.sibling(s, 2), m = e.child(p);
@@ -40,7 +40,7 @@ function a(n) {
40
40
  var y = e.sibling(p, 2), b = e.child(y);
41
41
  e.set_attribute(b, "srcset", "/sjvair-air.avif 235w, /sjvair-air2.avif 469w");
42
42
  var x = e.sibling(b);
43
- e.set_attribute(x, "srcset", "/sjvair-air2.webp 235w, /sjvair-air.webp 469w");
43
+ e.set_attribute(x, "srcset", "/sjvair-air.webp 235w, /sjvair-air2.webp 469w");
44
44
  var S = e.sibling(x);
45
45
  e.set_attribute(S, "srcset", "/sjvair-air.png 235w, /sjvair-air2.png 469w");
46
46
  var C = e.sibling(S);
@@ -8,64 +8,71 @@ import { hmsSmokeMapIntegration as o } from "../hms/hms-smoke-map-integration.sv
8
8
  import * as s from "svelte/internal/client";
9
9
  import "svelte/internal/disclose-version";
10
10
  import "svelte/internal/flags/legacy";
11
+ import { CrosshairIcon as c, FlameIcon as l, WavesVerticalIcon as u, WindIcon as d } from "@lucide/svelte";
11
12
  //#region src/lib/components/MapLayersDisplayOptions.svelte
12
- var c = s.reactive_import(() => n), l = s.reactive_import(() => t), u = s.reactive_import(() => a), d = s.reactive_import(() => o), f = s.from_html("<p class=\"text-lg font-bold whitespace-nowrap underline\">Map Layers</p> <!> <!> <!> <!>", 1);
13
- function p(t, n) {
13
+ var f = s.reactive_import(() => n), p = s.reactive_import(() => t), m = s.reactive_import(() => a), h = s.reactive_import(() => o), g = s.from_html("<div class=\"flex gap-1 items-center\"><!> <!></div>"), _ = s.from_html("<p class=\"text-lg font-bold whitespace-nowrap underline\">Map Layers</p> <div class=\"flex gap-1 items-center\"><!> <!></div> <!> <div class=\"flex gap-1 items-center\"><!> <!></div> <div class=\"flex gap-1 items-center\"><!> <!></div>", 1);
14
+ function v(t, n) {
14
15
  s.push(n, !1), s.init(), r(t, {
15
16
  children: (t, n) => {
16
- var r = f(), a = s.sibling(s.first_child(r), 2);
17
- i(a, {
17
+ var r = _(), a = s.sibling(s.first_child(r), 2), o = s.child(a);
18
+ d(o, { size: "16" }), i(s.sibling(o, 2), {
18
19
  id: "wind",
19
20
  label: "Wind",
20
21
  get value() {
21
- return c().enabled;
22
+ return f().enabled;
22
23
  },
23
24
  set value(e) {
24
- c(c().enabled = e);
25
+ f(f().enabled = e);
25
26
  },
26
27
  $$legacy: !0
27
- });
28
- var o = s.sibling(a, 2), p = (e) => {
29
- i(e, {
28
+ }), s.reset(a);
29
+ var v = s.sibling(a, 2), y = (e) => {
30
+ var t = g(), n = s.child(t);
31
+ c(n, {
32
+ size: "16",
33
+ color: "#4A5FC6"
34
+ }), i(s.sibling(n, 2), {
30
35
  id: "collocation-sites",
31
36
  label: "Collocation Sites",
32
37
  get value() {
33
- return l().enabled;
38
+ return p().enabled;
34
39
  },
35
40
  set value(e) {
36
- l(l().enabled = e);
41
+ p(p().enabled = e);
37
42
  },
38
43
  $$legacy: !0
39
- });
44
+ }), s.reset(t), s.append(e, t);
40
45
  };
41
- s.if(o, (t) => {
42
- e.pollutant === "pm25" && t(p);
46
+ s.if(v, (t) => {
47
+ e.pollutant === "pm25" && t(y);
43
48
  });
44
- var m = s.sibling(o, 2);
45
- i(m, {
49
+ var b = s.sibling(v, 2), x = s.child(b);
50
+ l(x, { size: "16" }), i(s.sibling(x, 2), {
46
51
  id: "hms-fire",
47
52
  label: "HMS Fire",
48
53
  get value() {
49
- return u().enabled;
54
+ return m().enabled;
50
55
  },
51
56
  set value(e) {
52
- u(u().enabled = e);
57
+ m(m().enabled = e);
53
58
  },
54
59
  $$legacy: !0
55
- }), i(s.sibling(m, 2), {
60
+ }), s.reset(b);
61
+ var S = s.sibling(b, 2), C = s.child(S);
62
+ u(C, { size: "16" }), i(s.sibling(C, 2), {
56
63
  id: "hms-smoke",
57
64
  label: "HMS Smoke",
58
65
  get value() {
59
- return d().enabled;
66
+ return h().enabled;
60
67
  },
61
68
  set value(e) {
62
- d(d().enabled = e);
69
+ h(h().enabled = e);
63
70
  },
64
71
  $$legacy: !0
65
- }), s.append(t, r);
72
+ }), s.reset(S), s.append(t, r);
66
73
  },
67
74
  $$slots: { default: !0 }
68
75
  }), s.pop();
69
76
  }
70
77
  //#endregion
71
- export { p as default };
78
+ export { v as default };
@@ -1,8 +1,8 @@
1
1
  import * as e from "svelte/internal/client";
2
- import { featureCollection as t, point as n } from "@turf/helpers";
3
- import { getHMSFire as r, getHMSSmoke as i } from "@sjvair/sdk/hms";
4
- import a from "@turf/clusters-dbscan";
5
- import { SvelteMap as o } from "svelte/reactivity";
2
+ import { SvelteMap as t } from "svelte/reactivity";
3
+ import { featureCollection as n, point as r } from "@turf/helpers";
4
+ import { getHMSFire as i, getHMSSmoke as a } from "@sjvair/sdk/hms";
5
+ import o from "@turf/clusters-dbscan";
6
6
  //#region src/lib/hms/hms.svelte.ts
7
7
  var s = 2, c = 1, l = class {
8
8
  #e = e.state();
@@ -30,11 +30,11 @@ var s = 2, c = 1, l = class {
30
30
  await Promise.allSettled([this.loadSmoke(), this.loadFire()]);
31
31
  }
32
32
  async loadSmoke() {
33
- this.smoke = await i();
33
+ this.smoke = await a();
34
34
  }
35
35
  async loadFire() {
36
36
  try {
37
- let e = u((await r()).filter((e) => e.frp !== null));
37
+ let e = u((await i()).filter((e) => e.frp !== null));
38
38
  this.fire = e, this.fireGroups = d(e);
39
39
  } catch (e) {
40
40
  console.error("HMS fire load failed:", e);
@@ -51,22 +51,22 @@ function u(e) {
51
51
  }
52
52
  function d(e) {
53
53
  if (!e.length) return [];
54
- let r = a(t(e.map((e) => n(e.geometry.coordinates, {
54
+ let i = o(n(e.map((e) => r(e.geometry.coordinates, {
55
55
  fireId: e.id,
56
56
  frp: e.frp
57
57
  }))), s, {
58
58
  minPoints: c,
59
59
  units: "kilometers"
60
- }), i = new o();
61
- for (let e of r.features) {
62
- let t = e.properties, n = t.dbscan === "noise" ? `noise-${t.fireId}` : `cluster-${t.cluster}`, [r, a] = e.geometry.coordinates, o = i.get(n) ?? {
60
+ }), a = new t();
61
+ for (let e of i.features) {
62
+ let t = e.properties, n = t.dbscan === "noise" ? `noise-${t.fireId}` : `cluster-${t.cluster}`, [r, i] = e.geometry.coordinates, o = a.get(n) ?? {
63
63
  frps: [],
64
64
  lngs: [],
65
65
  lats: []
66
66
  };
67
- o.frps.push(t.frp), o.lngs.push(r), o.lats.push(a), i.set(n, o);
67
+ o.frps.push(t.frp), o.lngs.push(r), o.lats.push(i), a.set(n, o);
68
68
  }
69
- return Array.from(i.entries()).map(([e, { frps: t, lngs: n, lats: r }]) => ({
69
+ return Array.from(a.entries()).map(([e, { frps: t, lngs: n, lats: r }]) => ({
70
70
  id: `hms-fire-group-${e}`,
71
71
  coordinates: [n.reduce((e, t) => e + t, 0) / n.length, r.reduce((e, t) => e + t, 0) / r.length],
72
72
  avgFrp: t.reduce((e, t) => e + t, 0) / t.length,
@@ -8,9 +8,10 @@ var t = class {
8
8
  set value(t) {
9
9
  e.set(this.#e, t, !0);
10
10
  }
11
+ icon;
11
12
  label;
12
- constructor(t, n) {
13
- this.label = t, this.#e = e.state(e.proxy(n));
13
+ constructor(t, n, r) {
14
+ this.icon = r, this.label = t, this.#e = e.state(e.proxy(n));
14
15
  }
15
16
  };
16
17
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { mapManager as e } from "../map.svelte.js";
2
- import { XMap as t } from "@tstk/builtin-extensions";
2
+ import { SvelteMap as t } from "svelte/reactivity";
3
3
  //#region src/lib/map/integrations/map-icon-manager.ts
4
4
  var n = class {
5
5
  icons = new t();
@@ -6,22 +6,22 @@ import i from "../../components/ToggleSwitch.js";
6
6
  import * as a from "svelte/internal/client";
7
7
  import "svelte/internal/disclose-version";
8
8
  //#region src/lib/monitors/components/MonitorsDisplayOptions.svelte
9
- var o = a.from_html("<label class=\"cursor-pointer whitespace-nowrap select-none\"><input type=\"checkbox\"/> </label>"), s = a.from_html("<p class=\"text-lg font-bold underline\">Air Monitors</p> <div class=\"mb-2 w-full text-xs\"><div class=\"w-fit\"><!></div> <!></div> <!>", 1);
10
- function c(c, l) {
11
- a.push(l, !0);
12
- let u = [{
9
+ var o = a.from_html("<img class=\"w-3\"/>"), s = a.from_html("<label class=\"flex gap-1 cursor-pointer whitespace-nowrap select-none\"><input type=\"checkbox\"/> <!> </label>"), c = a.from_html("<p class=\"text-lg font-bold underline\">Air Monitors</p> <div class=\"mb-2 w-full text-xs\"><div class=\"w-fit\"><!></div> <!></div> <!>", 1);
10
+ function l(l, u) {
11
+ a.push(u, !0);
12
+ let d = [{
13
13
  label: "PM 2.5",
14
14
  value: "pm25"
15
15
  }, {
16
16
  label: "Ozone",
17
17
  value: "o3"
18
- }], d = a.derived(() => e.pollutant && e.pollutant === "pm25" ? Object.entries(t.displayOptions) : Object.entries(t.displayOptions).filter(([t, n]) => t === "inactive" || e.meta?.asIter.monitors.some((t) => t.label === n.label && e.pollutant && e.pollutant in t.entries)));
18
+ }], f = a.derived(() => e.pollutant && e.pollutant === "pm25" ? Object.entries(t.displayOptions) : Object.entries(t.displayOptions).filter(([t, n]) => t === "inactive" || e.meta?.asIter.monitors.some((t) => t.label === n.label && e.pollutant && e.pollutant in t.entries)));
19
19
  a.user_effect(() => {
20
20
  e.list = [], e.latest = null, e.update();
21
- }), n(c, {
22
- children: (n, c) => {
23
- var l = s(), f = a.sibling(a.first_child(l), 2), p = a.child(f);
24
- i(a.child(p), {
21
+ }), n(l, {
22
+ children: (n, l) => {
23
+ var u = c(), p = a.sibling(a.first_child(u), 2), m = a.child(p);
24
+ i(a.child(m), {
25
25
  id: "monitor-clusters",
26
26
  label: "Marker Clusters",
27
27
  get value() {
@@ -30,12 +30,12 @@ function c(c, l) {
30
30
  set value(e) {
31
31
  t.clustered = e;
32
32
  }
33
- }), a.reset(p);
34
- var m = a.sibling(p, 2), h = (t) => {
33
+ }), a.reset(m);
34
+ var h = a.sibling(m, 2), g = (t) => {
35
35
  r(t, {
36
36
  segmentLabel: "Pollutant:",
37
37
  get options() {
38
- return u;
38
+ return d;
39
39
  },
40
40
  get group() {
41
41
  return e.pollutant;
@@ -45,23 +45,32 @@ function c(c, l) {
45
45
  }
46
46
  });
47
47
  };
48
- a.if(m, (t) => {
49
- e.pollutant && t(h);
50
- }), a.reset(f);
51
- var g = a.sibling(f, 2);
52
- a.each(g, 17, () => a.get(d), ([e, t]) => t.label, (e, t) => {
48
+ a.if(h, (t) => {
49
+ e.pollutant && t(g);
50
+ }), a.reset(p);
51
+ var _ = a.sibling(p, 2);
52
+ a.each(_, 17, () => a.get(f), ([e, t]) => t.label, (e, t) => {
53
53
  var n = a.derived(() => a.to_array(a.get(t), 2));
54
- let r = () => a.get(n)[0], i = () => a.get(n)[1], s = a.derived(() => `${r()}-monitor-display-option`);
55
- var c = o(), l = a.child(c);
56
- a.remove_input_defaults(l);
57
- var u = a.sibling(l);
58
- a.reset(c), a.template_effect(() => {
59
- a.set_attribute(c, "for", a.get(s)), a.set_attribute(l, "id", a.get(s)), a.set_attribute(l, "name", i().label), a.set_text(u, ` ${i().label ?? ""}`);
60
- }), a.bind_checked(l, () => i().value, (e) => i().value = e), a.append(e, c);
61
- }), a.append(n, l);
54
+ let r = () => a.get(n)[0], i = () => a.get(n)[1], c = a.derived(() => `${r()}-monitor-display-option`);
55
+ var l = s(), u = a.child(l);
56
+ a.remove_input_defaults(u);
57
+ var d = a.sibling(u, 2), f = (e) => {
58
+ var t = o();
59
+ a.template_effect(() => {
60
+ a.set_attribute(t, "src", i().icon.image.src), a.set_attribute(t, "alt", i().icon.image.alt);
61
+ }), a.append(e, t);
62
+ };
63
+ a.if(d, (e) => {
64
+ i().icon && e(f);
65
+ });
66
+ var p = a.sibling(d);
67
+ a.reset(l), a.template_effect(() => {
68
+ a.set_attribute(l, "for", a.get(c)), a.set_attribute(u, "id", a.get(c)), a.set_attribute(u, "name", i().label), a.set_text(p, ` ${i().label ?? ""}`);
69
+ }), a.bind_checked(u, () => i().value, (e) => i().value = e), a.append(e, l);
70
+ }), a.append(n, u);
62
71
  },
63
72
  $$slots: { default: !0 }
64
73
  }), a.pop();
65
74
  }
66
75
  //#endregion
67
- export { c as default };
76
+ export { l as default };
@@ -8,8 +8,8 @@ var c = {
8
8
  circle: r,
9
9
  square: i,
10
10
  triangle: a
11
- }, l = 2, u = "#969696";
12
- function d(e, t) {
11
+ }, l = 2, u = "#969696", d = "#48c78e";
12
+ function f(e, t) {
13
13
  let n = `${e.location}-${e.is_active ? t.name : "default"}`;
14
14
  switch (e.type) {
15
15
  case "airgradient": return `${n}-circle`;
@@ -20,7 +20,7 @@ function d(e, t) {
20
20
  default: throw Error(`Map icon for ${e.device} has not been set`);
21
21
  }
22
22
  }
23
- var f = class extends o {
23
+ var p = class extends o {
24
24
  get iconSize() {
25
25
  return 24;
26
26
  }
@@ -28,10 +28,17 @@ var f = class extends o {
28
28
  super(), s.effect_root(() => {
29
29
  s.user_effect(() => {
30
30
  if (e.levels) {
31
- let r = [...e.levels, {
32
- name: "default",
33
- color: u
34
- }];
31
+ let r = [
32
+ ...e.levels,
33
+ {
34
+ name: "default",
35
+ color: u
36
+ },
37
+ {
38
+ name: "display",
39
+ color: d
40
+ }
41
+ ];
35
42
  for (let e of ["inside", "outside"]) for (let [i, a] of Object.entries(c)) for (let o of r) {
36
43
  let r = [
37
44
  this.idPrefix,
@@ -52,7 +59,7 @@ var f = class extends o {
52
59
  });
53
60
  });
54
61
  }
55
- }, p = class extends f {
62
+ }, m = class extends p {
56
63
  get idPrefix() {
57
64
  return "";
58
65
  }
@@ -61,4 +68,4 @@ var f = class extends o {
61
68
  }
62
69
  };
63
70
  //#endregion
64
- export { f as MonitorShapeIconManager, p as MonitorsIconManager, d as getIconId };
71
+ export { p as MonitorShapeIconManager, m as MonitorsIconManager, f as getIconId };
@@ -67,22 +67,28 @@ var m = {
67
67
  icons = new i();
68
68
  tooltipManager = new o();
69
69
  renderer = new u(this);
70
- displayOptions = {
71
- purpleair: new s("PurpleAir", !0),
72
- sjvair: new s("SJVAir non-FEM", !0),
73
- aqview: new s("AQview", !0),
74
- bam1022: new s("SJVAir FEM", !0),
75
- airnow: new s("AirNow", !0),
76
- inactive: new s("Inactive", !1),
77
- inside: new s("Inside", !1)
78
- };
70
+ #n = f.derived(() => ({
71
+ purpleair: new s("PurpleAir", !0, this.icons.get("outside-display-square")),
72
+ sjvair: new s("SJVAir non-FEM", !0, this.icons.get("outside-display-circle")),
73
+ aqview: new s("AQview", !0, this.icons.get("outside-display-triangle")),
74
+ bam1022: new s("SJVAir FEM", !0, this.icons.get("outside-display-triangle")),
75
+ airnow: new s("AirNow", !0, this.icons.get("outside-display-triangle")),
76
+ inactive: new s("Inactive", !1, this.icons.get("outside-default-square")),
77
+ inside: new s("Inside", !1, this.icons.get("inside-display-square"))
78
+ }));
79
+ get displayOptions() {
80
+ return f.get(this.#n);
81
+ }
82
+ set displayOptions(e) {
83
+ f.set(this.#n, e);
84
+ }
79
85
  onMonitorClick = null;
80
- #n = f.state(null);
86
+ #r = f.state(null);
81
87
  get selectedMonitorId() {
82
- return f.get(this.#n);
88
+ return f.get(this.#r);
83
89
  }
84
90
  set selectedMonitorId(e) {
85
- f.set(this.#n, e, !0);
91
+ f.set(this.#r, e, !0);
86
92
  }
87
93
  handleMonitorClick = (e) => {
88
94
  if (!this.onMonitorClick) return;
@@ -94,7 +100,7 @@ var m = {
94
100
  zoom: Math.max(t.map.getZoom(), 12)
95
101
  });
96
102
  };
97
- #r = f.derived(() => {
103
+ #i = f.derived(() => {
98
104
  if (!e.meta || !e.latest || !e.pollutant) return [];
99
105
  let t = e.meta.entryType(e.pollutant).asIter.levels;
100
106
  return Array.from(e.latest.values().map((e) => {
@@ -121,12 +127,12 @@ var m = {
121
127
  }));
122
128
  });
123
129
  get features() {
124
- return f.get(this.#r);
130
+ return f.get(this.#i);
125
131
  }
126
132
  set features(e) {
127
- f.set(this.#r, e);
133
+ f.set(this.#i, e);
128
134
  }
129
- #i = f.derived(() => {
135
+ #a = f.derived(() => {
130
136
  let e = ["any"], t = ["any", [
131
137
  "==",
132
138
  ["get", "location"],
@@ -152,12 +158,12 @@ var m = {
152
158
  ];
153
159
  });
154
160
  get filters() {
155
- return f.get(this.#i);
161
+ return f.get(this.#a);
156
162
  }
157
163
  set filters(e) {
158
- f.set(this.#i, e);
164
+ f.set(this.#a, e);
159
165
  }
160
- #a = f.derived(() => {
166
+ #o = f.derived(() => {
161
167
  let e = this.displayOptions, t = {};
162
168
  for (let n of this.features) {
163
169
  let r = n.properties;
@@ -174,17 +180,17 @@ var m = {
174
180
  return t;
175
181
  });
176
182
  get featuresByType() {
177
- return f.get(this.#a);
183
+ return f.get(this.#o);
178
184
  }
179
185
  set featuresByType(e) {
180
- f.set(this.#a, e);
186
+ f.set(this.#o, e);
181
187
  }
182
- #o = f.derived(() => !e.meta || !e.pollutant ? [] : e.meta.entryType(e.pollutant).asIter.levels ?? []);
188
+ #s = f.derived(() => !e.meta || !e.pollutant ? [] : e.meta.entryType(e.pollutant).asIter.levels ?? []);
183
189
  get clusterIconThresholds() {
184
- return f.get(this.#o);
190
+ return f.get(this.#s);
185
191
  }
186
192
  set clusterIconThresholds(e) {
187
- f.set(this.#o, e);
193
+ f.set(this.#s, e);
188
194
  }
189
195
  get mapLayer() {
190
196
  return {
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file