@flowmap.gl/data 8.0.0-alpha.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.
- package/LICENSE +199 -0
- package/dist/FlowMapAggregateAccessors.d.ts +15 -0
- package/dist/FlowMapAggregateAccessors.d.ts.map +1 -0
- package/dist/FlowMapAggregateAccessors.js +43 -0
- package/dist/FlowMapSelectors.d.ts +156 -0
- package/dist/FlowMapSelectors.d.ts.map +1 -0
- package/dist/FlowMapSelectors.js +831 -0
- package/dist/FlowMapState.d.ts +24 -0
- package/dist/FlowMapState.d.ts.map +1 -0
- package/dist/FlowMapState.js +2 -0
- package/dist/cluster/ClusterIndex.d.ts +42 -0
- package/dist/cluster/ClusterIndex.d.ts.map +1 -0
- package/dist/cluster/ClusterIndex.js +178 -0
- package/dist/cluster/cluster.d.ts +31 -0
- package/dist/cluster/cluster.d.ts.map +1 -0
- package/dist/cluster/cluster.js +206 -0
- package/dist/colors.d.ts +103 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +441 -0
- package/dist/getViewStateForLocations.d.ts +16 -0
- package/dist/getViewStateForLocations.d.ts.map +1 -0
- package/dist/getViewStateForLocations.js +30 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/provider/FlowMapDataProvider.d.ts +16 -0
- package/dist/provider/FlowMapDataProvider.d.ts.map +1 -0
- package/dist/provider/FlowMapDataProvider.js +17 -0
- package/dist/provider/LocalFlowMapDataProvider.d.ts +20 -0
- package/dist/provider/LocalFlowMapDataProvider.d.ts.map +1 -0
- package/dist/provider/LocalFlowMapDataProvider.js +87 -0
- package/dist/time.d.ts +24 -0
- package/dist/time.d.ts.map +1 -0
- package/dist/time.js +126 -0
- package/dist/types.d.ts +116 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +23 -0
- package/dist/util.d.ts +2 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +4 -0
- package/package.json +48 -0
- package/src/FlowMapAggregateAccessors.ts +60 -0
- package/src/FlowMapSelectors.ts +1407 -0
- package/src/FlowMapState.ts +26 -0
- package/src/cluster/ClusterIndex.ts +266 -0
- package/src/cluster/cluster.ts +299 -0
- package/src/colors.ts +723 -0
- package/src/getViewStateForLocations.ts +64 -0
- package/src/index.ts +10 -0
- package/src/provider/FlowMapDataProvider.ts +63 -0
- package/src/provider/LocalFlowMapDataProvider.ts +108 -0
- package/src/time.ts +160 -0
- package/src/types.ts +162 -0
- package/src/util.ts +3 -0
- package/tsconfig.json +11 -0
- package/typings.d.ts +1 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { LocationFilterMode, ViewportProps } from './types';
|
|
2
|
+
export interface FilterState {
|
|
3
|
+
selectedLocations: string[] | undefined;
|
|
4
|
+
selectedTimeRange: [Date, Date] | undefined;
|
|
5
|
+
locationFilterMode: LocationFilterMode;
|
|
6
|
+
}
|
|
7
|
+
export interface SettingsState {
|
|
8
|
+
animationEnabled: boolean;
|
|
9
|
+
fadeEnabled: boolean;
|
|
10
|
+
locationTotalsEnabled: boolean;
|
|
11
|
+
adaptiveScalesEnabled: boolean;
|
|
12
|
+
clusteringEnabled: boolean;
|
|
13
|
+
clusteringAuto: boolean;
|
|
14
|
+
clusteringLevel?: number;
|
|
15
|
+
darkMode: boolean;
|
|
16
|
+
fadeAmount: number;
|
|
17
|
+
colorScheme: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
export interface FlowMapState {
|
|
20
|
+
filterState: FilterState;
|
|
21
|
+
settingsState: SettingsState;
|
|
22
|
+
viewport: ViewportProps;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=FlowMapState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FlowMapState.d.ts","sourceRoot":"","sources":["../src/FlowMapState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAE,aAAa,EAAC,MAAM,SAAS,CAAC;AAE1D,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACxC,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC;IAC5C,kBAAkB,EAAE,kBAAkB,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;CACzB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmxvd01hcFN0YXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL0Zsb3dNYXBTdGF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtMb2NhdGlvbkZpbHRlck1vZGUsIFZpZXdwb3J0UHJvcHN9IGZyb20gJy4vdHlwZXMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEZpbHRlclN0YXRlIHtcbiAgc2VsZWN0ZWRMb2NhdGlvbnM6IHN0cmluZ1tdIHwgdW5kZWZpbmVkO1xuICBzZWxlY3RlZFRpbWVSYW5nZTogW0RhdGUsIERhdGVdIHwgdW5kZWZpbmVkO1xuICBsb2NhdGlvbkZpbHRlck1vZGU6IExvY2F0aW9uRmlsdGVyTW9kZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTZXR0aW5nc1N0YXRlIHtcbiAgYW5pbWF0aW9uRW5hYmxlZDogYm9vbGVhbjtcbiAgZmFkZUVuYWJsZWQ6IGJvb2xlYW47XG4gIGxvY2F0aW9uVG90YWxzRW5hYmxlZDogYm9vbGVhbjtcbiAgYWRhcHRpdmVTY2FsZXNFbmFibGVkOiBib29sZWFuO1xuICBjbHVzdGVyaW5nRW5hYmxlZDogYm9vbGVhbjtcbiAgY2x1c3RlcmluZ0F1dG86IGJvb2xlYW47XG4gIGNsdXN0ZXJpbmdMZXZlbD86IG51bWJlcjtcbiAgZGFya01vZGU6IGJvb2xlYW47XG4gIGZhZGVBbW91bnQ6IG51bWJlcjtcbiAgY29sb3JTY2hlbWU6IHN0cmluZyB8IHVuZGVmaW5lZDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGbG93TWFwU3RhdGUge1xuICBmaWx0ZXJTdGF0ZTogRmlsdGVyU3RhdGU7XG4gIHNldHRpbmdzU3RhdGU6IFNldHRpbmdzU3RhdGU7XG4gIHZpZXdwb3J0OiBWaWV3cG9ydFByb3BzO1xufVxuIl19
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AggregateFlow, Cluster, ClusterLevels, ClusterNode, FlowAccessors, FlowCountsMapReduce } from './../types';
|
|
2
|
+
export declare type LocationWeightGetter = (id: string) => number;
|
|
3
|
+
/**
|
|
4
|
+
* A data structure representing the cluster levels for efficient flow aggregation.
|
|
5
|
+
*/
|
|
6
|
+
export interface ClusterIndex<F> {
|
|
7
|
+
availableZoomLevels: number[];
|
|
8
|
+
getClusterById: (clusterId: string) => Cluster | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* List the nodes on the given zoom level.
|
|
11
|
+
*/
|
|
12
|
+
getClusterNodesFor: (zoom: number | undefined) => ClusterNode[] | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Get the min zoom level on which the location is not clustered.
|
|
15
|
+
*/
|
|
16
|
+
getMinZoomForLocation: (locationId: string) => number;
|
|
17
|
+
/**
|
|
18
|
+
* List the IDs of all locations in the cluster (leaves of the subtree starting in the cluster).
|
|
19
|
+
*/
|
|
20
|
+
expandCluster: (cluster: Cluster, targetZoom?: number) => string[];
|
|
21
|
+
/**
|
|
22
|
+
* Find the cluster the given location is residing in on the specified zoom level.
|
|
23
|
+
*/
|
|
24
|
+
findClusterFor: (locationId: string, zoom: number) => string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Aggregate flows for the specified zoom level.
|
|
27
|
+
*/
|
|
28
|
+
aggregateFlows: (flows: F[], zoom: number, { getFlowOriginId, getFlowDestId, getFlowMagnitude }: FlowAccessors<F>, options?: {
|
|
29
|
+
flowCountsMapReduce?: FlowCountsMapReduce<F>;
|
|
30
|
+
}) => (F | AggregateFlow)[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build ClusterIndex from the given cluster hierarchy
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildIndex<F>(clusterLevels: ClusterLevels): ClusterIndex<F>;
|
|
36
|
+
export declare function makeLocationWeightGetter<F>(flows: F[], { getFlowOriginId, getFlowDestId, getFlowMagnitude }: FlowAccessors<F>): LocationWeightGetter;
|
|
37
|
+
/**
|
|
38
|
+
* @param availableZoomLevels Must be sorted in ascending order
|
|
39
|
+
* @param targetZoom
|
|
40
|
+
*/
|
|
41
|
+
export declare function findAppropriateZoomLevel(availableZoomLevels: number[], targetZoom: number): number;
|
|
42
|
+
//# sourceMappingURL=ClusterIndex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClusterIndex.d.ts","sourceRoot":"","sources":["../../src/cluster/ClusterIndex.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,aAAa,EACb,OAAO,EACP,aAAa,EACb,WAAW,EACX,aAAa,EACb,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAGpB,oBAAY,oBAAoB,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,CAAC;IAC3D;;OAEG;IACH,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,WAAW,EAAE,GAAG,SAAS,CAAC;IAC5E;;OAEG;IACH,qBAAqB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IACtD;;OAEG;IACH,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACnE;;OAEG;IACH,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACzE;;OAEG;IACH,cAAc,EAAE,CACd,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,EAAE,MAAM,EACZ,EAAC,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAC,EAAE,aAAa,CAAC,CAAC,CAAC,EACpE,OAAO,CAAC,EAAE;QACR,mBAAmB,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC;KAC9C,KACE,CAAC,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,aAAa,EAAE,aAAa,GAAG,YAAY,CAAC,CAAC,CAAC,CAqJ3E;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,KAAK,EAAE,CAAC,EAAE,EACV,EAAC,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GACnE,oBAAoB,CAuBtB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,mBAAmB,EAAE,MAAM,EAAE,EAC7B,UAAU,EAAE,MAAM,UAWnB"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 FlowmapBlue
|
|
3
|
+
* Copyright 2018-2020 Teralytics, modified by FlowmapBlue
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
import { isCluster, } from './../types';
|
|
19
|
+
import { ascending, bisectLeft, extent } from 'd3-array';
|
|
20
|
+
/**
|
|
21
|
+
* Build ClusterIndex from the given cluster hierarchy
|
|
22
|
+
*/
|
|
23
|
+
export function buildIndex(clusterLevels) {
|
|
24
|
+
const nodesByZoom = new Map();
|
|
25
|
+
const clustersById = new Map();
|
|
26
|
+
const minZoomByLocationId = new Map();
|
|
27
|
+
for (const { zoom, nodes } of clusterLevels) {
|
|
28
|
+
nodesByZoom.set(zoom, nodes);
|
|
29
|
+
for (const node of nodes) {
|
|
30
|
+
if (isCluster(node)) {
|
|
31
|
+
clustersById.set(node.id, node);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const { id } = node;
|
|
35
|
+
const mz = minZoomByLocationId.get(id);
|
|
36
|
+
if (mz == null || mz > zoom) {
|
|
37
|
+
minZoomByLocationId.set(id, zoom);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const [minZoom, maxZoom] = extent(clusterLevels, (cl) => cl.zoom);
|
|
43
|
+
if (minZoom == null || maxZoom == null) {
|
|
44
|
+
throw new Error('Could not determine minZoom or maxZoom');
|
|
45
|
+
}
|
|
46
|
+
const leavesToClustersByZoom = new Map();
|
|
47
|
+
for (const cluster of clustersById.values()) {
|
|
48
|
+
const { zoom } = cluster;
|
|
49
|
+
let leavesToClusters = leavesToClustersByZoom.get(zoom);
|
|
50
|
+
if (!leavesToClusters) {
|
|
51
|
+
leavesToClusters = new Map();
|
|
52
|
+
leavesToClustersByZoom.set(zoom, leavesToClusters);
|
|
53
|
+
}
|
|
54
|
+
visitClusterLeaves(cluster, (leafId) => {
|
|
55
|
+
leavesToClusters === null || leavesToClusters === void 0 ? void 0 : leavesToClusters.set(leafId, cluster);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function visitClusterLeaves(cluster, visit) {
|
|
59
|
+
for (const childId of cluster.children) {
|
|
60
|
+
const child = clustersById.get(childId);
|
|
61
|
+
if (child) {
|
|
62
|
+
visitClusterLeaves(child, visit);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
visit(childId);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const expandCluster = (cluster, targetZoom = maxZoom) => {
|
|
70
|
+
const ids = [];
|
|
71
|
+
const visit = (c, expandedIds) => {
|
|
72
|
+
if (targetZoom > c.zoom) {
|
|
73
|
+
for (const childId of c.children) {
|
|
74
|
+
const child = clustersById.get(childId);
|
|
75
|
+
if (child) {
|
|
76
|
+
visit(child, expandedIds);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
expandedIds.push(childId);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
expandedIds.push(c.id);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
visit(cluster, ids);
|
|
88
|
+
return ids;
|
|
89
|
+
};
|
|
90
|
+
function findClusterFor(locationId, zoom) {
|
|
91
|
+
const leavesToClusters = leavesToClustersByZoom.get(zoom);
|
|
92
|
+
if (!leavesToClusters) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
const cluster = leavesToClusters.get(locationId);
|
|
96
|
+
return cluster ? cluster.id : undefined;
|
|
97
|
+
}
|
|
98
|
+
const availableZoomLevels = clusterLevels
|
|
99
|
+
.map((cl) => +cl.zoom)
|
|
100
|
+
.sort((a, b) => ascending(a, b));
|
|
101
|
+
return {
|
|
102
|
+
availableZoomLevels,
|
|
103
|
+
getClusterNodesFor: (zoom) => {
|
|
104
|
+
if (zoom === undefined) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
return nodesByZoom.get(zoom);
|
|
108
|
+
},
|
|
109
|
+
getClusterById: (clusterId) => clustersById.get(clusterId),
|
|
110
|
+
getMinZoomForLocation: (locationId) => minZoomByLocationId.get(locationId) || minZoom,
|
|
111
|
+
expandCluster,
|
|
112
|
+
findClusterFor,
|
|
113
|
+
aggregateFlows: (flows, zoom, { getFlowOriginId, getFlowDestId, getFlowMagnitude }, options = {}) => {
|
|
114
|
+
if (zoom > maxZoom) {
|
|
115
|
+
return flows;
|
|
116
|
+
}
|
|
117
|
+
const result = [];
|
|
118
|
+
const aggFlowsByKey = new Map();
|
|
119
|
+
const makeKey = (origin, dest) => `${origin}:${dest}`;
|
|
120
|
+
const { flowCountsMapReduce = {
|
|
121
|
+
map: getFlowMagnitude,
|
|
122
|
+
reduce: (acc, count) => (acc || 0) + count,
|
|
123
|
+
}, } = options;
|
|
124
|
+
for (const flow of flows) {
|
|
125
|
+
const origin = getFlowOriginId(flow);
|
|
126
|
+
const dest = getFlowDestId(flow);
|
|
127
|
+
const originCluster = findClusterFor(origin, zoom) || origin;
|
|
128
|
+
const destCluster = findClusterFor(dest, zoom) || dest;
|
|
129
|
+
const key = makeKey(originCluster, destCluster);
|
|
130
|
+
if (originCluster === origin && destCluster === dest) {
|
|
131
|
+
result.push(flow);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
let aggregateFlow = aggFlowsByKey.get(key);
|
|
135
|
+
if (!aggregateFlow) {
|
|
136
|
+
aggregateFlow = {
|
|
137
|
+
origin: originCluster,
|
|
138
|
+
dest: destCluster,
|
|
139
|
+
count: flowCountsMapReduce.map(flow),
|
|
140
|
+
aggregate: true,
|
|
141
|
+
};
|
|
142
|
+
result.push(aggregateFlow);
|
|
143
|
+
aggFlowsByKey.set(key, aggregateFlow);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
aggregateFlow.count = flowCountsMapReduce.reduce(aggregateFlow.count, flowCountsMapReduce.map(flow));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
export function makeLocationWeightGetter(flows, { getFlowOriginId, getFlowDestId, getFlowMagnitude }) {
|
|
155
|
+
const locationTotals = {
|
|
156
|
+
incoming: new Map(),
|
|
157
|
+
outgoing: new Map(),
|
|
158
|
+
};
|
|
159
|
+
for (const flow of flows) {
|
|
160
|
+
const origin = getFlowOriginId(flow);
|
|
161
|
+
const dest = getFlowDestId(flow);
|
|
162
|
+
const count = getFlowMagnitude(flow);
|
|
163
|
+
locationTotals.incoming.set(dest, (locationTotals.incoming.get(dest) || 0) + count);
|
|
164
|
+
locationTotals.outgoing.set(origin, (locationTotals.outgoing.get(origin) || 0) + count);
|
|
165
|
+
}
|
|
166
|
+
return (id) => Math.max(Math.abs(locationTotals.incoming.get(id) || 0), Math.abs(locationTotals.outgoing.get(id) || 0));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* @param availableZoomLevels Must be sorted in ascending order
|
|
170
|
+
* @param targetZoom
|
|
171
|
+
*/
|
|
172
|
+
export function findAppropriateZoomLevel(availableZoomLevels, targetZoom) {
|
|
173
|
+
if (!availableZoomLevels.length) {
|
|
174
|
+
throw new Error('No available zoom levels');
|
|
175
|
+
}
|
|
176
|
+
return availableZoomLevels[Math.min(bisectLeft(availableZoomLevels, Math.floor(targetZoom)), availableZoomLevels.length - 1)];
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2x1c3RlckluZGV4LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsdXN0ZXIvQ2x1c3RlckluZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBRUgsT0FBTyxFQU9MLFNBQVMsR0FDVixNQUFNLFlBQVksQ0FBQztBQUNwQixPQUFPLEVBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUMsTUFBTSxVQUFVLENBQUM7QUF1Q3ZEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLFVBQVUsQ0FBSSxhQUE0QjtJQUN4RCxNQUFNLFdBQVcsR0FBRyxJQUFJLEdBQUcsRUFBeUIsQ0FBQztJQUNyRCxNQUFNLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBbUIsQ0FBQztJQUNoRCxNQUFNLG1CQUFtQixHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBQ3RELEtBQUssTUFBTSxFQUFDLElBQUksRUFBRSxLQUFLLEVBQUMsSUFBSSxhQUFhLEVBQUU7UUFDekMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDN0IsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLEVBQUU7WUFDeEIsSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQ25CLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNqQztpQkFBTTtnQkFDTCxNQUFNLEVBQUMsRUFBRSxFQUFDLEdBQUcsSUFBSSxDQUFDO2dCQUNsQixNQUFNLEVBQUUsR0FBRyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQ3ZDLElBQUksRUFBRSxJQUFJLElBQUksSUFBSSxFQUFFLEdBQUcsSUFBSSxFQUFFO29CQUMzQixtQkFBbUIsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO2lCQUNuQzthQUNGO1NBQ0Y7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QUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQzlDLElBQUksQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQy9DLENBQUM7QUFDTixDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLHdCQUF3QixDQUN0QyxtQkFBNkIsRUFDN0IsVUFBa0I7SUFFbEIsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRTtRQUMvQixNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUM7S0FDN0M7SUFDRCxPQUFPLG1CQUFtQixDQUN4QixJQUFJLENBQUMsR0FBRyxDQUNOLFVBQVUsQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQ3ZELG1CQUFtQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQy9CLENBQ0YsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IDIwMjIgRmxvd21hcEJsdWVcbiAqIENvcHlyaWdodCAyMDE4LTIwMjAgVGVyYWx5dGljcywgbW9kaWZpZWQgYnkgRmxvd21hcEJsdWVcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cblxuaW1wb3J0IHtcbiAgQWdncmVnYXRlRmxvdyxcbiAgQ2x1c3RlcixcbiAgQ2x1c3RlckxldmVscyxcbiAgQ2x1c3Rlck5vZGUsXG4gIEZsb3dBY2Nlc3NvcnMsXG4gIEZsb3dDb3VudHNNYXBSZWR1Y2UsXG4gIGlzQ2x1c3Rlcixcbn0gZnJvbSAnLi8uLi90eXBlcyc7XG5pbXBvcnQge2FzY2VuZGluZywgYmlzZWN0TGVmdCwgZXh0ZW50fSBmcm9tICdkMy1hcnJheSc7XG5cbmV4cG9ydCB0eXBlIExvY2F0aW9uV2VpZ2h0R2V0dGVyID0gKGlkOiBzdHJpbmcpID0+IG51bWJlcjtcblxuLyoqXG4gKiBBIGRhdGEgc3RydWN0dXJlIHJlcHJlc2VudGluZyB0aGUgY2x1c3RlciBsZXZlbHMgZm9yIGVmZmljaWVudCBmbG93IGFnZ3JlZ2F0aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENsdXN0ZXJJbmRleDxGPiB7XG4gIGF2YWlsYWJsZVpvb21MZXZlbHM6IG51bWJlcltdO1xuICBnZXRDbHVzdGVyQnlJZDogKGNsdXN0ZXJJZDogc3RyaW5nKSA9PiBDbHVzdGVyIHwgdW5kZWZpbmVkO1xuICAvKipcbiAgICogTGlzdCB0aGUgbm9kZXMgb24gdGhlIGdpdmVuIHpvb20gbGV2ZWwuXG4gICAqL1xuICBnZXRDbHVzdGVyTm9kZXNGb3I6ICh6b29tOiBudW1iZXIgfCB1bmRlZmluZWQpID0+IENsdXN0ZXJOb2RlW10gfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBHZXQgdGhlIG1pbiB6b29tIGxldmVsIG9uIHdoaWNoIHRoZSBsb2NhdGlvbiBpcyBub3QgY2x1c3RlcmVkLlxuICAgKi9cbiAgZ2V0TWluWm9vbUZvckxvY2F0aW9uOiAobG9jYXRpb25JZDogc3RyaW5nKSA9PiBudW1iZXI7XG4gIC8qKlxuICAgKiBMaXN0IHRoZSBJRHMgb2YgYWxsIGxvY2F0aW9ucyBpbiB0aGUgY2x1c3RlciAobGVhdmVzIG9mIHRoZSBzdWJ0cmVlIHN0YXJ0aW5nIGluIHRoZSBjbHVzdGVyKS5cbiAgICovXG4gIGV4cGFuZENsdXN0ZXI6IChjbHVzdGVyOiBDbHVzdGVyLCB0YXJnZXRab29tPzogbnVtYmVyKSA9PiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIEZpbmQgdGhlIGNsdXN0ZXIgdGhlIGdpdmVuIGxvY2F0aW9uIGlzIHJlc2lkaW5nIGluIG9uIHRoZSBzcGVjaWZpZWQgem9vbSBsZXZlbC5cbiAgICovXG4gIGZpbmRDbHVzdGVyRm9yOiAobG9jYXRpb25JZDogc3RyaW5nLCB6b29tOiBudW1iZXIpID0+IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgLyoqXG4gICAqIEFnZ3JlZ2F0ZSBmbG93cyBmb3IgdGhlIHNwZWNpZmllZCB6b29tIGxldmVsLlxuICAgKi9cbiAgYWdncmVnYXRlRmxvd3M6IChcbiAgICBmbG93czogRltdLFxuICAgIHpvb206IG51bWJlcixcbiAgICB7Z2V0Rmxvd09yaWdpbklkLCBnZXRGbG93RGVzdElkLCBnZXRGbG93TWFnbml0dWRlfTogRmxvd0FjY2Vzc29yczxGPixcbiAgICBvcHRpb25zPzoge1xuICAgICAgZmxvd0NvdW50c01hcFJlZHVjZT86IEZsb3dDb3VudHNNYXBSZWR1Y2U8Rj47XG4gICAgfSxcbiAgKSA9PiAoRiB8IEFnZ3JlZ2F0ZUZsb3cpW107XG59XG5cbi8qKlxuICogQnVpbGQgQ2x1c3RlckluZGV4IGZyb20gdGhlIGdpdmVuIGNsdXN0ZXIgaGllcmFyY2h5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZEluZGV4PEY+KGNsdXN0ZXJMZXZlbHM6IENsdXN0ZXJMZXZlbHMpOiBDbHVzdGVySW5kZXg8Rj4ge1xuICBjb25zdCBub2Rlc0J5Wm9vbSA9IG5ldyBNYXA8bnVtYmVyLCBDbHVzdGVyTm9kZVtdPigpO1xuICBjb25zdCBjbHVzdGVyc0J5SWQgPSBuZXcgTWFwPHN0cmluZywgQ2x1c3Rlcj4oKTtcbiAgY29uc3QgbWluWm9vbUJ5TG9jYXRpb25JZCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gIGZvciAoY29uc3Qge3pvb20sIG5vZGVzfSBvZiBjbHVzdGVyTGV2ZWxzKSB7XG4gICAgbm9kZXNCeVpvb20uc2V0KHpvb20sIG5vZGVzKTtcbiAgICBmb3IgKGNvbnN0IG5vZGUgb2Ygbm9kZXMpIHtcbiAgICAgIGlmIChpc0NsdXN0ZXIobm9kZSkpIHtcbiAgICAgICAgY2x1c3RlcnNCeUlkLnNldChub2RlLmlkLCBub2RlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHtpZH0gPSBub2RlO1xuICAgICAgICBjb25zdCBteiA9IG1pblpvb21CeUxvY2F0aW9uSWQuZ2V0KGlkKTtcbiAgICAgICAgaWYgKG16ID09IG51bGwgfHwgbXogPiB6b29tKSB7XG4gICAgICAgICAgbWluWm9vbUJ5TG9jYXRpb25JZC5zZXQoaWQsIHpvb20pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY29uc3QgW21pblpvb20sIG1heFpvb21dID0gZXh0ZW50KGNsdXN0ZXJMZXZlbHMsIChjbCkgPT4gY2wuem9vbSk7XG4gIGlmIChtaW5ab29tID09IG51bGwgfHwgbWF4Wm9vbSA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgZGV0ZXJtaW5lIG1pblpvb20gb3IgbWF4Wm9vbScpO1xuICB9XG5cbiAgY29uc3QgbGVhdmVzVG9DbHVzdGVyc0J5Wm9vbSA9IG5ldyBNYXA8bnVtYmVyLCBNYXA8c3RyaW5nLCBDbHVzdGVyPj4oKTtcblxuICBmb3IgKGNvbnN0IGNsdXN0ZXIgb2YgY2x1c3RlcnNCeUlkLnZhbHVlcygpKSB7XG4gICAgY29uc3Qge3pvb219ID0gY2x1c3RlcjtcbiAgICBsZXQgbGVhdmVzVG9DbHVzdGVycyA9IGxlYXZlc1RvQ2x1c3RlcnNCeVpvb20uZ2V0KHpvb20pO1xuICAgIGlmICghbGVhdmVzVG9DbHVzdGVycykge1xuICAgICAgbGVhdmVzVG9DbHVzdGVycyA9IG5ldyBNYXA8c3RyaW5nLCBDbHVzdGVyPigpO1xuICAgICAgbGVhdmVzVG9DbHVzdGVyc0J5Wm9vbS5zZXQoem9vbSwgbGVhdmVzVG9DbHVzdGVycyk7XG4gICAgfVxuICAgIHZpc2l0Q2x1c3RlckxlYXZlcyhjbHVzdGVyLCAobGVhZklkKSA9PiB7XG4gICAgICBsZWF2ZXNUb0NsdXN0ZXJzPy5zZXQobGVhZklkLCBjbHVzdGVyKTtcbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHZpc2l0Q2x1c3RlckxlYXZlcyhjbHVzdGVyOiBDbHVzdGVyLCB2aXNpdDogKGlkOiBzdHJpbmcpID0+IHZvaWQpIHtcbiAgICBmb3IgKGNvbnN0IGNoaWxkSWQgb2YgY2x1c3Rlci5jaGlsZHJlbikge1xuICAgICAgY29uc3QgY2hpbGQgPSBjbHVzdGVyc0J5SWQuZ2V0KGNoaWxkSWQpO1xuICAgICAgaWYgKGNoaWxkKSB7XG4gICAgICAgIHZpc2l0Q2x1c3RlckxlYXZlcyhjaGlsZCwgdmlzaXQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmlzaXQoY2hpbGRJZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY29uc3QgZXhwYW5kQ2x1c3RlciA9IChjbHVzdGVyOiBDbHVzdGVyLCB0YXJnZXRab29tOiBudW1iZXIgPSBtYXhab29tKSA9PiB7XG4gICAgY29uc3QgaWRzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IHZpc2l0ID0gKGM6IENsdXN0ZXIsIGV4cGFuZGVkSWRzOiBzdHJpbmdbXSkgPT4ge1xuICAgICAgaWYgKHRhcmdldFpvb20gPiBjLnpvb20pIHtcbiAgICAgICAgZm9yIChjb25zdCBjaGlsZElkIG9mIGMuY2hpbGRyZW4pIHtcbiAgICAgICAgICBjb25zdCBjaGlsZCA9IGNsdXN0ZXJzQnlJZC5nZXQoY2hpbGRJZCk7XG4gICAgICAgICAgaWYgKGNoaWxkKSB7XG4gICAgICAgICAgICB2aXNpdChjaGlsZCwgZXhwYW5kZWRJZHMpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBleHBhbmRlZElkcy5wdXNoKGNoaWxkSWQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZXhwYW5kZWRJZHMucHVzaChjLmlkKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHZpc2l0KGNsdXN0ZXIsIGlkcyk7XG4gICAgcmV0dXJuIGlkcztcbiAgfTtcblxuICBmdW5jdGlvbiBmaW5kQ2x1c3RlckZvcihsb2NhdGlvbklkOiBzdHJpbmcsIHpvb206IG51bWJlcikge1xuICAgIGNvbnN0IGxlYXZlc1RvQ2x1c3RlcnMgPSBsZWF2ZXNUb0NsdXN0ZXJzQnlab29tLmdldCh6b29tKTtcbiAgICBpZiAoIWxlYXZlc1RvQ2x1c3RlcnMpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGNvbnN0IGNsdXN0ZXIgPSBsZWF2ZXNUb0NsdXN0ZXJzLmdldChsb2NhdGlvbklkKTtcbiAgICByZXR1cm4gY2x1c3RlciA/IGNsdXN0ZXIuaWQgOiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBhdmFpbGFibGVab29tTGV2ZWxzID0gY2x1c3RlckxldmVsc1xuICAgIC5tYXAoKGNsKSA9PiArY2wuem9vbSlcbiAgICAuc29ydCgoYSwgYikgPT4gYXNjZW5kaW5nKGEsIGIpKTtcblxuICByZXR1cm4ge1xuICAgIGF2YWlsYWJsZVpvb21MZXZlbHMsXG5cbiAgICBnZXRDbHVzdGVyTm9kZXNGb3I6ICh6b29tKSA9PiB7XG4gICAgICBpZiAoem9vbSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICByZXR1cm4gbm9kZXNCeVpvb20uZ2V0KHpvb20pO1xuICAgIH0sXG5cbiAgICBnZXRDbHVzdGVyQnlJZDogKGNsdXN0ZXJJZCkgPT4gY2x1c3RlcnNCeUlkLmdldChjbHVzdGVySWQpLFxuXG4gICAgZ2V0TWluWm9vbUZvckxvY2F0aW9uOiAobG9jYXRpb25JZCkgPT5cbiAgICAgIG1pblpvb21CeUxvY2F0aW9uSWQuZ2V0KGxvY2F0aW9uSWQpIHx8IG1pblpvb20sXG5cbiAgICBleHBhbmRDbHVzdGVyLFxuXG4gICAgZmluZENsdXN0ZXJGb3IsXG5cbiAgICBhZ2dyZWdhdGVGbG93czogKFxuICAgICAgZmxvd3MsXG4gICAgICB6b29tLFxuICAgICAge2dldEZsb3dPcmlnaW5JZCwgZ2V0Rmxvd0Rlc3RJZCwgZ2V0Rmxvd01hZ25pdHVkZX0sXG4gICAgICBvcHRpb25zID0ge30sXG4gICAgKSA9PiB7XG4gICAgICBpZiAoem9vbSA+IG1heFpvb20pIHtcbiAgICAgICAgcmV0dXJuIGZsb3dzO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVzdWx0OiAoRiB8IEFnZ3JlZ2F0ZUZsb3cpW10gPSBbXTtcbiAgICAgIGNvbnN0IGFnZ0Zsb3dzQnlLZXkgPSBuZXcgTWFwPHN0cmluZywgQWdncmVnYXRlRmxvdz4oKTtcbiAgICAgIGNvbnN0IG1ha2VLZXkgPSAob3JpZ2luOiBzdHJpbmcsIGRlc3Q6IHN0cmluZykgPT4gYCR7b3JpZ2lufToke2Rlc3R9YDtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZmxvd0NvdW50c01hcFJlZHVjZSA9IHtcbiAgICAgICAgICBtYXA6IGdldEZsb3dNYWduaXR1ZGUsXG4gICAgICAgICAgcmVkdWNlOiAoYWNjOiBhbnksIGNvdW50OiBudW1iZXIpID0+IChhY2MgfHwgMCkgKyBjb3VudCxcbiAgICAgICAgfSxcbiAgICAgIH0gPSBvcHRpb25zO1xuICAgICAgZm9yIChjb25zdCBmbG93IG9mIGZsb3dzKSB7XG4gICAgICAgIGNvbnN0IG9yaWdpbiA9IGdldEZsb3dPcmlnaW5JZChmbG93KTtcbiAgICAgICAgY29uc3QgZGVzdCA9IGdldEZsb3dEZXN0SWQoZmxvdyk7XG4gICAgICAgIGNvbnN0IG9yaWdpbkNsdXN0ZXIgPSBmaW5kQ2x1c3RlckZvcihvcmlnaW4sIHpvb20pIHx8IG9yaWdpbjtcbiAgICAgICAgY29uc3QgZGVzdENsdXN0ZXIgPSBmaW5kQ2x1c3RlckZvcihkZXN0LCB6b29tKSB8fCBkZXN0O1xuICAgICAgICBjb25zdCBrZXkgPSBtYWtlS2V5KG9yaWdpbkNsdXN0ZXIsIGRlc3RDbHVzdGVyKTtcbiAgICAgICAgaWYgKG9yaWdpbkNsdXN0ZXIgPT09IG9yaWdpbiAmJiBkZXN0Q2x1c3RlciA9PT0gZGVzdCkge1xuICAgICAgICAgIHJlc3VsdC5wdXNoKGZsb3cpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxldCBhZ2dyZWdhdGVGbG93ID0gYWdnRmxvd3NCeUtleS5nZXQoa2V5KTtcbiAgICAgICAgICBpZiAoIWFnZ3JlZ2F0ZUZsb3cpIHtcbiAgICAgICAgICAgIGFnZ3JlZ2F0ZUZsb3cgPSB7XG4gICAgICAgICAgICAgIG9yaWdpbjogb3JpZ2luQ2x1c3RlcixcbiAgICAgICAgICAgICAgZGVzdDogZGVzdENsdXN0ZXIsXG4gICAgICAgICAgICAgIGNvdW50OiBmbG93Q291bnRzTWFwUmVkdWNlLm1hcChmbG93KSxcbiAgICAgICAgICAgICAgYWdncmVnYXRlOiB0cnVlLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKGFnZ3JlZ2F0ZUZsb3cpO1xuICAgICAgICAgICAgYWdnRmxvd3NCeUtleS5zZXQoa2V5LCBhZ2dyZWdhdGVGbG93KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWdncmVnYXRlRmxvdy5jb3VudCA9IGZsb3dDb3VudHNNYXBSZWR1Y2UucmVkdWNlKFxuICAgICAgICAgICAgICBhZ2dyZWdhdGVGbG93LmNvdW50LFxuICAgICAgICAgICAgICBmbG93Q291bnRzTWFwUmVkdWNlLm1hcChmbG93KSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0sXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBtYWtlTG9jYXRpb25XZWlnaHRHZXR0ZXI8Rj4oXG4gIGZsb3dzOiBGW10sXG4gIHtnZXRGbG93T3JpZ2luSWQsIGdldEZsb3dEZXN0SWQsIGdldEZsb3dNYWduaXR1ZGV9OiBGbG93QWNjZXNzb3JzPEY+LFxuKTogTG9jYXRpb25XZWlnaHRHZXR0ZXIge1xuICBjb25zdCBsb2NhdGlvblRvdGFscyA9IHtcbiAgICBpbmNvbWluZzogbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKSxcbiAgICBvdXRnb2luZzogbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKSxcbiAgfTtcbiAgZm9yIChjb25zdCBmbG93IG9mIGZsb3dzKSB7XG4gICAgY29uc3Qgb3JpZ2luID0gZ2V0Rmxvd09yaWdpbklkKGZsb3cpO1xuICAgIGNvbnN0IGRlc3QgPSBnZXRGbG93RGVzdElkKGZsb3cpO1xuICAgIGNvbnN0IGNvdW50ID0gZ2V0Rmxvd01hZ25pdHVkZShmbG93KTtcbiAgICBsb2NhdGlvblRvdGFscy5pbmNvbWluZy5zZXQoXG4gICAgICBkZXN0LFxuICAgICAgKGxvY2F0aW9uVG90YWxzLmluY29taW5nLmdldChkZXN0KSB8fCAwKSArIGNvdW50LFxuICAgICk7XG4gICAgbG9jYXRpb25Ub3RhbHMub3V0Z29pbmcuc2V0KFxuICAgICAgb3JpZ2luLFxuICAgICAgKGxvY2F0aW9uVG90YWxzLm91dGdvaW5nLmdldChvcmlnaW4pIHx8IDApICsgY291bnQsXG4gICAgKTtcbiAgfVxuICByZXR1cm4gKGlkOiBzdHJpbmcpID0+XG4gICAgTWF0aC5tYXgoXG4gICAgICBNYXRoLmFicyhsb2NhdGlvblRvdGFscy5pbmNvbWluZy5nZXQoaWQpIHx8IDApLFxuICAgICAgTWF0aC5hYnMobG9jYXRpb25Ub3RhbHMub3V0Z29pbmcuZ2V0KGlkKSB8fCAwKSxcbiAgICApO1xufVxuXG4vKipcbiAqIEBwYXJhbSBhdmFpbGFibGVab29tTGV2ZWxzIE11c3QgYmUgc29ydGVkIGluIGFzY2VuZGluZyBvcmRlclxuICogQHBhcmFtIHRhcmdldFpvb21cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmRBcHByb3ByaWF0ZVpvb21MZXZlbChcbiAgYXZhaWxhYmxlWm9vbUxldmVsczogbnVtYmVyW10sXG4gIHRhcmdldFpvb206IG51bWJlcixcbikge1xuICBpZiAoIWF2YWlsYWJsZVpvb21MZXZlbHMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdObyBhdmFpbGFibGUgem9vbSBsZXZlbHMnKTtcbiAgfVxuICByZXR1cm4gYXZhaWxhYmxlWm9vbUxldmVsc1tcbiAgICBNYXRoLm1pbihcbiAgICAgIGJpc2VjdExlZnQoYXZhaWxhYmxlWm9vbUxldmVscywgTWF0aC5mbG9vcih0YXJnZXRab29tKSksXG4gICAgICBhdmFpbGFibGVab29tTGV2ZWxzLmxlbmd0aCAtIDEsXG4gICAgKVxuICBdO1xufVxuIl19
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LocationWeightGetter } from './ClusterIndex';
|
|
2
|
+
import { ClusterLevel, LocationAccessors } from '../types';
|
|
3
|
+
export interface Options {
|
|
4
|
+
minZoom: number;
|
|
5
|
+
maxZoom: number;
|
|
6
|
+
radius: number;
|
|
7
|
+
extent: number;
|
|
8
|
+
nodeSize: number;
|
|
9
|
+
makeClusterName: (id: number, numPoints: number) => string | undefined;
|
|
10
|
+
makeClusterId: (id: number) => string;
|
|
11
|
+
}
|
|
12
|
+
interface BasePoint {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
weight: number;
|
|
16
|
+
zoom: number;
|
|
17
|
+
parentId: number;
|
|
18
|
+
}
|
|
19
|
+
interface LeafPoint extends BasePoint {
|
|
20
|
+
index: number;
|
|
21
|
+
}
|
|
22
|
+
interface ClusterPoint extends BasePoint {
|
|
23
|
+
id: number;
|
|
24
|
+
numPoints: number;
|
|
25
|
+
}
|
|
26
|
+
declare type Point = LeafPoint | ClusterPoint;
|
|
27
|
+
export declare function isLeafPoint(p: Point): p is LeafPoint;
|
|
28
|
+
export declare function isClusterPoint(p: Point): p is ClusterPoint;
|
|
29
|
+
export declare function clusterLocations<L>(locations: L[], locationAccessors: LocationAccessors<L>, getLocationWeight: LocationWeightGetter, options?: Partial<Options>): ClusterLevel[];
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=cluster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/cluster/cluster.ts"],"names":[],"mappings":"AAwCA,OAAO,EAAC,oBAAoB,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAU,YAAY,EAAe,iBAAiB,EAAC,MAAM,UAAU,CAAC;AAE/E,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACvE,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAYD,UAAU,SAAS;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,SAAU,SAAQ,SAAS;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,YAAa,SAAQ,SAAS;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,aAAK,KAAK,GAAG,SAAS,GAAG,YAAY,CAAC;AAEtC,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,IAAI,SAAS,CAGpD;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,IAAI,YAAY,CAG1D;AAID,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,SAAS,EAAE,CAAC,EAAE,EACd,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC,EACvC,iBAAiB,EAAE,oBAAoB,EACvC,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GACzB,YAAY,EAAE,CA2FhB"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 FlowmapBlue
|
|
3
|
+
* Copyright 2018-2020 Teralytics, modified by FlowmapBlue
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* The code in this file is a based on https://github.com/mapbox/supercluster
|
|
20
|
+
*/
|
|
21
|
+
// ISC License
|
|
22
|
+
//
|
|
23
|
+
// Copyright (c) 2016, Mapbox
|
|
24
|
+
//
|
|
25
|
+
// Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
26
|
+
// with or without fee is hereby granted, provided that the above copyright notice
|
|
27
|
+
// and this permission notice appear in all copies.
|
|
28
|
+
//
|
|
29
|
+
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
30
|
+
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
31
|
+
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
32
|
+
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
33
|
+
// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
34
|
+
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
35
|
+
// THIS SOFTWARE.
|
|
36
|
+
import { rollup } from 'd3-array';
|
|
37
|
+
import KDBush from 'kdbush';
|
|
38
|
+
const defaultOptions = {
|
|
39
|
+
minZoom: 0,
|
|
40
|
+
maxZoom: 16,
|
|
41
|
+
radius: 40,
|
|
42
|
+
extent: 512,
|
|
43
|
+
nodeSize: 64,
|
|
44
|
+
makeClusterName: (id, numPoints) => undefined,
|
|
45
|
+
makeClusterId: (id) => `{[${id}]}`,
|
|
46
|
+
};
|
|
47
|
+
export function isLeafPoint(p) {
|
|
48
|
+
const { index } = p;
|
|
49
|
+
return index != null;
|
|
50
|
+
}
|
|
51
|
+
export function isClusterPoint(p) {
|
|
52
|
+
const { id } = p;
|
|
53
|
+
return id != null;
|
|
54
|
+
}
|
|
55
|
+
export function clusterLocations(locations, locationAccessors, getLocationWeight, options) {
|
|
56
|
+
const { getLocationCentroid, getLocationId } = locationAccessors;
|
|
57
|
+
const opts = Object.assign(Object.assign({}, defaultOptions), options);
|
|
58
|
+
const { minZoom, maxZoom, nodeSize, makeClusterName, makeClusterId } = opts;
|
|
59
|
+
const trees = new Array(maxZoom + 1);
|
|
60
|
+
// generate a cluster object for each point and index input points into a KD-tree
|
|
61
|
+
let clusters = new Array();
|
|
62
|
+
for (let i = 0; i < locations.length; i++) {
|
|
63
|
+
const [x, y] = getLocationCentroid(locations[i]);
|
|
64
|
+
clusters.push({
|
|
65
|
+
x: lngX(x),
|
|
66
|
+
y: latY(y),
|
|
67
|
+
weight: getLocationWeight(getLocationId(locations[i])),
|
|
68
|
+
zoom: Infinity,
|
|
69
|
+
index: i,
|
|
70
|
+
parentId: -1, // parent cluster id
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
trees[maxZoom + 1] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
|
|
74
|
+
// cluster points on max zoom, then cluster the results on previous zoom, etc.;
|
|
75
|
+
// results in a cluster hierarchy across zoom levels
|
|
76
|
+
for (let z = maxZoom; z >= minZoom; z--) {
|
|
77
|
+
// create a new set of clusters for the zoom and index them with a KD-tree
|
|
78
|
+
clusters = cluster(clusters, z, trees[z + 1], opts);
|
|
79
|
+
trees[z] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
|
|
80
|
+
}
|
|
81
|
+
if (trees.length === 0) {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
const numbersOfClusters = trees.map((d) => d.points.length);
|
|
85
|
+
const maxAvailZoom = numbersOfClusters.indexOf(numbersOfClusters[numbersOfClusters.length - 1]);
|
|
86
|
+
const minAvailZoom = Math.min(maxAvailZoom, numbersOfClusters.lastIndexOf(numbersOfClusters[0]));
|
|
87
|
+
const clusterLevels = new Array();
|
|
88
|
+
for (let zoom = minAvailZoom; zoom <= maxAvailZoom; zoom++) {
|
|
89
|
+
let childrenByParent;
|
|
90
|
+
const tree = trees[zoom];
|
|
91
|
+
if (zoom < maxAvailZoom) {
|
|
92
|
+
childrenByParent = rollup(trees[zoom + 1].points, (points) => points.map((p) => p.id ? makeClusterId(p.id) : getLocationId(locations[p.index])), (point) => point.parentId);
|
|
93
|
+
}
|
|
94
|
+
const nodes = [];
|
|
95
|
+
for (const point of tree.points) {
|
|
96
|
+
const { x, y, numPoints } = point;
|
|
97
|
+
if (isLeafPoint(point)) {
|
|
98
|
+
const location = locations[point.index];
|
|
99
|
+
nodes.push({
|
|
100
|
+
id: getLocationId(location),
|
|
101
|
+
zoom,
|
|
102
|
+
centroid: getLocationCentroid(location),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else if (isClusterPoint(point)) {
|
|
106
|
+
const { id } = point;
|
|
107
|
+
const children = childrenByParent && childrenByParent.get(id);
|
|
108
|
+
if (!children) {
|
|
109
|
+
throw new Error(`Cluster ${id} doesn't have children`);
|
|
110
|
+
}
|
|
111
|
+
nodes.push({
|
|
112
|
+
id: makeClusterId(id),
|
|
113
|
+
name: makeClusterName(id, numPoints),
|
|
114
|
+
zoom,
|
|
115
|
+
centroid: [xLng(x), yLat(y)],
|
|
116
|
+
children,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
clusterLevels.push({
|
|
121
|
+
zoom,
|
|
122
|
+
nodes,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return clusterLevels;
|
|
126
|
+
}
|
|
127
|
+
function createCluster(x, y, id, numPoints, weight) {
|
|
128
|
+
return {
|
|
129
|
+
x,
|
|
130
|
+
y,
|
|
131
|
+
zoom: Infinity,
|
|
132
|
+
id,
|
|
133
|
+
parentId: -1,
|
|
134
|
+
numPoints,
|
|
135
|
+
weight,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function cluster(points, zoom, tree, options) {
|
|
139
|
+
const clusters = [];
|
|
140
|
+
const { radius, extent } = options;
|
|
141
|
+
const r = radius / (extent * Math.pow(2, zoom));
|
|
142
|
+
// loop through each point
|
|
143
|
+
for (let i = 0; i < points.length; i++) {
|
|
144
|
+
const p = points[i];
|
|
145
|
+
// if we've already visited the point at this zoom level, skip it
|
|
146
|
+
if (p.zoom <= zoom) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
p.zoom = zoom;
|
|
150
|
+
// find all nearby points
|
|
151
|
+
const neighborIds = tree.within(p.x, p.y, r);
|
|
152
|
+
let weight = p.weight || 1;
|
|
153
|
+
let numPoints = isClusterPoint(p) ? p.numPoints : 1;
|
|
154
|
+
let wx = p.x * weight;
|
|
155
|
+
let wy = p.y * weight;
|
|
156
|
+
// encode both zoom and point index on which the cluster originated
|
|
157
|
+
const id = (i << 5) + (zoom + 1);
|
|
158
|
+
for (const neighborId of neighborIds) {
|
|
159
|
+
const b = tree.points[neighborId];
|
|
160
|
+
// filter out neighbors that are already processed
|
|
161
|
+
if (b.zoom <= zoom) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
b.zoom = zoom; // save the zoom (so it doesn't get processed twice)
|
|
165
|
+
const weight2 = b.weight || 1;
|
|
166
|
+
const numPoints2 = b.numPoints || 1;
|
|
167
|
+
wx += b.x * weight2; // accumulate coordinates for calculating weighted center
|
|
168
|
+
wy += b.y * weight2;
|
|
169
|
+
weight += weight2;
|
|
170
|
+
numPoints += numPoints2;
|
|
171
|
+
b.parentId = id;
|
|
172
|
+
}
|
|
173
|
+
if (numPoints === 1) {
|
|
174
|
+
clusters.push(p);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
p.parentId = id;
|
|
178
|
+
clusters.push(createCluster(wx / weight, wy / weight, id, numPoints, weight));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return clusters;
|
|
182
|
+
}
|
|
183
|
+
// spherical mercator to longitude/latitude
|
|
184
|
+
function xLng(x) {
|
|
185
|
+
return (x - 0.5) * 360;
|
|
186
|
+
}
|
|
187
|
+
function yLat(y) {
|
|
188
|
+
const y2 = ((180 - y * 360) * Math.PI) / 180;
|
|
189
|
+
return (360 * Math.atan(Math.exp(y2))) / Math.PI - 90;
|
|
190
|
+
}
|
|
191
|
+
// longitude/latitude to spherical mercator in [0..1] range
|
|
192
|
+
function lngX(lng) {
|
|
193
|
+
return lng / 360 + 0.5;
|
|
194
|
+
}
|
|
195
|
+
function latY(lat) {
|
|
196
|
+
const sin = Math.sin((lat * Math.PI) / 180);
|
|
197
|
+
const y = 0.5 - (0.25 * Math.log((1 + sin) / (1 - sin))) / Math.PI;
|
|
198
|
+
return y < 0 ? 0 : y > 1 ? 1 : y;
|
|
199
|
+
}
|
|
200
|
+
function getX(p) {
|
|
201
|
+
return p.x;
|
|
202
|
+
}
|
|
203
|
+
function getY(p) {
|
|
204
|
+
return p.y;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2x1c3Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jbHVzdGVyL2NsdXN0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFFSDs7R0FFRztBQUVILGNBQWM7QUFDZCxFQUFFO0FBQ0YsNkJBQTZCO0FBQzdCLEVBQUU7QUFDRixtRkFBbUY7QUFDbkYsa0ZBQWtGO0FBQ2xGLG1EQUFtRDtBQUNuRCxFQUFFO0FBQ0YsZ0ZBQWdGO0FBQ2hGLGtGQUFrRjtBQUNsRiwyRUFBMkU7QUFDM0UsbUZBQW1GO0FBQ25GLGlGQUFpRjtBQUNqRixrRkFBa0Y7QUFDbEYsaUJBQWlCO0FBRWpCLE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBYzVCLE1BQU0sY0FBYyxHQUFZO0lBQzlCLE9BQU8sRUFBRSxDQUFDO0lBQ1YsT0FBTyxFQUFFLEVBQUU7SUFDWCxNQUFNLEVBQUUsRUFBRTtJQUNWLE1BQU0sRUFBRSxHQUFHO0lBQ1gsUUFBUSxFQUFFLEVBQUU7SUFDWixlQUFlLEVBQUUsQ0FBQyxFQUFVLEVBQUUsU0FBaUIsRUFBRSxFQUFFLENBQUMsU0FBUztJQUM3RCxhQUFhLEVBQUUsQ0FBQyxFQUFVLEVBQUUsRUFBRSxDQUFDLEtBQUssRUFBRSxJQUFJO0NBQzNDLENBQUM7QUFxQkYsTUFBTSxVQUFVLFdBQVcsQ0FBQyxDQUFRO0lBQ2xDLE1BQU0sRUFBQyxLQUFLLEVBQUMsR0FBRyxDQUFjLENBQUM7SUFDL0IsT0FBTyxLQUFLLElBQUksSUFBSSxDQUFDO0FBQ3ZCLENBQUM7QUFFRCxNQUFNLFVBQVUsY0FBYyxDQUFDLENBQVE7SUFDckMsTUFBTSxFQUFDLEVBQUUsRUFBQyxHQUFHLENBQWlCLENBQUM7SUFDL0IsT0FBTyxFQUFFLElBQUksSUFBSSxDQUFDO0FBQ3BCLENBQUM7QUFJRCxNQUFNLFVBQVUsZ0JBQWdC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ekIsQ0FBQztBQUVELFNBQVMsSUFBSSxDQUFDLEdBQVc7SUFDdkIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7SUFDNUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDbkUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ25DLENBQUM7QUFFRCxTQUFTLElBQUksQ0FBQyxDQUFRO0lBQ3BCLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNiLENBQUM7QUFFRCxTQUFTLElBQUksQ0FBQyxDQUFRO0lBQ3BCLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNiLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IDIwMjIgRmxvd21hcEJsdWVcbiAqIENvcHlyaWdodCAyMDE4LTIwMjAgVGVyYWx5dGljcywgbW9kaWZpZWQgYnkgRmxvd21hcEJsdWVcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cblxuLyoqXG4gKiBUaGUgY29kZSBpbiB0aGlzIGZpbGUgaXMgYSBiYXNlZCBvbiBodHRwczovL2dpdGh1Yi5jb20vbWFwYm94L3N1cGVyY2x1c3RlclxuICovXG5cbi8vIElTQyBMaWNlbnNlXG4vL1xuLy8gQ29weXJpZ2h0IChjKSAyMDE2LCBNYXBib3hcbi8vXG4vLyBQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBhbmQvb3IgZGlzdHJpYnV0ZSB0aGlzIHNvZnR3YXJlIGZvciBhbnkgcHVycG9zZVxuLy8gd2l0aCBvciB3aXRob3V0IGZlZSBpcyBoZXJlYnkgZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZVxuLy8gYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2UgYXBwZWFyIGluIGFsbCBjb3BpZXMuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiBBTkQgVEhFIEFVVEhPUiBESVNDTEFJTVMgQUxMIFdBUlJBTlRJRVMgV0lUSFxuLy8gUkVHQVJEIFRPIFRISVMgU09GVFdBUkUgSU5DTFVESU5HIEFMTCBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORFxuLy8gRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsXG4vLyBJTkRJUkVDVCwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIE9SIEFOWSBEQU1BR0VTIFdIQVRTT0VWRVIgUkVTVUxUSU5HIEZST00gTE9TU1xuLy8gT0YgVVNFLCBEQVRBIE9SIFBST0ZJVFMsIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBORUdMSUdFTkNFIE9SIE9USEVSXG4vLyBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SIFBFUkZPUk1BTkNFIE9GXG4vLyBUSElTIFNPRlRXQVJFLlxuXG5pbXBvcnQge3JvbGx1cH0gZnJvbSAnZDMtYXJyYXknO1xuaW1wb3J0IEtEQnVzaCBmcm9tICdrZGJ1c2gnO1xuaW1wb3J0IHtMb2NhdGlvbldlaWdodEdldHRlcn0gZnJvbSAnLi9DbHVzdGVySW5kZXgnO1xuaW1wb3J0IHtDbHVzdGVyLCBDbHVzdGVyTGV2ZWwsIENsdXN0ZXJOb2RlLCBMb2NhdGlvbkFjY2Vzc29yc30gZnJvbSAnLi4vdHlwZXMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE9wdGlvbnMge1xuICBtaW5ab29tOiBudW1iZXI7IC8vIG1pbiB6b29tIHRvIGdlbmVyYXRlIGNsdXN0ZXJzIG9uXG4gIG1heFpvb206IG51bWJlcjsgLy8gbWF4IHpvb20gbGV2ZWwgdG8gY2x1c3RlciB0aGUgcG9pbnRzIG9uXG4gIHJhZGl1czogbnVtYmVyOyAvLyBjbHVzdGVyIHJhZGl1cyBpbiBwaXhlbHNcbiAgZXh0ZW50OiBudW1iZXI7IC8vIHRpbGUgZXh0ZW50IChyYWRpdXMgaXMgY2FsY3VsYXRlZCByZWxhdGl2ZSB0byBpdClcbiAgbm9kZVNpemU6IG51bWJlcjsgLy8gc2l6ZSBvZiB0aGUgS0QtdHJlZSBsZWFmIG5vZGUsIGFmZmVjdHMgcGVyZm9ybWFuY2VcbiAgbWFrZUNsdXN0ZXJOYW1lOiAoaWQ6IG51bWJlciwgbnVtUG9pbnRzOiBudW1iZXIpID0+IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbWFrZUNsdXN0ZXJJZDogKGlkOiBudW1iZXIpID0+IHN0cmluZztcbn1cblxuY29uc3QgZGVmYXVsdE9wdGlvbnM6IE9wdGlvbnMgPSB7XG4gIG1pblpvb206IDAsXG4gIG1heFpvb206IDE2LFxuICByYWRpdXM6IDQwLFxuICBleHRlbnQ6IDUxMixcbiAgbm9kZVNpemU6IDY0LFxuICBtYWtlQ2x1c3Rlck5hbWU6IChpZDogbnVtYmVyLCBudW1Qb2ludHM6IG51bWJlcikgPT4gdW5kZWZpbmVkLFxuICBtYWtlQ2x1c3RlcklkOiAoaWQ6IG51bWJlcikgPT4gYHtbJHtpZH1dfWAsXG59O1xuXG5pbnRlcmZhY2UgQmFzZVBvaW50IHtcbiAgeDogbnVtYmVyOyAvLyBwcm9qZWN0ZWQgcG9pbnQgY29vcmRpbmF0ZXNcbiAgeTogbnVtYmVyO1xuICB3ZWlnaHQ6IG51bWJlcjtcbiAgem9vbTogbnVtYmVyOyAvLyB0aGUgbGFzdCB6b29tIHRoZSBwb2ludCB3YXMgcHJvY2Vzc2VkIGF0XG4gIHBhcmVudElkOiBudW1iZXI7IC8vIHBhcmVudCBjbHVzdGVyIGlkXG59XG5cbmludGVyZmFjZSBMZWFmUG9pbnQgZXh0ZW5kcyBCYXNlUG9pbnQge1xuICBpbmRleDogbnVtYmVyOyAvLyBpbmRleCBvZiB0aGUgc291cmNlIGZlYXR1cmUgaW4gdGhlIG9yaWdpbmFsIGlucHV0IGFycmF5LFxufVxuXG5pbnRlcmZhY2UgQ2x1c3RlclBvaW50IGV4dGVuZHMgQmFzZVBvaW50IHtcbiAgaWQ6IG51bWJlcjtcbiAgbnVtUG9pbnRzOiBudW1iZXI7XG59XG5cbnR5cGUgUG9pbnQgPSBMZWFmUG9pbnQgfCBDbHVzdGVyUG9pbnQ7XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0xlYWZQb2ludChwOiBQb2ludCk6IHAgaXMgTGVhZlBvaW50IHtcbiAgY29uc3Qge2luZGV4fSA9IHAgYXMgTGVhZlBvaW50O1xuICByZXR1cm4gaW5kZXggIT0gbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzQ2x1c3RlclBvaW50KHA6IFBvaW50KTogcCBpcyBDbHVzdGVyUG9pbnQge1xuICBjb25zdCB7aWR9ID0gcCBhcyBDbHVzdGVyUG9pbnQ7XG4gIHJldHVybiBpZCAhPSBudWxsO1xufVxuXG50eXBlIFpvb21MZXZlbEtEQnVzaCA9IGFueTtcblxuZXhwb3J0IGZ1bmN0aW9uIGNsdXN0ZXJMb2NhdGlvbnM8TD4oXG4gIGxvY2F0aW9uczogTFtdLFxuICBsb2NhdGlvbkFjY2Vzc29yczogTG9jYXRpb25BY2Nlc3NvcnM8TD4sXG4gIGdldExvY2F0aW9uV2VpZ2h0OiBMb2NhdGlvbldlaWdodEdldHRlcixcbiAgb3B0aW9ucz86IFBhcnRpYWw8T3B0aW9ucz4sXG4pOiBDbHVzdGVyTGV2ZWxbXSB7XG4gIGNvbnN0IHtnZXRMb2NhdGlvbkNlbnRyb2lkLCBnZXRMb2NhdGlvbklkfSA9IGxvY2F0aW9uQWNjZXNzb3JzO1xuICBjb25zdCBvcHRzID0ge1xuICAgIC4uLmRlZmF1bHRPcHRpb25zLFxuICAgIC4uLm9wdGlvbnMsXG4gIH07XG4gIGNvbnN0IHttaW5ab29tLCBtYXhab29tLCBub2RlU2l6ZSwgbWFrZUNsdXN0ZXJOYW1lLCBtYWtlQ2x1c3RlcklkfSA9IG9wdHM7XG5cbiAgY29uc3QgdHJlZXMgPSBuZXcgQXJyYXk8Wm9vbUxldmVsS0RCdXNoPihtYXhab29tICsgMSk7XG5cbiAgLy8gZ2VuZXJhdGUgYSBjbHVzdGVyIG9iamVjdCBmb3IgZWFjaCBwb2ludCBhbmQgaW5kZXggaW5wdXQgcG9pbnRzIGludG8gYSBLRC10cmVlXG4gIGxldCBjbHVzdGVycyA9IG5ldyBBcnJheTxQb2ludD4oKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsb2NhdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBbeCwgeV0gPSBnZXRMb2NhdGlvbkNlbnRyb2lkKGxvY2F0aW9uc1tpXSk7XG4gICAgY2x1c3RlcnMucHVzaCh7XG4gICAgICB4OiBsbmdYKHgpLCAvLyBwcm9qZWN0ZWQgcG9pbnQgY29vcmRpbmF0ZXNcbiAgICAgIHk6IGxhdFkoeSksXG4gICAgICB3ZWlnaHQ6IGdldExvY2F0aW9uV2VpZ2h0KGdldExvY2F0aW9uSWQobG9jYXRpb25zW2ldKSksXG4gICAgICB6b29tOiBJbmZpbml0eSwgLy8gdGhlIGxhc3Qgem9vbSB0aGUgcG9pbnQgd2FzIHByb2Nlc3NlZCBhdFxuICAgICAgaW5kZXg6IGksIC8vIGluZGV4IG9mIHRoZSBzb3VyY2UgZmVhdHVyZSBpbiB0aGUgb3JpZ2luYWwgaW5wdXQgYXJyYXksXG4gICAgICBwYXJlbnRJZDogLTEsIC8vIHBhcmVudCBjbHVzdGVyIGlkXG4gICAgfSk7XG4gIH1cbiAgdHJlZXNbbWF4Wm9vbSArIDFdID0gbmV3IEtEQnVzaChjbHVzdGVycywgZ2V0WCwgZ2V0WSwgbm9kZVNpemUsIEZsb2F0MzJBcnJheSk7XG5cbiAgLy8gY2x1c3RlciBwb2ludHMgb24gbWF4IHpvb20sIHRoZW4gY2x1c3RlciB0aGUgcmVzdWx0cyBvbiBwcmV2aW91cyB6b29tLCBldGMuO1xuICAvLyByZXN1bHRzIGluIGEgY2x1c3RlciBoaWVyYXJjaHkgYWNyb3NzIHpvb20gbGV2ZWxzXG4gIGZvciAobGV0IHogPSBtYXhab29tOyB6ID49IG1pblpvb207IHotLSkge1xuICAgIC8vIGNyZWF0ZSBhIG5ldyBzZXQgb2YgY2x1c3RlcnMgZm9yIHRoZSB6b29tIGFuZCBpbmRleCB0aGVtIHdpdGggYSBLRC10cmVlXG4gICAgY2x1c3RlcnMgPSBjbHVzdGVyKGNsdXN0ZXJzLCB6LCB0cmVlc1t6ICsgMV0sIG9wdHMpO1xuICAgIHRyZWVzW3pdID0gbmV3IEtEQnVzaChjbHVzdGVycywgZ2V0WCwgZ2V0WSwgbm9kZVNpemUsIEZsb2F0MzJBcnJheSk7XG4gIH1cblxuICBpZiAodHJlZXMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIGNvbnN0IG51bWJlcnNPZkNsdXN0ZXJzID0gdHJlZXMubWFwKChkKSA9PiBkLnBvaW50cy5sZW5ndGgpO1xuICBjb25zdCBtYXhBdmFpbFpvb20gPSBudW1iZXJzT2ZDbHVzdGVycy5pbmRleE9mKFxuICAgIG51bWJlcnNPZkNsdXN0ZXJzW251bWJlcnNPZkNsdXN0ZXJzLmxlbmd0aCAtIDFdLFxuICApO1xuICBjb25zdCBtaW5BdmFpbFpvb20gPSBNYXRoLm1pbihcbiAgICBtYXhBdmFpbFpvb20sXG4gICAgbnVtYmVyc09mQ2x1c3RlcnMubGFzdEluZGV4T2YobnVtYmVyc09mQ2x1c3RlcnNbMF0pLFxuICApO1xuXG4gIGNvbnN0IGNsdXN0ZXJMZXZlbHMgPSBuZXcgQXJyYXk8Q2x1c3RlckxldmVsPigpO1xuICBmb3IgKGxldCB6b29tID0gbWluQXZhaWxab29tOyB6b29tIDw9IG1heEF2YWlsWm9vbTsgem9vbSsrKSB7XG4gICAgbGV0IGNoaWxkcmVuQnlQYXJlbnQ6IE1hcDxudW1iZXIsIHN0cmluZ1tdPiB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCB0cmVlID0gdHJlZXNbem9vbV07XG4gICAgaWYgKHpvb20gPCBtYXhBdmFpbFpvb20pIHtcbiAgICAgIGNoaWxkcmVuQnlQYXJlbnQgPSByb2xsdXA8UG9pbnQsIHN0cmluZ1tdLCBudW1iZXI+KFxuICAgICAgICB0cmVlc1t6b29tICsgMV0ucG9pbnRzLFxuICAgICAgICAocG9pbnRzOiBhbnlbXSkgPT5cbiAgICAgICAgICBwb2ludHMubWFwKChwOiBhbnkpID0+XG4gICAgICAgICAgICBwLmlkID8gbWFrZUNsdXN0ZXJJZChwLmlkKSA6IGdldExvY2F0aW9uSWQobG9jYXRpb25zW3AuaW5kZXhdKSxcbiAgICAgICAgICApLFxuICAgICAgICAocG9pbnQ6IGFueSkgPT4gcG9pbnQucGFyZW50SWQsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IG5vZGVzOiBDbHVzdGVyTm9kZVtdID0gW107XG4gICAgZm9yIChjb25zdCBwb2ludCBvZiB0cmVlLnBvaW50cykge1xuICAgICAgY29uc3Qge3gsIHksIG51bVBvaW50c30gPSBwb2ludDtcbiAgICAgIGlmIChpc0xlYWZQb2ludChwb2ludCkpIHtcbiAgICAgICAgY29uc3QgbG9jYXRpb24gPSBsb2NhdGlvbnNbcG9pbnQuaW5kZXhdO1xuICAgICAgICBub2Rlcy5wdXNoKHtcbiAgICAgICAgICBpZDogZ2V0TG9jYXRpb25JZChsb2NhdGlvbiksXG4gICAgICAgICAgem9vbSxcbiAgICAgICAgICBjZW50cm9pZDogZ2V0TG9jYXRpb25DZW50cm9pZChsb2NhdGlvbiksXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChpc0NsdXN0ZXJQb2ludChwb2ludCkpIHtcbiAgICAgICAgY29uc3Qge2lkfSA9IHBvaW50O1xuICAgICAgICBjb25zdCBjaGlsZHJlbiA9IGNoaWxkcmVuQnlQYXJlbnQgJiYgY2hpbGRyZW5CeVBhcmVudC5nZXQoaWQpO1xuICAgICAgICBpZiAoIWNoaWxkcmVuKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDbHVzdGVyICR7aWR9IGRvZXNuJ3QgaGF2ZSBjaGlsZHJlbmApO1xuICAgICAgICB9XG4gICAgICAgIG5vZGVzLnB1c2goe1xuICAgICAgICAgIGlkOiBtYWtlQ2x1c3RlcklkKGlkKSxcbiAgICAgICAgICBuYW1lOiBtYWtlQ2x1c3Rlck5hbWUoaWQsIG51bVBvaW50cyksXG4gICAgICAgICAgem9vbSxcbiAgICAgICAgICBjZW50cm9pZDogW3hMbmcoeCksIHlMYXQoeSldIGFzIFtudW1iZXIsIG51bWJlcl0sXG4gICAgICAgICAgY2hpbGRyZW4sXG4gICAgICAgIH0gYXMgQ2x1c3Rlcik7XG4gICAgICB9XG4gICAgfVxuICAgIGNsdXN0ZXJMZXZlbHMucHVzaCh7XG4gICAgICB6b29tLFxuICAgICAgbm9kZXMsXG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGNsdXN0ZXJMZXZlbHM7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUNsdXN0ZXIoXG4gIHg6IG51bWJlcixcbiAgeTogbnVtYmVyLFxuICBpZDogbnVtYmVyLFxuICBudW1Qb2ludHM6IG51bWJlcixcbiAgd2VpZ2h0OiBudW1iZXIsXG4pOiBDbHVzdGVyUG9pbnQge1xuICByZXR1cm4ge1xuICAgIHgsIC8vIHdlaWdodGVkIGNsdXN0ZXIgY2VudGVyXG4gICAgeSxcbiAgICB6b29tOiBJbmZpbml0eSwgLy8gdGhlIGxhc3Qgem9vbSB0aGUgY2x1c3RlciB3YXMgcHJvY2Vzc2VkIGF0XG4gICAgaWQsIC8vIGVuY29kZXMgaW5kZXggb2YgdGhlIGZpcnN0IGNoaWxkIG9mIHRoZSBjbHVzdGVyIGFuZCBpdHMgem9vbSBsZXZlbFxuICAgIHBhcmVudElkOiAtMSwgLy8gcGFyZW50IGNsdXN0ZXIgaWRcbiAgICBudW1Qb2ludHMsXG4gICAgd2VpZ2h0LFxuICB9O1xufVxuXG5mdW5jdGlvbiBjbHVzdGVyKFxuICBwb2ludHM6IFBvaW50W10sXG4gIHpvb206IG51bWJlcixcbiAgdHJlZTogWm9vbUxldmVsS0RCdXNoLFxuICBvcHRpb25zOiBPcHRpb25zLFxuKSB7XG4gIGNvbnN0IGNsdXN0ZXJzOiBQb2ludFtdID0gW107XG4gIGNvbnN0IHtyYWRpdXMsIGV4dGVudH0gPSBvcHRpb25zO1xuICBjb25zdCByID0gcmFkaXVzIC8gKGV4dGVudCAqIE1hdGgucG93KDIsIHpvb20pKTtcblxuICAvLyBsb29wIHRocm91Z2ggZWFjaCBwb2ludFxuICBmb3IgKGxldCBpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IHAgPSBwb2ludHNbaV07XG4gICAgLy8gaWYgd2UndmUgYWxyZWFkeSB2aXNpdGVkIHRoZSBwb2ludCBhdCB0aGlzIHpvb20gbGV2ZWwsIHNraXAgaXRcbiAgICBpZiAocC56b29tIDw9IHpvb20pIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBwLnpvb20gPSB6b29tO1xuXG4gICAgLy8gZmluZCBhbGwgbmVhcmJ5IHBvaW50c1xuICAgIGNvbnN0IG5laWdoYm9ySWRzID0gdHJlZS53aXRoaW4ocC54LCBwLnksIHIpO1xuXG4gICAgbGV0IHdlaWdodCA9IHAud2VpZ2h0IHx8IDE7XG4gICAgbGV0IG51bVBvaW50cyA9IGlzQ2x1c3RlclBvaW50KHApID8gcC5udW1Qb2ludHMgOiAxO1xuICAgIGxldCB3eCA9IHAueCAqIHdlaWdodDtcbiAgICBsZXQgd3kgPSBwLnkgKiB3ZWlnaHQ7XG5cbiAgICAvLyBlbmNvZGUgYm90aCB6b29tIGFuZCBwb2ludCBpbmRleCBvbiB3aGljaCB0aGUgY2x1c3RlciBvcmlnaW5hdGVkXG4gICAgY29uc3QgaWQgPSAoaSA8PCA1KSArICh6b29tICsgMSk7XG5cbiAgICBmb3IgKGNvbnN0IG5laWdoYm9ySWQgb2YgbmVpZ2hib3JJZHMpIHtcbiAgICAgIGNvbnN0IGIgPSB0cmVlLnBvaW50c1tuZWlnaGJvcklkXTtcbiAgICAgIC8vIGZpbHRlciBvdXQgbmVpZ2hib3JzIHRoYXQgYXJlIGFscmVhZHkgcHJvY2Vzc2VkXG4gICAgICBpZiAoYi56b29tIDw9IHpvb20pIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBiLnpvb20gPSB6b29tOyAvLyBzYXZlIHRoZSB6b29tIChzbyBpdCBkb2Vzbid0IGdldCBwcm9jZXNzZWQgdHdpY2UpXG5cbiAgICAgIGNvbnN0IHdlaWdodDIgPSBiLndlaWdodCB8fCAxO1xuICAgICAgY29uc3QgbnVtUG9pbnRzMiA9IGIubnVtUG9pbnRzIHx8IDE7XG4gICAgICB3eCArPSBiLnggKiB3ZWlnaHQyOyAvLyBhY2N1bXVsYXRlIGNvb3JkaW5hdGVzIGZvciBjYWxjdWxhdGluZyB3ZWlnaHRlZCBjZW50ZXJcbiAgICAgIHd5ICs9IGIueSAqIHdlaWdodDI7XG5cbiAgICAgIHdlaWdodCArPSB3ZWlnaHQyO1xuICAgICAgbnVtUG9pbnRzICs9IG51bVBvaW50czI7XG4gICAgICBiLnBhcmVudElkID0gaWQ7XG4gICAgfVxuXG4gICAgaWYgKG51bVBvaW50cyA9PT0gMSkge1xuICAgICAgY2x1c3RlcnMucHVzaChwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcC5wYXJlbnRJZCA9IGlkO1xuICAgICAgY2x1c3RlcnMucHVzaChcbiAgICAgICAgY3JlYXRlQ2x1c3Rlcih3eCAvIHdlaWdodCwgd3kgLyB3ZWlnaHQsIGlkLCBudW1Qb2ludHMsIHdlaWdodCksXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBjbHVzdGVycztcbn1cblxuLy8gc3BoZXJpY2FsIG1lcmNhdG9yIHRvIGxvbmdpdHVkZS9sYXRpdHVkZVxuZnVuY3Rpb24geExuZyh4OiBudW1iZXIpIHtcbiAgcmV0dXJuICh4IC0gMC41KSAqIDM2MDtcbn1cblxuZnVuY3Rpb24geUxhdCh5OiBudW1iZXIpIHtcbiAgY29uc3QgeTIgPSAoKDE4MCAtIHkgKiAzNjApICogTWF0aC5QSSkgLyAxODA7XG4gIHJldHVybiAoMzYwICogTWF0aC5hdGFuKE1hdGguZXhwKHkyKSkpIC8gTWF0aC5QSSAtIDkwO1xufVxuXG4vLyBsb25naXR1ZGUvbGF0aXR1ZGUgdG8gc3BoZXJpY2FsIG1lcmNhdG9yIGluIFswLi4xXSByYW5nZVxuZnVuY3Rpb24gbG5nWChsbmc6IG51bWJlcikge1xuICByZXR1cm4gbG5nIC8gMzYwICsgMC41O1xufVxuXG5mdW5jdGlvbiBsYXRZKGxhdDogbnVtYmVyKSB7XG4gIGNvbnN0IHNpbiA9IE1hdGguc2luKChsYXQgKiBNYXRoLlBJKSAvIDE4MCk7XG4gIGNvbnN0IHkgPSAwLjUgLSAoMC4yNSAqIE1hdGgubG9nKCgxICsgc2luKSAvICgxIC0gc2luKSkpIC8gTWF0aC5QSTtcbiAgcmV0dXJuIHkgPCAwID8gMCA6IHkgPiAxID8gMSA6IHk7XG59XG5cbmZ1bmN0aW9uIGdldFgocDogUG9pbnQpIHtcbiAgcmV0dXJuIHAueDtcbn1cblxuZnVuY3Rpb24gZ2V0WShwOiBQb2ludCkge1xuICByZXR1cm4gcC55O1xufVxuIl19
|