@mailwoman/bdc 8.3.0

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 (87) hide show
  1. package/README.md +7 -0
  2. package/index.ts +2 -0
  3. package/out/index.d.ts +3 -0
  4. package/out/index.d.ts.map +1 -0
  5. package/out/index.js +3 -0
  6. package/out/index.js.map +1 -0
  7. package/out/schema.d.ts +138 -0
  8. package/out/schema.d.ts.map +1 -0
  9. package/out/schema.js +88 -0
  10. package/out/schema.js.map +1 -0
  11. package/out/sdk/build-bdc.d.ts +214 -0
  12. package/out/sdk/build-bdc.d.ts.map +1 -0
  13. package/out/sdk/build-bdc.js +500 -0
  14. package/out/sdk/build-bdc.js.map +1 -0
  15. package/out/sdk/buildings.d.ts +84 -0
  16. package/out/sdk/buildings.d.ts.map +1 -0
  17. package/out/sdk/buildings.js +75 -0
  18. package/out/sdk/buildings.js.map +1 -0
  19. package/out/sdk/client.d.ts +237 -0
  20. package/out/sdk/client.d.ts.map +1 -0
  21. package/out/sdk/client.js +430 -0
  22. package/out/sdk/client.js.map +1 -0
  23. package/out/sdk/common.d.ts +279 -0
  24. package/out/sdk/common.d.ts.map +1 -0
  25. package/out/sdk/common.js +162 -0
  26. package/out/sdk/common.js.map +1 -0
  27. package/out/sdk/data-collection.d.ts +244 -0
  28. package/out/sdk/data-collection.d.ts.map +1 -0
  29. package/out/sdk/data-collection.js +50 -0
  30. package/out/sdk/data-collection.js.map +1 -0
  31. package/out/sdk/download.d.ts +36 -0
  32. package/out/sdk/download.d.ts.map +1 -0
  33. package/out/sdk/download.js +76 -0
  34. package/out/sdk/download.js.map +1 -0
  35. package/out/sdk/filing-dates.d.ts +57 -0
  36. package/out/sdk/filing-dates.d.ts.map +1 -0
  37. package/out/sdk/filing-dates.js +50 -0
  38. package/out/sdk/filing-dates.js.map +1 -0
  39. package/out/sdk/filing-landscape.d.ts +124 -0
  40. package/out/sdk/filing-landscape.d.ts.map +1 -0
  41. package/out/sdk/filing-landscape.js +216 -0
  42. package/out/sdk/filing-landscape.js.map +1 -0
  43. package/out/sdk/index.d.ts +15 -0
  44. package/out/sdk/index.d.ts.map +1 -0
  45. package/out/sdk/index.js +15 -0
  46. package/out/sdk/index.js.map +1 -0
  47. package/out/sdk/list-files.d.ts +39 -0
  48. package/out/sdk/list-files.d.ts.map +1 -0
  49. package/out/sdk/list-files.js +26 -0
  50. package/out/sdk/list-files.js.map +1 -0
  51. package/out/sdk/location.d.ts +40 -0
  52. package/out/sdk/location.d.ts.map +1 -0
  53. package/out/sdk/location.js +23 -0
  54. package/out/sdk/location.js.map +1 -0
  55. package/out/sdk/nearest-infrastructure.d.ts +84 -0
  56. package/out/sdk/nearest-infrastructure.d.ts.map +1 -0
  57. package/out/sdk/nearest-infrastructure.js +84 -0
  58. package/out/sdk/nearest-infrastructure.js.map +1 -0
  59. package/out/sdk/parsing.d.ts +57 -0
  60. package/out/sdk/parsing.d.ts.map +1 -0
  61. package/out/sdk/parsing.js +87 -0
  62. package/out/sdk/parsing.js.map +1 -0
  63. package/out/sdk/plausibility.d.ts +256 -0
  64. package/out/sdk/plausibility.d.ts.map +1 -0
  65. package/out/sdk/plausibility.js +334 -0
  66. package/out/sdk/plausibility.js.map +1 -0
  67. package/out/sdk/technologies.d.ts +229 -0
  68. package/out/sdk/technologies.d.ts.map +1 -0
  69. package/out/sdk/technologies.js +217 -0
  70. package/out/sdk/technologies.js.map +1 -0
  71. package/package.json +97 -0
  72. package/schema.ts +172 -0
  73. package/sdk/build-bdc.ts +810 -0
  74. package/sdk/buildings.ts +87 -0
  75. package/sdk/client.ts +643 -0
  76. package/sdk/common.ts +363 -0
  77. package/sdk/data-collection.ts +268 -0
  78. package/sdk/download.ts +91 -0
  79. package/sdk/filing-dates.ts +88 -0
  80. package/sdk/filing-landscape.ts +287 -0
  81. package/sdk/index.ts +14 -0
  82. package/sdk/list-files.ts +72 -0
  83. package/sdk/location.ts +45 -0
  84. package/sdk/nearest-infrastructure.ts +129 -0
  85. package/sdk/parsing.ts +124 -0
  86. package/sdk/plausibility.ts +512 -0
  87. package/sdk/technologies.ts +258 -0
@@ -0,0 +1,15 @@
1
+ export * from "./build-bdc.ts";
2
+ export * from "./buildings.ts";
3
+ export * from "./client.ts";
4
+ export * from "./common.ts";
5
+ export * from "./data-collection.ts";
6
+ export * from "./download.ts";
7
+ export * from "./filing-dates.ts";
8
+ export * from "./filing-landscape.ts";
9
+ export * from "./list-files.ts";
10
+ export * from "./location.ts";
11
+ export * from "./nearest-infrastructure.ts";
12
+ export * from "./parsing.ts";
13
+ export * from "./plausibility.ts";
14
+ export * from "./technologies.ts";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../sdk/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,eAAe,CAAA;AAC7B,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,6BAA6B,CAAA;AAC3C,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA"}
@@ -0,0 +1,15 @@
1
+ export * from "./build-bdc.js";
2
+ export * from "./buildings.js";
3
+ export * from "./client.js";
4
+ export * from "./common.js";
5
+ export * from "./data-collection.js";
6
+ export * from "./download.js";
7
+ export * from "./filing-dates.js";
8
+ export * from "./filing-landscape.js";
9
+ export * from "./list-files.js";
10
+ export * from "./location.js";
11
+ export * from "./nearest-infrastructure.js";
12
+ export * from "./parsing.js";
13
+ export * from "./plausibility.js";
14
+ export * from "./technologies.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../sdk/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,eAAe,CAAA;AAC7B,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,6BAA6B,CAAA;AAC3C,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file FCC BDC availability-file listing.
6
+ *
7
+ * Re-homed from Nexus's `sync/fcc/bdc/list-files.ts` (relicense-by-copy, no provenance headers):
8
+ * the `URLRoutePattern`-compiled route → a plain template literal (this port has no routing
9
+ * dependency), the `$BCDClient`-bound `retrieveAvailabilityFiles()` → a plain function taking a
10
+ * {@linkcode BDCClient}. Raw entries are parsed via Task 4's `parseRawBDCFile` and returned sorted
11
+ * ascending by revision (`compareRevisionAsc`) rather than in API order.
12
+ */
13
+ import type { BDCClient } from "./client.ts";
14
+ import { type BDCFile, type BDCFileCategory, type BDCProviderSubCategory, type BDCStateSubCategory, type BDCSummarySubCategory } from "./common.ts";
15
+ export interface RetrieveProviderAvailabilityFilesParams {
16
+ /**
17
+ * The filing's `as_of_date`, e.g. from {@linkcode file://./filing-dates.ts#resolveLatestVintage}.
18
+ */
19
+ asOfDate: string;
20
+ category: typeof BDCFileCategory.Provider;
21
+ subcategory: BDCProviderSubCategory;
22
+ }
23
+ export interface RetrieveStateAvailabilityFilesParams {
24
+ asOfDate: string;
25
+ category: typeof BDCFileCategory.State;
26
+ subcategory: BDCStateSubCategory;
27
+ }
28
+ export interface RetrieveSummaryAvailabilityFilesParams {
29
+ asOfDate: string;
30
+ category: typeof BDCFileCategory.Summary;
31
+ subcategory: BDCSummarySubCategory;
32
+ }
33
+ export type RetrieveAvailabilityFilesParams = RetrieveProviderAvailabilityFilesParams | RetrieveStateAvailabilityFilesParams | RetrieveSummaryAvailabilityFilesParams;
34
+ /**
35
+ * List the BDC availability files for a given `as_of_date`/category/subcategory, parsed into {@linkcode BDCFile}
36
+ * records and sorted ascending by revision date ({@linkcode compareRevisionAsc}).
37
+ */
38
+ export declare function retrieveAvailabilityFiles(client: BDCClient, { asOfDate, category, subcategory }: RetrieveAvailabilityFilesParams): Promise<BDCFile[]>;
39
+ //# sourceMappingURL=list-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-files.d.ts","sourceRoot":"","sources":["../../sdk/list-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAGN,KAAK,OAAO,EACZ,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAE1B,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,uCAAuC;IACvD;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,eAAe,CAAC,QAAQ,CAAA;IACzC,WAAW,EAAE,sBAAsB,CAAA;CACnC;AAED,MAAM,WAAW,oCAAoC;IACpD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,eAAe,CAAC,KAAK,CAAA;IACtC,WAAW,EAAE,mBAAmB,CAAA;CAChC;AAED,MAAM,WAAW,sCAAsC;IACtD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,eAAe,CAAC,OAAO,CAAA;IACxC,WAAW,EAAE,qBAAqB,CAAA;CAClC;AAED,MAAM,MAAM,+BAA+B,GACxC,uCAAuC,GACvC,oCAAoC,GACpC,sCAAsC,CAAA;AAMzC;;;GAGG;AACH,wBAAsB,yBAAyB,CAC9C,MAAM,EAAE,SAAS,EACjB,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,+BAA+B,GAClE,OAAO,CAAC,OAAO,EAAE,CAAC,CASpB"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file FCC BDC availability-file listing.
6
+ *
7
+ * Re-homed from Nexus's `sync/fcc/bdc/list-files.ts` (relicense-by-copy, no provenance headers):
8
+ * the `URLRoutePattern`-compiled route → a plain template literal (this port has no routing
9
+ * dependency), the `$BCDClient`-bound `retrieveAvailabilityFiles()` → a plain function taking a
10
+ * {@linkcode BDCClient}. Raw entries are parsed via Task 4's `parseRawBDCFile` and returned sorted
11
+ * ascending by revision (`compareRevisionAsc`) rather than in API order.
12
+ */
13
+ import { compareRevisionAsc, parseRawBDCFile, } from "./common.js";
14
+ /**
15
+ * List the BDC availability files for a given `as_of_date`/category/subcategory, parsed into {@linkcode BDCFile}
16
+ * records and sorted ascending by revision date ({@linkcode compareRevisionAsc}).
17
+ */
18
+ export async function retrieveAvailabilityFiles(client, { asOfDate, category, subcategory }) {
19
+ const pathname = `/map/downloads/listAvailabilityData/${encodeURIComponent(asOfDate)}`;
20
+ const body = await client.get(pathname, {
21
+ category,
22
+ subcategory,
23
+ });
24
+ return body.data.map(parseRawBDCFile).toSorted(compareRevisionAsc);
25
+ }
26
+ //# sourceMappingURL=list-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-files.js","sourceRoot":"","sources":["../../sdk/list-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EACN,kBAAkB,EAClB,eAAe,GAOf,MAAM,aAAa,CAAA;AAgCpB;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC9C,MAAiB,EACjB,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAmC;IAEpE,MAAM,QAAQ,GAAG,uCAAuC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAA;IAEtF,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAmC,QAAQ,EAAE;QACzE,QAAQ;QACR,WAAW;KACX,CAAC,CAAA;IAEF,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAA;AACnE,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ import type { Tagged } from "type-fest";
7
+ /**
8
+ * Matches a 10-digit FCC Broadband Serviceable Location ID, leading zeros included.
9
+ *
10
+ * @see {@linkcode isBroadbandServicableLocationID} for the type-predicate that uses this.
11
+ */
12
+ export declare const BROADBAND_SERVICABLE_LOCATION_INPUT_PATTERN: RegExp;
13
+ /**
14
+ * Unique ID for the Fabric location.
15
+ *
16
+ * The BSL ID remains persistent version to version when newer evidence indicates the position of the serviceable
17
+ * location or the presence of a serviceable location on a single location parcel is not significantly changed as
18
+ * compared to the prior version.
19
+ *
20
+ * - While IDs persist across Fabric versions does not mean that the latitude and longitude are unchanged.
21
+ * - An ID will remain consistent across versions when a different building is selected on a single parcel.
22
+ *
23
+ * Typed as a `string`, not a `number` — the FCC's own IDs are 10-digit zero-padded strings, and leading zeros make
24
+ * integer storage lossy.
25
+ *
26
+ * @type string
27
+ * @title Broadband Servicable Location ID
28
+ * @pattern ^\d{10}$
29
+ */
30
+ export type BroadbandServicableLocationID = Tagged<string, "BroadbandServicableLocationID">;
31
+ /**
32
+ * Type-predicate for checking if a value appears to be a valid Broadband Servicable Location ID.
33
+ *
34
+ * Accepts only a 10-digit string. A `number` input is always rejected, even if its digits would otherwise match —
35
+ * numeric storage would silently drop meaningful leading zeros.
36
+ *
37
+ * @internal
38
+ */
39
+ export declare function isBroadbandServicableLocationID(input: unknown): input is BroadbandServicableLocationID;
40
+ //# sourceMappingURL=location.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../sdk/location.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAEvC;;;;GAIG;AACH,eAAO,MAAM,2CAA2C,QAAa,CAAA;AAErE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,6BAA6B,GAAG,MAAM,CAAC,MAAM,EAAE,+BAA+B,CAAC,CAAA;AAE3F;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,6BAA6B,CAEtG"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ /**
7
+ * Matches a 10-digit FCC Broadband Serviceable Location ID, leading zeros included.
8
+ *
9
+ * @see {@linkcode isBroadbandServicableLocationID} for the type-predicate that uses this.
10
+ */
11
+ export const BROADBAND_SERVICABLE_LOCATION_INPUT_PATTERN = /^\d{10}$/;
12
+ /**
13
+ * Type-predicate for checking if a value appears to be a valid Broadband Servicable Location ID.
14
+ *
15
+ * Accepts only a 10-digit string. A `number` input is always rejected, even if its digits would otherwise match —
16
+ * numeric storage would silently drop meaningful leading zeros.
17
+ *
18
+ * @internal
19
+ */
20
+ export function isBroadbandServicableLocationID(input) {
21
+ return typeof input === "string" && BROADBAND_SERVICABLE_LOCATION_INPUT_PATTERN.test(input);
22
+ }
23
+ //# sourceMappingURL=location.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"location.js","sourceRoot":"","sources":["../../sdk/location.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,2CAA2C,GAAG,UAAU,CAAA;AAqBrE;;;;;;;GAOG;AACH,MAAM,UAAU,+BAA+B,CAAC,KAAc;IAC7D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,2CAA2C,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC5F,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `nearestInfrastructure` — a coverage-paired k-nearest read over the telecom-infrastructure POI
7
+ * categories (`telecom_exchange`/`tower_comms`, poi-taxonomy task 1 + the `--source osm` extractor,
8
+ * 2b tasks 1–2) that a caller can join against ANY layer's own `layer_coverage` survey-completeness
9
+ * table (2b task 4, decision 7). Typical caller: a BDC filing scorer that wants "what's the nearest
10
+ * real infrastructure to this claimed Broadband Serviceable Location, and does OUR layer even have
11
+ * survey evidence for that area" in one call.
12
+ *
13
+ * Two deviations from the task brief's literal sketch, both forced by what `poi-lookup.ts` and
14
+ * `@mailwoman/core/layers` actually expose (documented per the brief's "implementer picks and
15
+ * documents" instruction):
16
+ *
17
+ * - **`poiLookup` is an already-open {@link POILookup}, not a `POILookupOpts` this function
18
+ * constructs itself.** `POILookup`'s constructor eagerly loads the poi-taxonomy category dictionary
19
+ * and prepares three statements (see `poi-lookup.ts`) — reconstructing that per call would mean
20
+ * re-opening the SQLite handle and re-running the dictionary `SELECT` on every single
21
+ * `nearestInfrastructure` invocation. A scorer calling this once per filing candidate wants to open
22
+ * `poi.db` ONCE and reuse the same `POILookup` — this wrapper takes that shape: the caller owns
23
+ * `POILookup`'s open/dispose lifecycle (`using poiLookup = new POILookup(...)`), we just call
24
+ * `.search()` on it.
25
+ * - **`nearestInfrastructure` is `async`, not the brief's sync sketch.** `readLayerCoverage`
26
+ * (`@mailwoman/core/layers`) is `Promise`-returning — every layer-contract read in this codebase is
27
+ * (`readLayerManifest`, `filingLandscape` itself) — so pairing each POI hit with its coverage cell
28
+ * means awaiting one `readLayerCoverage` call per hit. A sync signature can't await that.
29
+ *
30
+ * {@link res9ShortCellToRes6Parent} (exported by `filing-landscape.ts`; see that file's docstring for
31
+ * why the res-9 → res-6 reconstruction is a straight concatenation, not `@mailwoman/spatial`'s
32
+ * `expandH3Cell`) turns each hit's res-9 cell into the res-6 cell every layer in this repo aggregates
33
+ * coverage at (poi.db's own convention; `bdc.db`'s `BDC_COVERAGE_H3_RESOLUTION` matches it
34
+ * deliberately — see `schema.ts`). `POI_H3_RESOLUTION` (`poi-lookup.ts`) is ALSO 9, so the two layers'
35
+ * spines agree without this module hardcoding a resolution of its own.
36
+ */
37
+ import type { DatabaseClient } from "@mailwoman/core/kysley/client";
38
+ import { type CoverageCell, type LayerContractDatabase } from "@mailwoman/core/layers";
39
+ import { type POILookup } from "@mailwoman/resolver-wof-sqlite/poi-lookup";
40
+ import { type PointLiteral } from "@mailwoman/spatial";
41
+ /**
42
+ * Ring budget default for {@link nearestInfrastructure} — wider than `POILookup`'s own internal `DEFAULT_MAX_RINGS`
43
+ * (16, ≈5.4 km) because telecom infrastructure (central offices, comm towers) is sparser per-area than poi.db's dense
44
+ * categories (cafes, etc.): 32 res-9 rings ≈ 11 km, a BDC-block-scale search radius that gives real infrastructure room
45
+ * to be found without over-restricting callers who DO want a tighter budget via `options.maxRings`.
46
+ */
47
+ export declare const NEAREST_INFRASTRUCTURE_DEFAULT_MAX_RINGS = 32;
48
+ /**
49
+ * One k-nearest telecom-infrastructure hit, paired with the res-6 coverage cell it falls in. `coverage: undefined`
50
+ * means `contractDB`'s layer has never surveyed that area (the meaning-of-zero rule; see `@mailwoman/core/layers`) —
51
+ * never conflate it with a covered-but-empty cell.
52
+ */
53
+ export interface InfrastructureHit {
54
+ categoryID: string;
55
+ name: string | null;
56
+ distanceM: number;
57
+ /**
58
+ * Res-9 short H3 cell of the hit ITSELF — not the (coarser) coverage cell; see `coverage.h3Cell` for that.
59
+ */
60
+ h3Cell: number;
61
+ coverage: CoverageCell | undefined;
62
+ }
63
+ export interface NearestInfrastructureOptions {
64
+ center: PointLiteral;
65
+ /**
66
+ * Poi-taxonomy category ids to search — fans out to `POILookup.search`'s `categoryIDs` (union across every resolved
67
+ * leaf, nearest-first). Typically `["telecom_exchange", "tower_comms"]`.
68
+ */
69
+ categoryIDs: string[];
70
+ limit?: number;
71
+ /**
72
+ * Ring budget. Default {@link NEAREST_INFRASTRUCTURE_DEFAULT_MAX_RINGS} (32) — NOT `POILookup`'s own internal default
73
+ * (16); see this module's docstring.
74
+ */
75
+ maxRings?: number;
76
+ }
77
+ /**
78
+ * K-nearest telecom-infrastructure POIs from `options.center`, each paired with the coverage cell it falls in per
79
+ * `contractDB`'s own `layer_coverage` table. Never throws on a sparse result — no infrastructure within `maxRings`, or
80
+ * every `categoryIDs` entry unresolvable against `poiLookup`'s dictionary — returns `[]`, the same discipline
81
+ * `POILookup.search` itself follows.
82
+ */
83
+ export declare function nearestInfrastructure(poiLookup: POILookup, contractDB: DatabaseClient<LayerContractDatabase>, options: NearestInfrastructureOptions): Promise<InfrastructureHit[]>;
84
+ //# sourceMappingURL=nearest-infrastructure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nearest-infrastructure.d.ts","sourceRoot":"","sources":["../../sdk/nearest-infrastructure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAAqB,KAAK,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACzG,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,2CAA2C,CAAA;AAC7F,OAAO,EAA+B,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAKnF;;;;;GAKG;AACH,eAAO,MAAM,wCAAwC,KAAK,CAAA;AAE1D;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAA;CAClC;AAED,MAAM,WAAW,4BAA4B;IAC5C,MAAM,EAAE,YAAY,CAAA;IACpB;;;OAGG;IACH,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAC1C,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,cAAc,CAAC,qBAAqB,CAAC,EACjD,OAAO,EAAE,4BAA4B,GACnC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkC9B"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * `nearestInfrastructure` — a coverage-paired k-nearest read over the telecom-infrastructure POI
7
+ * categories (`telecom_exchange`/`tower_comms`, poi-taxonomy task 1 + the `--source osm` extractor,
8
+ * 2b tasks 1–2) that a caller can join against ANY layer's own `layer_coverage` survey-completeness
9
+ * table (2b task 4, decision 7). Typical caller: a BDC filing scorer that wants "what's the nearest
10
+ * real infrastructure to this claimed Broadband Serviceable Location, and does OUR layer even have
11
+ * survey evidence for that area" in one call.
12
+ *
13
+ * Two deviations from the task brief's literal sketch, both forced by what `poi-lookup.ts` and
14
+ * `@mailwoman/core/layers` actually expose (documented per the brief's "implementer picks and
15
+ * documents" instruction):
16
+ *
17
+ * - **`poiLookup` is an already-open {@link POILookup}, not a `POILookupOpts` this function
18
+ * constructs itself.** `POILookup`'s constructor eagerly loads the poi-taxonomy category dictionary
19
+ * and prepares three statements (see `poi-lookup.ts`) — reconstructing that per call would mean
20
+ * re-opening the SQLite handle and re-running the dictionary `SELECT` on every single
21
+ * `nearestInfrastructure` invocation. A scorer calling this once per filing candidate wants to open
22
+ * `poi.db` ONCE and reuse the same `POILookup` — this wrapper takes that shape: the caller owns
23
+ * `POILookup`'s open/dispose lifecycle (`using poiLookup = new POILookup(...)`), we just call
24
+ * `.search()` on it.
25
+ * - **`nearestInfrastructure` is `async`, not the brief's sync sketch.** `readLayerCoverage`
26
+ * (`@mailwoman/core/layers`) is `Promise`-returning — every layer-contract read in this codebase is
27
+ * (`readLayerManifest`, `filingLandscape` itself) — so pairing each POI hit with its coverage cell
28
+ * means awaiting one `readLayerCoverage` call per hit. A sync signature can't await that.
29
+ *
30
+ * {@link res9ShortCellToRes6Parent} (exported by `filing-landscape.ts`; see that file's docstring for
31
+ * why the res-9 → res-6 reconstruction is a straight concatenation, not `@mailwoman/spatial`'s
32
+ * `expandH3Cell`) turns each hit's res-9 cell into the res-6 cell every layer in this repo aggregates
33
+ * coverage at (poi.db's own convention; `bdc.db`'s `BDC_COVERAGE_H3_RESOLUTION` matches it
34
+ * deliberately — see `schema.ts`). `POI_H3_RESOLUTION` (`poi-lookup.ts`) is ALSO 9, so the two layers'
35
+ * spines agree without this module hardcoding a resolution of its own.
36
+ */
37
+ import { readLayerCoverage } from "@mailwoman/core/layers";
38
+ import { POI_H3_RESOLUTION } from "@mailwoman/resolver-wof-sqlite/poi-lookup";
39
+ import { shortCellToInt } from "@mailwoman/spatial";
40
+ import { latLngToCell } from "h3-js";
41
+ import { res9ShortCellToRes6Parent } from "./filing-landscape.js";
42
+ /**
43
+ * Ring budget default for {@link nearestInfrastructure} — wider than `POILookup`'s own internal `DEFAULT_MAX_RINGS`
44
+ * (16, ≈5.4 km) because telecom infrastructure (central offices, comm towers) is sparser per-area than poi.db's dense
45
+ * categories (cafes, etc.): 32 res-9 rings ≈ 11 km, a BDC-block-scale search radius that gives real infrastructure room
46
+ * to be found without over-restricting callers who DO want a tighter budget via `options.maxRings`.
47
+ */
48
+ export const NEAREST_INFRASTRUCTURE_DEFAULT_MAX_RINGS = 32;
49
+ /**
50
+ * K-nearest telecom-infrastructure POIs from `options.center`, each paired with the coverage cell it falls in per
51
+ * `contractDB`'s own `layer_coverage` table. Never throws on a sparse result — no infrastructure within `maxRings`, or
52
+ * every `categoryIDs` entry unresolvable against `poiLookup`'s dictionary — returns `[]`, the same discipline
53
+ * `POILookup.search` itself follows.
54
+ */
55
+ export async function nearestInfrastructure(poiLookup, contractDB, options) {
56
+ const [longitude, latitude] = options.center.coordinates;
57
+ const hits = poiLookup.search({
58
+ categoryIDs: options.categoryIDs,
59
+ center: { latitude, longitude },
60
+ limit: options.limit,
61
+ maxRings: options.maxRings ?? NEAREST_INFRASTRUCTURE_DEFAULT_MAX_RINGS,
62
+ });
63
+ const infrastructureHits = [];
64
+ for (const hit of hits) {
65
+ if (hit.categoryID === null) {
66
+ // `categoryIDs` above always constrains the k-ring probe to real (non-zero) category ids (see
67
+ // POILookup#searchKRing), so a hit here always carries the category it was found under — this
68
+ // can't happen without a corrupted poi.db. Guard rather than silently coerce to "".
69
+ throw new Error(`nearestInfrastructure: hit ${JSON.stringify(hit.name)} has no categoryID`);
70
+ }
71
+ const h3Cell = shortCellToInt(latLngToCell(hit.latitude, hit.longitude, POI_H3_RESOLUTION));
72
+ const coverage = await readLayerCoverage(contractDB, res9ShortCellToRes6Parent(h3Cell));
73
+ infrastructureHits.push({
74
+ categoryID: hit.categoryID,
75
+ name: hit.name,
76
+ // `center` is always supplied above, so POILookup.search always attaches distanceM.
77
+ distanceM: hit.distanceM,
78
+ h3Cell,
79
+ coverage,
80
+ });
81
+ }
82
+ return infrastructureHits;
83
+ }
84
+ //# sourceMappingURL=nearest-infrastructure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nearest-infrastructure.js","sourceRoot":"","sources":["../../sdk/nearest-infrastructure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,EAAE,iBAAiB,EAAiD,MAAM,wBAAwB,CAAA;AACzG,OAAO,EAAE,iBAAiB,EAAkB,MAAM,2CAA2C,CAAA;AAC7F,OAAO,EAAE,cAAc,EAAkC,MAAM,oBAAoB,CAAA;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAEpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wCAAwC,GAAG,EAAE,CAAA;AAiC1D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAC1C,SAAoB,EACpB,UAAiD,EACjD,OAAqC;IAErC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAA;IAExD,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC;QAC7B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE;QAC/B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,wCAAwC;KACtE,CAAC,CAAA;IAEF,MAAM,kBAAkB,GAAwB,EAAE,CAAA;IAElD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,8FAA8F;YAC9F,8FAA8F;YAC9F,oFAAoF;YACpF,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QAC5F,CAAC;QAED,MAAM,MAAM,GAAG,cAAc,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAAW,CAAC,CAAA;QACrG,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,UAAU,EAAE,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAA;QAEvF,kBAAkB,CAAC,IAAI,CAAC;YACvB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,oFAAoF;YACpF,SAAS,EAAE,GAAG,CAAC,SAAU;YACzB,MAAM;YACN,QAAQ;SACR,CAAC,CAAA;IACH,CAAC;IAED,OAAO,kBAAkB,CAAA;AAC1B,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file FCC BDC availability CSV byte-level parser.
6
+ *
7
+ * Re-homed from Nexus's `sync/fcc/bdc/parsing.ts` (relicense-by-copy, no provenance headers): the same
8
+ * byte-scanning generator over the FCC's 12-column availability CSV — see the Nexus `RawBSLAvailabilityRow`
9
+ * tuple (`sync/fcc/bdc/block-aggregator.ts`) for the column order this scan assumes: frn, provider_id,
10
+ * brand_name, location_id, technology, max_advertised_download_speed, max_advertised_upload_speed,
11
+ * low_latency, business_residential_code, state_usps, block_geoid, h3_res8_id. Changed only where the
12
+ * pre-registered 2a decisions require: `geoid` (column 10, `block_geoid`) decodes to an ASCII string
13
+ * instead of staying a raw `Uint8Array` slice (decision 3), and `location_id` (column 3) stays a string
14
+ * instead of `parseInt`ing it, preserving leading zeros (decision 1). `business_residential_code` is
15
+ * likewise decoded to its ASCII string here — the Nexus original kept only the field's first raw byte as
16
+ * a bare `number`, which this port's `BDCAvailabilityRow` shape doesn't call for.
17
+ *
18
+ * Columns 0-2 (frn, provider_id, brand_name) and 9, 11 (state_usps, h3_res8_id) are scanned over but
19
+ * never sliced into the output record: `provider_id` comes from the `providerID` parameter instead (the
20
+ * FCC partitions availability files per provider, so the caller already knows it), and FRN/brand/state/H3
21
+ * join concerns are out of scope for 2a (decision 8 — provider identity is a 2c registry-join seam).
22
+ */
23
+ import type { ProviderID } from "./common.ts";
24
+ /**
25
+ * A single parsed row of FCC BDC availability data.
26
+ *
27
+ * @see {@linkcode takeAvailabilityLine}
28
+ */
29
+ export interface BDCAvailabilityRow {
30
+ provider_id: number;
31
+ /**
32
+ * Kept as a string — the FCC's `location_id` values are zero-padded 10-digit strings; `parseInt`ing would lose
33
+ * leading zeros (2a decision 1).
34
+ */
35
+ location_id: string;
36
+ technology_code: number;
37
+ max_advertised_download_speed: number;
38
+ max_advertised_upload_speed: number;
39
+ low_latency: 0 | 1;
40
+ business_residential_code: string;
41
+ /**
42
+ * Decoded to an ASCII string at the parse boundary (2a decision 3) — joins `TIGERBlockTable.GEOID` (note: uppercase
43
+ * column on that side).
44
+ */
45
+ geoid: string;
46
+ }
47
+ /**
48
+ * Given a buffer containing FCC BDC availability CSV data, yield each data row (the header row is skipped) as a
49
+ * {@linkcode BDCAvailabilityRow}.
50
+ *
51
+ * A byte-level scan, not a general CSV parser: it tracks comma/newline byte positions directly and only toggles
52
+ * quote-awareness via a running double-quote count (an odd count means the scanner is currently inside a quoted field,
53
+ * so a comma there isn't a column delimiter) — matching the Nexus original's approach for this specific, known-shaped
54
+ * 12-column file rather than reaching for a general CSV library.
55
+ */
56
+ export declare function takeAvailabilityLine(csvBuffer: Buffer, providerID: ProviderID): Iterable<BDCAvailabilityRow>;
57
+ //# sourceMappingURL=parsing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsing.d.ts","sourceRoot":"","sources":["../../sdk/parsing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAgB7C;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,6BAA6B,EAAE,MAAM,CAAA;IACrC,2BAA2B,EAAE,MAAM,CAAA;IACnC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAA;IAClB,yBAAyB,EAAE,MAAM,CAAA;IACjC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;GAQG;AACH,wBAAiB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAmD7G"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file FCC BDC availability CSV byte-level parser.
6
+ *
7
+ * Re-homed from Nexus's `sync/fcc/bdc/parsing.ts` (relicense-by-copy, no provenance headers): the same
8
+ * byte-scanning generator over the FCC's 12-column availability CSV — see the Nexus `RawBSLAvailabilityRow`
9
+ * tuple (`sync/fcc/bdc/block-aggregator.ts`) for the column order this scan assumes: frn, provider_id,
10
+ * brand_name, location_id, technology, max_advertised_download_speed, max_advertised_upload_speed,
11
+ * low_latency, business_residential_code, state_usps, block_geoid, h3_res8_id. Changed only where the
12
+ * pre-registered 2a decisions require: `geoid` (column 10, `block_geoid`) decodes to an ASCII string
13
+ * instead of staying a raw `Uint8Array` slice (decision 3), and `location_id` (column 3) stays a string
14
+ * instead of `parseInt`ing it, preserving leading zeros (decision 1). `business_residential_code` is
15
+ * likewise decoded to its ASCII string here — the Nexus original kept only the field's first raw byte as
16
+ * a bare `number`, which this port's `BDCAvailabilityRow` shape doesn't call for.
17
+ *
18
+ * Columns 0-2 (frn, provider_id, brand_name) and 9, 11 (state_usps, h3_res8_id) are scanned over but
19
+ * never sliced into the output record: `provider_id` comes from the `providerID` parameter instead (the
20
+ * FCC partitions availability files per provider, so the caller already knows it), and FRN/brand/state/H3
21
+ * join concerns are out of scope for 2a (decision 8 — provider identity is a 2c registry-join seam).
22
+ */
23
+ /**
24
+ * Byte values this scanner switches on.
25
+ *
26
+ * Local to this file — no generic newline-delimited-file utility exists elsewhere in the repo to import. Nexus's
27
+ * equivalent (`LineDelimitedCharacter`) lived in `@isp.nexus/sdk/files`, a workspace this port doesn't carry over, and
28
+ * repo convention forbids TS `enum` anyway (`erasableSyntaxOnly`).
29
+ */
30
+ const CSVByte = {
31
+ Newline: 10,
32
+ Comma: 44,
33
+ DoubleQuote: 34,
34
+ One: 49,
35
+ };
36
+ /**
37
+ * Given a buffer containing FCC BDC availability CSV data, yield each data row (the header row is skipped) as a
38
+ * {@linkcode BDCAvailabilityRow}.
39
+ *
40
+ * A byte-level scan, not a general CSV parser: it tracks comma/newline byte positions directly and only toggles
41
+ * quote-awareness via a running double-quote count (an odd count means the scanner is currently inside a quoted field,
42
+ * so a comma there isn't a column delimiter) — matching the Nexus original's approach for this specific, known-shaped
43
+ * 12-column file rather than reaching for a general CSV library.
44
+ */
45
+ export function* takeAvailabilityLine(csvBuffer, providerID) {
46
+ // Skip the header row.
47
+ let byteIndex = csvBuffer.indexOf(CSVByte.Newline) + 1;
48
+ const contentDelimiters = new Uint32Array(12); // 12 columns
49
+ contentDelimiters[0] = byteIndex;
50
+ let delimiterIndex = 1;
51
+ let doubleQuoteCount = 0;
52
+ while (byteIndex < csvBuffer.length) {
53
+ const byte = csvBuffer[byteIndex];
54
+ if (byte === CSVByte.DoubleQuote) {
55
+ doubleQuoteCount++;
56
+ }
57
+ if (byte === CSVByte.Comma && doubleQuoteCount % 2 === 0) {
58
+ contentDelimiters[delimiterIndex] = byteIndex;
59
+ delimiterIndex++;
60
+ }
61
+ if (byte === CSVByte.Newline) {
62
+ contentDelimiters[delimiterIndex] = CSVByte.Newline;
63
+ const slices = [];
64
+ // Skip columns 0-2 (frn, provider_id, brand_name) — see the file header for why.
65
+ for (let i = 3; i < contentDelimiters.length; i++) {
66
+ const start = contentDelimiters[i] + 1;
67
+ const end = contentDelimiters[i + 1];
68
+ slices.push(csvBuffer.subarray(start, end));
69
+ }
70
+ const record = {
71
+ provider_id: providerID,
72
+ location_id: slices[0].toString("ascii"),
73
+ technology_code: Number.parseInt(slices[1].toString(), 10),
74
+ max_advertised_download_speed: Number.parseInt(slices[2].toString(), 10),
75
+ max_advertised_upload_speed: Number.parseInt(slices[3].toString(), 10),
76
+ low_latency: slices[4][0] === CSVByte.One ? 1 : 0,
77
+ business_residential_code: slices[5].toString("ascii"),
78
+ geoid: slices[7].toString("ascii"),
79
+ };
80
+ yield record;
81
+ delimiterIndex = 1;
82
+ doubleQuoteCount = 0;
83
+ }
84
+ byteIndex++;
85
+ }
86
+ }
87
+ //# sourceMappingURL=parsing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsing.js","sourceRoot":"","sources":["../../sdk/parsing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH;;;;;;GAMG;AACH,MAAM,OAAO,GAAG;IACf,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,EAAE;IACT,WAAW,EAAE,EAAE;IACf,GAAG,EAAE,EAAE;CACE,CAAA;AA0BV;;;;;;;;GAQG;AACH,MAAM,SAAS,CAAC,CAAC,oBAAoB,CAAC,SAAiB,EAAE,UAAsB;IAC9E,uBAAuB;IACvB,IAAI,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACtD,MAAM,iBAAiB,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAA,CAAC,aAAa;IAC3D,iBAAiB,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;IAChC,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,IAAI,gBAAgB,GAAG,CAAC,CAAA;IAExB,OAAO,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAA;QAEjC,IAAI,IAAI,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC;YAClC,gBAAgB,EAAE,CAAA;QACnB,CAAC;QAED,IAAI,IAAI,KAAK,OAAO,CAAC,KAAK,IAAI,gBAAgB,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1D,iBAAiB,CAAC,cAAc,CAAC,GAAG,SAAS,CAAA;YAE7C,cAAc,EAAE,CAAA;QACjB,CAAC;QAED,IAAI,IAAI,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAC9B,iBAAiB,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,OAAO,CAAA;YACnD,MAAM,MAAM,GAAa,EAAE,CAAA;YAE3B,iFAAiF;YACjF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACnD,MAAM,KAAK,GAAG,iBAAiB,CAAC,CAAC,CAAE,GAAG,CAAC,CAAA;gBACvC,MAAM,GAAG,GAAG,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;gBAEpC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;YAC5C,CAAC;YAED,MAAM,MAAM,GAAuB;gBAClC,WAAW,EAAE,UAAU;gBACvB,WAAW,EAAE,MAAM,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACzC,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;gBAC3D,6BAA6B,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;gBACzE,2BAA2B,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;gBACvE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClD,yBAAyB,EAAE,MAAM,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACvD,KAAK,EAAE,MAAM,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;aACnC,CAAA;YAED,MAAM,MAAM,CAAA;YACZ,cAAc,GAAG,CAAC,CAAA;YAClB,gBAAgB,GAAG,CAAC,CAAA;QACrB,CAAC;QAED,SAAS,EAAE,CAAA;IACZ,CAAC;AACF,CAAC"}