text-to-map 1.1.45 → 1.1.47
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 +21 -21
- package/README.md +69 -69
- package/dist/bin/address-points.d.ts +1 -1
- package/dist/bin/address-points.js +16 -16
- package/dist/bin/cities.d.ts +1 -1
- package/dist/bin/cities.js +10 -10
- package/dist/bin/clear-all.d.ts +1 -1
- package/dist/bin/clear-all.js +13 -13
- package/dist/bin/constants.d.ts +2 -2
- package/dist/bin/constants.js +4 -4
- package/dist/bin/generate-syntax-diagrams.d.ts +1 -1
- package/dist/bin/generate-syntax-diagrams.js +20 -20
- package/dist/bin/init-db.d.ts +1 -1
- package/dist/bin/init-db.js +8 -8
- package/dist/bin/knex.d.ts +1 -1
- package/dist/bin/knex.js +10 -10
- package/dist/bin/parse-ordinance.d.ts +1 -1
- package/dist/bin/parse-ordinance.js +74 -74
- package/dist/bin/polygons.d.ts +1 -1
- package/dist/bin/polygons.js +27 -27
- package/dist/bin/regions.d.ts +1 -1
- package/dist/bin/regions.js +10 -10
- package/dist/bin/schools.d.ts +1 -1
- package/dist/bin/schools.js +10 -10
- package/dist/bin/streets.d.ts +1 -1
- package/dist/bin/streets.js +19 -19
- package/dist/bin/sync-all.d.ts +1 -1
- package/dist/bin/sync-all.js +4 -4
- package/dist/db/address-points.d.ts +59 -59
- package/dist/db/address-points.js +401 -399
- package/dist/db/cities.d.ts +7 -7
- package/dist/db/cities.js +95 -95
- package/dist/db/db.d.ts +37 -37
- package/dist/db/db.js +191 -191
- package/dist/db/founders.d.ts +14 -14
- package/dist/db/founders.js +461 -461
- package/dist/db/meta.d.ts +4 -4
- package/dist/db/meta.js +26 -26
- package/dist/db/migrations/20230704125715_initial.js +304 -304
- package/dist/db/migrations/20230731232915_city_positions.js +13 -13
- package/dist/db/migrations/20240106224603_city_polygon.js +11 -11
- package/dist/db/migrations/20240320200534_district_polygon.js +11 -11
- package/dist/db/migrations/20250316162700_kindergartens.js +12 -12
- package/dist/db/regions.d.ts +31 -31
- package/dist/db/regions.js +81 -81
- package/dist/db/schools.d.ts +7 -7
- package/dist/db/schools.js +95 -95
- package/dist/db/street-sync.d.ts +6 -6
- package/dist/db/street-sync.js +22 -22
- package/dist/db/sync-log.d.ts +9 -9
- package/dist/db/sync-log.js +66 -66
- package/dist/db/types.d.ts +59 -59
- package/dist/db/types.js +26 -26
- package/dist/index.d.ts +23 -23
- package/dist/index.js +32 -32
- package/dist/open-data-sync/address-points.d.ts +2 -2
- package/dist/open-data-sync/address-points.js +68 -68
- package/dist/open-data-sync/cities.d.ts +2 -2
- package/dist/open-data-sync/cities.js +32 -32
- package/dist/open-data-sync/common.d.ts +2 -2
- package/dist/open-data-sync/common.js +22 -22
- package/dist/open-data-sync/regions.d.ts +2 -2
- package/dist/open-data-sync/regions.js +37 -37
- package/dist/open-data-sync/schools.d.ts +3 -3
- package/dist/open-data-sync/schools.js +207 -207
- package/dist/open-data-sync/streets.d.ts +2 -2
- package/dist/open-data-sync/streets.js +132 -132
- package/dist/smd-to-csv/json-to-csv.d.ts +1 -1
- package/dist/smd-to-csv/json-to-csv.js +154 -154
- package/dist/smd-to-csv/ordinance-to-csv-rules.d.ts +1 -1
- package/dist/smd-to-csv/ordinance-to-csv-rules.js +23 -23
- package/dist/smd-to-csv/txt-to-json.d.ts +1 -1
- package/dist/smd-to-csv/txt-to-json.js +92 -92
- package/dist/souradnice.csv +6260 -6260
- package/dist/street-markdown/municipality.d.ts +11 -11
- package/dist/street-markdown/municipality.js +116 -116
- package/dist/street-markdown/polygons.d.ts +7 -7
- package/dist/street-markdown/polygons.js +261 -261
- package/dist/street-markdown/roman-numerals.d.ts +1 -1
- package/dist/street-markdown/roman-numerals.js +68 -68
- package/dist/street-markdown/smd-line-parser.d.ts +4 -4
- package/dist/street-markdown/smd-line-parser.js +40 -40
- package/dist/street-markdown/smd-parser.d.ts +23 -23
- package/dist/street-markdown/smd-parser.js +393 -393
- package/dist/street-markdown/smd.d.ts +24 -24
- package/dist/street-markdown/smd.js +440 -440
- package/dist/street-markdown/token-definition.d.ts +25 -25
- package/dist/street-markdown/token-definition.js +168 -168
- package/dist/street-markdown/types.d.ts +148 -148
- package/dist/street-markdown/types.js +13 -13
- package/dist/utils/atom.d.ts +2 -2
- package/dist/utils/atom.js +57 -57
- package/dist/utils/helpers.d.ts +28 -28
- package/dist/utils/helpers.js +176 -176
- package/dist/utils/jtsk2wgs84.d.ts +17 -17
- package/dist/utils/jtsk2wgs84.js +82 -82
- package/package.json +109 -109
|
@@ -1,399 +1,401 @@
|
|
|
1
|
-
import { AddressPointType, createSingleLineAddress } from "czech-address";
|
|
2
|
-
import { SeriesType, isNegativeSeriesSpec, isRange, isSeriesSpecArray, } from "../street-markdown/types";
|
|
3
|
-
import { findClosestString, roundToNDecimalPlaces } from "../utils/helpers";
|
|
4
|
-
import jtsk2wgs84 from "../utils/jtsk2wgs84";
|
|
5
|
-
import { extractKeyValuesPairs, generate2DPlaceholders, getKnexDb, insertMultipleRows, isMysql, isSqlite, nonEmptyOrNull, rawQuery, } from "./db";
|
|
6
|
-
import { getFounderCityCode } from "./founders";
|
|
7
|
-
import { MunicipalityType } from "./types";
|
|
8
|
-
import chunk from "lodash/chunk";
|
|
9
|
-
const DescriptiveType = "č.p.";
|
|
10
|
-
const RegistrationType = "č.ev.";
|
|
11
|
-
const ObjectTypes = {
|
|
12
|
-
[DescriptiveType]: 1,
|
|
13
|
-
[RegistrationType]: 2,
|
|
14
|
-
};
|
|
15
|
-
export const Column = {
|
|
16
|
-
admCode: 0,
|
|
17
|
-
cityCode: 1,
|
|
18
|
-
cityName: 2,
|
|
19
|
-
districtCode: 3,
|
|
20
|
-
districtName: 4,
|
|
21
|
-
pragueDistrictCode: 5,
|
|
22
|
-
pragueDistrictName: 6,
|
|
23
|
-
municipalityPartCode: 7,
|
|
24
|
-
municipalityPartName: 8,
|
|
25
|
-
streetCode: 9,
|
|
26
|
-
streetName: 10,
|
|
27
|
-
objectType: 11,
|
|
28
|
-
houseNumber: 12,
|
|
29
|
-
orientationalNumber: 13,
|
|
30
|
-
orientationalNumberLetter: 14,
|
|
31
|
-
postalCode: 15,
|
|
32
|
-
yCoordinate: 16,
|
|
33
|
-
xCoordinate: 17,
|
|
34
|
-
validFrom: 18,
|
|
35
|
-
};
|
|
36
|
-
const columnNames = [
|
|
37
|
-
"id",
|
|
38
|
-
"street_code",
|
|
39
|
-
"object_type_id",
|
|
40
|
-
"descriptive_number",
|
|
41
|
-
"orientational_number",
|
|
42
|
-
"orientational_number_letter",
|
|
43
|
-
"city_code",
|
|
44
|
-
"city_district_code",
|
|
45
|
-
"municipality_part_code",
|
|
46
|
-
"prague_district_code",
|
|
47
|
-
"postal_code",
|
|
48
|
-
"jtsk_x",
|
|
49
|
-
"jtsk_y",
|
|
50
|
-
"wgs84_latitude",
|
|
51
|
-
"wgs84_longitude",
|
|
52
|
-
];
|
|
53
|
-
export const commitAddressPoints = async (buffer) => {
|
|
54
|
-
if (buffer.length === 0) {
|
|
55
|
-
return 0;
|
|
56
|
-
}
|
|
57
|
-
await insertCities(buffer);
|
|
58
|
-
await insertDistricts(buffer);
|
|
59
|
-
await insertMunicipalityParts(buffer);
|
|
60
|
-
await insertStreets(buffer);
|
|
61
|
-
await insertPragueDistricts(buffer);
|
|
62
|
-
const params = {};
|
|
63
|
-
buffer.forEach((data) => {
|
|
64
|
-
let latOrNull, lonOrNull;
|
|
65
|
-
latOrNull = null;
|
|
66
|
-
lonOrNull = null;
|
|
67
|
-
if (data[Column.xCoordinate] && data[Column.yCoordinate]) {
|
|
68
|
-
const { lat, lon } = jtsk2wgs84(parseFloat(data[Column.xCoordinate]), parseFloat(data[Column.yCoordinate]));
|
|
69
|
-
[latOrNull, lonOrNull] = [lat.toString(), lon.toString()];
|
|
70
|
-
}
|
|
71
|
-
params[data[Column.admCode]] = [
|
|
72
|
-
data[Column.admCode],
|
|
73
|
-
nonEmptyOrNull(data[Column.streetCode]),
|
|
74
|
-
ObjectTypes[data[Column.objectType]],
|
|
75
|
-
nonEmptyOrNull(data[Column.houseNumber]),
|
|
76
|
-
nonEmptyOrNull(data[Column.orientationalNumber]),
|
|
77
|
-
nonEmptyOrNull(data[Column.orientationalNumberLetter]),
|
|
78
|
-
data[Column.cityCode],
|
|
79
|
-
nonEmptyOrNull(data[Column.districtCode]),
|
|
80
|
-
nonEmptyOrNull(data[Column.municipalityPartCode]),
|
|
81
|
-
nonEmptyOrNull(data[Column.pragueDistrictCode]),
|
|
82
|
-
data[Column.postalCode],
|
|
83
|
-
nonEmptyOrNull(data[Column.xCoordinate]),
|
|
84
|
-
nonEmptyOrNull(data[Column.yCoordinate]),
|
|
85
|
-
latOrNull,
|
|
86
|
-
lonOrNull,
|
|
87
|
-
];
|
|
88
|
-
});
|
|
89
|
-
// find already existing rows
|
|
90
|
-
const existingRows = await rawQuery(`SELECT * FROM address_point WHERE id IN (${buffer
|
|
91
|
-
.map((data) => data[Column.admCode])
|
|
92
|
-
.join(",")})`);
|
|
93
|
-
const queries = [];
|
|
94
|
-
for (const row of existingRows) {
|
|
95
|
-
const toInsert = params[row.id];
|
|
96
|
-
const values = Object.values(row);
|
|
97
|
-
if (!toInsert.every((v, i) => valuesEqual(v, values[i]))) {
|
|
98
|
-
// update those whose values differ
|
|
99
|
-
queries.push(rawQuery(`UPDATE address_point SET ${columnNames
|
|
100
|
-
.map((c) => `${c} = ?`)
|
|
101
|
-
.join(", ")} WHERE id = ?`, [...toInsert, row.id]));
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
await Promise.all(queries);
|
|
105
|
-
const placeHolders = generate2DPlaceholders(columnNames.length, buffer.length);
|
|
106
|
-
const knex = getKnexDb();
|
|
107
|
-
await rawQuery(`INSERT ${isMysql(knex) ? "IGNORE" : ""} INTO address_point (${columnNames.join(",")}) VALUES ${placeHolders} ${!isMysql(knex) ? "ON CONFLICT (id) DO NOTHING" : ""}`, Object.values(params).flat());
|
|
108
|
-
return buffer.length;
|
|
109
|
-
};
|
|
110
|
-
export async function removeDeprecatedAddressPoints(allIds) {
|
|
111
|
-
const knex = getKnexDb();
|
|
112
|
-
const existingIds = await knex.pluck("id").from("address_point");
|
|
113
|
-
const toRemove = existingIds.filter((id) => !allIds.has(id));
|
|
114
|
-
const chunks = chunk(toRemove, 1000);
|
|
115
|
-
for (const chunk of chunks) {
|
|
116
|
-
await knex("address_point").whereIn("id", chunk).delete();
|
|
117
|
-
}
|
|
118
|
-
console.log(`Removed ${toRemove.length} deprecated address points.`);
|
|
119
|
-
}
|
|
120
|
-
function valuesEqual(a, b) {
|
|
121
|
-
return sanitizeValue(a) === sanitizeValue(b);
|
|
122
|
-
}
|
|
123
|
-
function sanitizeValue(value) {
|
|
124
|
-
if (value === null) {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
value = value.toString();
|
|
128
|
-
if (/\d+\.\d+/.test(value)) {
|
|
129
|
-
return roundToNDecimalPlaces(parseFloat(value), 6).toString();
|
|
130
|
-
}
|
|
131
|
-
return value;
|
|
132
|
-
}
|
|
133
|
-
export const insertCities = async (buffer) => {
|
|
134
|
-
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.cityCode, [Column.cityName]), "city", ["code", "name"]);
|
|
135
|
-
};
|
|
136
|
-
export const insertDistricts = async (buffer) => {
|
|
137
|
-
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.districtCode, [
|
|
138
|
-
Column.cityCode,
|
|
139
|
-
Column.districtName,
|
|
140
|
-
]), "city_district", ["code", "city_code", "name"]);
|
|
141
|
-
};
|
|
142
|
-
export const insertMunicipalityParts = async (buffer) => {
|
|
143
|
-
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.municipalityPartCode, [
|
|
144
|
-
Column.municipalityPartName,
|
|
145
|
-
Column.cityCode,
|
|
146
|
-
]), "municipality_part", ["code", "name", "city_code"]);
|
|
147
|
-
};
|
|
148
|
-
export const insertPragueDistricts = async (buffer) => {
|
|
149
|
-
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.pragueDistrictCode, [
|
|
150
|
-
Column.pragueDistrictName,
|
|
151
|
-
]), "prague_district", ["code", "name"]);
|
|
152
|
-
};
|
|
153
|
-
export const insertStreets = async (buffer) => {
|
|
154
|
-
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.streetCode, [
|
|
155
|
-
Column.cityCode,
|
|
156
|
-
Column.streetName,
|
|
157
|
-
]), "street", ["code", "city_code", "name"]);
|
|
158
|
-
};
|
|
159
|
-
export const areAddressPointsSynced = async () => {
|
|
160
|
-
const result = await getKnexDb()
|
|
161
|
-
.count("*", { as: "countAll" })
|
|
162
|
-
.from("address_point")
|
|
163
|
-
.first();
|
|
164
|
-
return Number(result.countAll) >= 2900000; // total is almost 3 million
|
|
165
|
-
};
|
|
166
|
-
const addressPointSelect = `
|
|
167
|
-
SELECT a.id, s.name AS street_name, o.name AS object_type_name, a.descriptive_number,
|
|
168
|
-
a.orientational_number, a.orientational_number_letter, c.name AS city_name,
|
|
169
|
-
m.name AS municipality_part_name, p.name AS prague_district_name,
|
|
170
|
-
d.name AS district_name, a.postal_code, a.wgs84_latitude, a.wgs84_longitude
|
|
171
|
-
FROM address_point a
|
|
172
|
-
LEFT JOIN street s ON a.street_code = s.code
|
|
173
|
-
INNER JOIN object_type o ON o.id = a.object_type_id
|
|
174
|
-
INNER JOIN city c ON c.code = a.city_code
|
|
175
|
-
LEFT JOIN city_district d ON a.city_district_code = d.code
|
|
176
|
-
LEFT JOIN prague_district p ON a.prague_district_code = p.code
|
|
177
|
-
LEFT JOIN municipality_part m ON a.municipality_part_code = m.code`;
|
|
178
|
-
export const getAddressPointById = async (addressPointId) => {
|
|
179
|
-
const row = await rawQuery(`${addressPointSelect}
|
|
180
|
-
WHERE a.id = ?`, [addressPointId]);
|
|
181
|
-
if (row.length === 0) {
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
return rowToAddressPoint(row[0]);
|
|
185
|
-
};
|
|
186
|
-
let lastFounder = null;
|
|
187
|
-
let allStreets = [];
|
|
188
|
-
export const checkStreetExists = async (streetName, founder) => {
|
|
189
|
-
const knex = getKnexDb();
|
|
190
|
-
const errors = [];
|
|
191
|
-
// we check the whole city
|
|
192
|
-
const cityCode = await getFounderCityCode(founder.municipalityType, founder.municipalityCode);
|
|
193
|
-
const rowList = await rawQuery(`SELECT name AS street_name
|
|
194
|
-
FROM street
|
|
195
|
-
WHERE city_code = ? AND name = ? ${isSqlite(knex) ? "COLLATE NOCASE" : ""}`, [cityCode, streetName]);
|
|
196
|
-
if (rowList.length > 0) {
|
|
197
|
-
const row = rowList[0];
|
|
198
|
-
if (row.street_name !== streetName) {
|
|
199
|
-
// errors.push(
|
|
200
|
-
// `Street '${streetName}' has wrong case, correct case: '${row.street_name}'.`
|
|
201
|
-
// );
|
|
202
|
-
}
|
|
203
|
-
return { exists: true, errors };
|
|
204
|
-
}
|
|
205
|
-
if (lastFounder !== founder) {
|
|
206
|
-
allStreets = await getAllStreets(cityCode);
|
|
207
|
-
lastFounder = founder;
|
|
208
|
-
}
|
|
209
|
-
const match = allStreets.find((s) => s.toLocaleLowerCase("cs-CZ") === streetName.toLocaleLowerCase("cs-CZ"));
|
|
210
|
-
let exists = false;
|
|
211
|
-
if (match) {
|
|
212
|
-
exists = true;
|
|
213
|
-
if (streetName !== match) {
|
|
214
|
-
// errors.push(
|
|
215
|
-
// `Street '${streetName}' has wrong case, correct case: '${match}'.`
|
|
216
|
-
// );
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
const closest = findClosestString(streetName, allStreets);
|
|
221
|
-
errors.push({
|
|
222
|
-
message: `Ulice '${streetName}' v této obci neexistuje, mysleli jste '${closest}'?`,
|
|
223
|
-
startOffset: 0,
|
|
224
|
-
endOffset: streetName.length + 1,
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
return { exists: false, errors };
|
|
228
|
-
};
|
|
229
|
-
const getAllStreets = async (cityCode) => {
|
|
230
|
-
const knex = getKnexDb();
|
|
231
|
-
return await knex.pluck("name").from("street").where("city_code", cityCode);
|
|
232
|
-
};
|
|
233
|
-
export const findAddressPoints = async (params) => {
|
|
234
|
-
const queryParams = getQueryParams(params);
|
|
235
|
-
const streetJoinCondition = getStreetJoinCondition(params);
|
|
236
|
-
const whereCondition = getWhereCondition(params);
|
|
237
|
-
const queryResult = await rawQuery(`SELECT a.id, s.name AS street_name, o.name AS object_type_name, a.descriptive_number,
|
|
238
|
-
a.orientational_number, a.orientational_number_letter, c.name AS city_name,
|
|
239
|
-
d.name AS district_name, m.name AS municipality_part_name, p.name AS prague_district_name,
|
|
240
|
-
a.postal_code, a.wgs84_latitude, a.wgs84_longitude
|
|
241
|
-
FROM address_point a
|
|
242
|
-
${streetJoinCondition}
|
|
243
|
-
INNER JOIN object_type o ON o.id = a.object_type_id
|
|
244
|
-
INNER JOIN city c ON c.code = a.city_code
|
|
245
|
-
LEFT JOIN city_district d ON a.city_district_code = d.code
|
|
246
|
-
LEFT JOIN municipality_part m ON a.municipality_part_code = m.code
|
|
247
|
-
LEFT JOIN prague_district p ON a.prague_district_code = p.code
|
|
248
|
-
WHERE ${whereCondition}`, queryParams);
|
|
249
|
-
return filterAddressPoints(queryResult.map(rowToAddressPoint), params);
|
|
250
|
-
};
|
|
251
|
-
export const filterAddressPoints = (addressPoints, params) => {
|
|
252
|
-
if (params.type === "wholeMunicipality" ||
|
|
253
|
-
params.type === "wholeMunicipalityNoStreetName" ||
|
|
254
|
-
params.type === "wholeMunicipalityPart") {
|
|
255
|
-
return addressPoints;
|
|
256
|
-
}
|
|
257
|
-
const result = [];
|
|
258
|
-
const numberSpec = params.smdLine.numberSpec;
|
|
259
|
-
if (isSeriesSpecArray(numberSpec)) {
|
|
260
|
-
numberSpec.forEach((seriesSpec) => {
|
|
261
|
-
result.push(...filterAddressPointsByRanges(addressPoints, seriesSpec));
|
|
262
|
-
});
|
|
263
|
-
// when no number specs are present, we take everything
|
|
264
|
-
if (numberSpec.length === 0) {
|
|
265
|
-
result.push(...addressPoints);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
else if (isNegativeSeriesSpec(numberSpec)) {
|
|
269
|
-
// negative number spec (e.g. odd numbers except 13-17)
|
|
270
|
-
const toExclude = filterAddressPointsByRanges(addressPoints, numberSpec);
|
|
271
|
-
result.push(...addressPoints.filter((addressPoint) => !toExclude.includes(addressPoint)));
|
|
272
|
-
}
|
|
273
|
-
return result;
|
|
274
|
-
};
|
|
275
|
-
const filterAddressPointsByRanges = (addressPoints, seriesSpec) => {
|
|
276
|
-
const result = [];
|
|
277
|
-
seriesSpec.ranges.forEach((range) => {
|
|
278
|
-
result.push(...addressPoints.filter((addressPoint) => {
|
|
279
|
-
if (isRange(range)) {
|
|
280
|
-
const number = getNumberByType(seriesSpec.type, addressPoint);
|
|
281
|
-
return (isInRange(number, seriesSpec.type !== SeriesType.Description
|
|
282
|
-
? addressPoint.orientationalNumberLetter ?? null
|
|
283
|
-
: null, range) && fitsType(number, seriesSpec.type));
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
const fullStreetNumber = range;
|
|
287
|
-
return equalsFullStreetNumber(fullStreetNumber, addressPoint);
|
|
288
|
-
}
|
|
289
|
-
}));
|
|
290
|
-
});
|
|
291
|
-
// when no series specs are present, we take everything that fits the type
|
|
292
|
-
if (seriesSpec.ranges.length === 0) {
|
|
293
|
-
result.push(...addressPoints.filter((addressPoint) => fitsType(getNumberByType(seriesSpec.type, addressPoint), seriesSpec.type)));
|
|
294
|
-
}
|
|
295
|
-
return result;
|
|
296
|
-
};
|
|
297
|
-
export const getQueryParams = (params) => {
|
|
298
|
-
if (params.type === "smdLine" && params.smdLine.type === "street") {
|
|
299
|
-
return [params.smdLine.street, params.municipality.code];
|
|
300
|
-
}
|
|
301
|
-
if ((params.type === "smdLine" && params.smdLine.type === "municipalityPart") ||
|
|
302
|
-
params.type === "wholeMunicipalityPart") {
|
|
303
|
-
return [params.municipalityPartCode];
|
|
304
|
-
}
|
|
305
|
-
return [params.municipality.code];
|
|
306
|
-
};
|
|
307
|
-
export const getStreetJoinCondition = (params) => {
|
|
308
|
-
if (params.type === "smdLine" && params.smdLine.type === "street") {
|
|
309
|
-
return `JOIN street s ON a.street_code = s.code AND s.name = ? ${isSqlite(getKnexDb()) ? "COLLATE NOCASE" : ""}`;
|
|
310
|
-
}
|
|
311
|
-
return "LEFT JOIN street s ON a.street_code = s.code";
|
|
312
|
-
};
|
|
313
|
-
export const getWhereCondition = (params) => {
|
|
314
|
-
if ((params.type === "smdLine" && params.smdLine.type === "municipalityPart") ||
|
|
315
|
-
params.type === "wholeMunicipalityPart") {
|
|
316
|
-
return "a.municipality_part_code = ?";
|
|
317
|
-
}
|
|
318
|
-
if (params.type === "wholeMunicipalityNoStreetName") {
|
|
319
|
-
return `${getMunicipalityWhere("a", params.municipality)} AND a.street_code IS NULL`;
|
|
320
|
-
}
|
|
321
|
-
return getMunicipalityWhere("a", params.municipality);
|
|
322
|
-
};
|
|
323
|
-
export const isInRange = (number, letter, range) => {
|
|
324
|
-
if (number === null) {
|
|
325
|
-
return !range.from && !range.to;
|
|
326
|
-
}
|
|
327
|
-
// explainer: either the lower bound is not set, or it is lower than the number
|
|
328
|
-
// if it's equal to the number, we also have to check the letter - if it's not set, we don't care
|
|
329
|
-
// if from.letter is set, we need to have a letter set and it has to be greater or equal:
|
|
330
|
-
// number without letter counts lower than number with letter 'a' (e.g. 23 < 23a)
|
|
331
|
-
const satisfiesFrom = !range.from ||
|
|
332
|
-
number > range.from.number ||
|
|
333
|
-
(number === range.from.number &&
|
|
334
|
-
(!range.from.letter || (!!letter && letter >= range.from.letter)));
|
|
335
|
-
const satisfiesTo = !range.to ||
|
|
336
|
-
number < range.to.number ||
|
|
337
|
-
(number === range.to.number &&
|
|
338
|
-
(!letter ||
|
|
339
|
-
(!!range.to.letter && !!letter && letter <= range.to.letter)));
|
|
340
|
-
return satisfiesFrom && satisfiesTo;
|
|
341
|
-
};
|
|
342
|
-
export const fitsType = (number, type) => {
|
|
343
|
-
return (type === SeriesType.Description ||
|
|
344
|
-
type === SeriesType.All ||
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRkcmVzcy1wb2ludHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGIvYWRkcmVzcy1wb2ludHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLHVCQUF1QixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFFLE9BQU8sRUFLTCxVQUFVLEVBR1Ysb0JBQW9CLEVBQ3BCLE9BQU8sRUFDUCxpQkFBaUIsR0FDbEIsTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM1RSxPQUFPLFVBQVUsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QyxPQUFPLEVBQ0wscUJBQXFCLEVBQ3JCLHNCQUFzQixFQUN0QixTQUFTLEVBQ1Qsa0JBQWtCLEVBQ2xCLE9BQU8sRUFDUCxRQUFRLEVBQ1IsY0FBYyxFQUNkLFFBQVEsR0FDVCxNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUNoRCxPQUFPLEVBQXlCLGdCQUFnQixFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ2xFLE9BQU8sS0FBSyxNQUFNLGNBQWMsQ0FBQztBQUVqQyxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUM7QUFDL0IsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUM7QUFFakMsTUFBTSxXQUFXLEdBQUc7SUFDbEIsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO0lBQ3BCLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxDQUFDO0NBQ3RCLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxNQUFNLEdBQUc7SUFDcEIsT0FBTyxFQUFFLENBQUM7SUFDVixRQUFRLEVBQUUsQ0FBQztJQUNYLFFBQVEsRUFBRSxDQUFDO0lBQ1gsWUFBWSxFQUFFLENBQUM7SUFDZixZQUFZLEVBQUUsQ0FBQztJQUNmLGtCQUFrQixFQUFFLENBQUM7SUFD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YUFBYSxDQUFDO0tBQ3BDO0lBQ0QsSUFBSSxHQUFHLENBQUMsb0JBQW9CLEtBQUssSUFBSSxFQUFFO1FBQ3JDLEtBQUssQ0FBQyxjQUFjLEdBQUcsR0FBRyxDQUFDLG9CQUFvQixDQUFDO0tBQ2pEO0lBQ0QsS0FBSyxDQUFDLE9BQU8sR0FBRyx1QkFBdUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMvQyxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFkZHJlc3NQb2ludFR5cGUsIGNyZWF0ZVNpbmdsZUxpbmVBZGRyZXNzIH0gZnJvbSBcImN6ZWNoLWFkZHJlc3NcIjtcclxuaW1wb3J0IHtcclxuICBBZGRyZXNzUG9pbnQsXHJcbiAgRnVsbFN0cmVldE51bWJlcixcclxuICBSYW5nZVNwZWMsXHJcbiAgU2VyaWVzU3BlYyxcclxuICBTZXJpZXNUeXBlLFxyXG4gIFNtZEVycm9yLFxyXG4gIFNtZExpbmUsXHJcbiAgaXNOZWdhdGl2ZVNlcmllc1NwZWMsXHJcbiAgaXNSYW5nZSxcclxuICBpc1Nlcmllc1NwZWNBcnJheSxcclxufSBmcm9tIFwiLi4vc3RyZWV0LW1hcmtkb3duL3R5cGVzXCI7XHJcbmltcG9ydCB7IGZpbmRDbG9zZXN0U3RyaW5nLCByb3VuZFRvTkRlY2ltYWxQbGFjZXMgfSBmcm9tIFwiLi4vdXRpbHMvaGVscGVyc1wiO1xyXG5pbXBvcnQganRzazJ3Z3M4NCBmcm9tIFwiLi4vdXRpbHMvanRzazJ3Z3M4NFwiO1xyXG5pbXBvcnQge1xyXG4gIGV4dHJhY3RLZXlWYWx1ZXNQYWlycyxcclxuICBnZW5lcmF0ZTJEUGxhY2Vob2xkZXJzLFxyXG4gIGdldEtuZXhEYixcclxuICBpbnNlcnRNdWx0aXBsZVJvd3MsXHJcbiAgaXNNeXNxbCxcclxuICBpc1NxbGl0ZSxcclxuICBub25FbXB0eU9yTnVsbCxcclxuICByYXdRdWVyeSxcclxufSBmcm9tIFwiLi9kYlwiO1xyXG5pbXBvcnQgeyBnZXRGb3VuZGVyQ2l0eUNvZGUgfSBmcm9tIFwiLi9mb3VuZGVyc1wiO1xyXG5pbXBvcnQgeyBGb3VuZGVyLCBNdW5pY2lwYWxpdHksIE11bmljaXBhbGl0eVR5cGUgfSBmcm9tIFwiLi90eXBlc1wiO1xyXG5pbXBvcnQgY2h1bmsgZnJvbSBcImxvZGFzaC9jaHVua1wiO1xyXG5cclxuY29uc3QgRGVzY3JpcHRpdmVUeXBlID0gXCLEjS5wLlwiO1xyXG5jb25zdCBSZWdpc3RyYXRpb25UeXBlID0gXCLEjS5ldi5cIjtcclxuXHJcbmNvbnN0IE9iamVjdFR5cGVzID0ge1xyXG4gIFtEZXNjcmlwdGl2ZVR5cGVdOiAxLFxyXG4gIFtSZWdpc3RyYXRpb25UeXBlXTogMixcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb2x1bW4gPSB7XHJcbiAgYWRtQ29kZTogMCxcclxuICBjaXR5Q29kZTogMSxcclxuICBjaXR5TmFtZTogMixcclxuICBkaXN0cmljdENvZGU6IDMsXHJcbiAgZGlzdHJpY3ROYW1lOiA0LFxyXG4gIHByYWd1ZURpc3RyaWN0Q29kZTogNSxcclxuICBwcmFndWVEaXN0cmljdE5hbWU6IDYsXHJcbiAgbXVuaWNpcGFsaXR5UGFydENvZGU6IDcsXHJcbiAgbXVuaWNpcGFsaXR5UGFydE5hbWU6IDgsXHJcbiAgc3RyZWV0Q29kZTogOSxcclxuICBzdHJlZXROYW1lOiAxMCxcclxuICBvYmplY3RUeXBlOiAxMSxcclxuICBob3VzZU51bWJlcjogMTIsXHJcbiAgb3JpZW50YXRpb25hbE51bWJlcjogMTMsXHJcbiAgb3JpZW50YXRpb25hbE51bWJlckxldHRlcjogMTQsXHJcbiAgcG9zdGFsQ29kZTogMTUsXHJcbiAgeUNvb3JkaW5hdGU6IDE2LFxyXG4gIHhDb29yZGluYXRlOiAxNyxcclxuICB2YWxpZEZyb206IDE4LFxyXG59O1xyXG5cclxuY29uc3QgY29sdW1uTmFtZXMgPSBbXHJcbiAgXCJpZFwiLFxyXG4gIFwic3RyZWV0X2NvZGVcIixcclxuICBcIm9iamVjdF90eXBlX2lkXCIsXHJcbiAgXCJkZXNjcmlwdGl2ZV9udW1iZXJcIixcclxuICBcIm9yaWVudGF0aW9uYWxfbnVtYmVyXCIsXHJcbiAgXCJvcmllbnRhdGlvbmFsX251bWJlcl9sZXR0ZXJcIixcclxuICBcImNpdHlfY29kZVwiLFxyXG4gIFwiY2l0eV9kaXN0cmljdF9jb2RlXCIsXHJcbiAgXCJtdW5pY2lwYWxpdHlfcGFydF9jb2RlXCIsXHJcbiAgXCJwcmFndWVfZGlzdHJpY3RfY29kZVwiLFxyXG4gIFwicG9zdGFsX2NvZGVcIixcclxuICBcImp0c2tfeFwiLFxyXG4gIFwianRza195XCIsXHJcbiAgXCJ3Z3M4NF9sYXRpdHVkZVwiLFxyXG4gIFwid2dzODRfbG9uZ2l0dWRlXCIsXHJcbl07XHJcblxyXG5leHBvcnQgY29uc3QgY29tbWl0QWRkcmVzc1BvaW50cyA9IGFzeW5jIChcclxuICBidWZmZXI6IHN0cmluZ1tdW11cclxuKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcclxuICBpZiAoYnVmZmVyLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIDA7XHJcbiAgfVxyXG4gIGF3YWl0IGluc2VydENpdGllcyhidWZmZXIpO1xyXG4gIGF3YWl0IGluc2VydERpc3RyaWN0cyhidWZmZXIpO1xyXG4gIGF3YWl0IGluc2VydE11bmljaXBhbGl0eVBhcnRzKGJ1ZmZlcik7XHJcbiAgYXdhaXQgaW5zZXJ0U3RyZWV0cyhidWZmZXIpO1xyXG4gIGF3YWl0IGluc2VydFByYWd1ZURpc3RyaWN0cyhidWZmZXIpO1xyXG5cclxuICBjb25zdCBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIChzdHJpbmcgfCBudWxsKVtdPiA9IHt9O1xyXG4gIGJ1ZmZlci5mb3JFYWNoKChkYXRhKSA9PiB7XHJcbiAgICBsZXQgbGF0T3JOdWxsOiBzdHJpbmcsIGxvbk9yTnVsbDogc3RyaW5nO1xyXG4gICAgbGF0T3JOdWxsID0gbnVsbDtcclxuICAgIGxvbk9yTnVsbCA9IG51bGw7XHJcbiAgICBpZiAoZGF0YVtDb2x1bW4ueENvb3JkaW5hdGVdICYmIGRhdGFbQ29sdW1uLnlDb29yZGluYXRlXSkge1xyXG4gICAgICBjb25zdCB7IGxhdCwgbG9uIH0gPSBqdHNrMndnczg0KFxyXG4gICAgICAgIHBhcnNlRmxvYXQoZGF0YVtDb2x1bW4ueENvb3JkaW5hdGVdKSxcclxuICAgICAgICBwYXJzZUZsb2F0KGRhdGFbQ29sdW1uLnlDb29yZGluYXRlXSlcclxuICAgICAgKTtcclxuICAgICAgW2xhdE9yTnVsbCwgbG9uT3JOdWxsXSA9IFtsYXQudG9TdHJpbmcoKSwgbG9uLnRvU3RyaW5nKCldO1xyXG4gICAgfVxyXG4gICAgcGFyYW1zW2RhdGFbQ29sdW1uLmFkbUNvZGVdXSA9IFtcclxuICAgICAgZGF0YVtDb2x1bW4uYWRtQ29kZV0sXHJcbiAgICAgIG5vbkVtcHR5T3JOdWxsKGRhdGFbQ29sdW1uLnN0cmVldENvZGVdKSxcclxuICAgICAgT2JqZWN0VHlwZXNbZGF0YVtDb2x1bW4ub2JqZWN0VHlwZV1dLFxyXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi5ob3VzZU51bWJlcl0pLFxyXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi5vcmllbnRhdGlvbmFsTnVtYmVyXSksXHJcbiAgICAgIG5vbkVtcHR5T3JOdWxsKGRhdGFbQ29sdW1uLm9yaWVudGF0aW9uYWxOdW1iZXJMZXR0ZXJdKSxcclxuICAgICAgZGF0YVtDb2x1bW4uY2l0eUNvZGVdLFxyXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi5kaXN0cmljdENvZGVdKSxcclxuICAgICAgbm9uRW1wdHlPck51bGwoZGF0YVtDb2x1bW4ubXVuaWNpcGFsaXR5UGFydENvZGVdKSxcclxuICAgICAgbm9uRW1wdHlPck51bGwoZGF0YVtDb2x1bW4ucHJhZ3VlRGlzdHJpY3RDb2RlXSksXHJcbiAgICAgIGRhdGFbQ29sdW1uLnBvc3RhbENvZGVdLFxyXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi54Q29vcmRpbmF0ZV0pLFxyXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi55Q29vcmRpbmF0ZV0pLFxyXG4gICAgICBsYXRPck51bGwsXHJcbiAgICAgIGxvbk9yTnVsbCxcclxuICAgIF07XHJcbiAgfSk7XHJcblxyXG4gIC8vIGZpbmQgYWxyZWFkeSBleGlzdGluZyByb3dzXHJcbiAgY29uc3QgZXhpc3RpbmdSb3dzID0gYXdhaXQgcmF3UXVlcnkoXHJcbiAgICBgU0VMRUNUICogRlJPTSBhZGRyZXNzX3BvaW50IFdIRVJFIGlkIElOICgke2J1ZmZlclxyXG4gICAgICAubWFwKChkYXRhKSA9PiBkYXRhW0NvbHVtbi5hZG1Db2RlXSlcclxuICAgICAgLmpvaW4oXCIsXCIpfSlgXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgcXVlcmllcyA9IFtdO1xyXG4gIGZvciAoY29uc3Qgcm93IG9mIGV4aXN0aW5nUm93cykge1xyXG4gICAgY29uc3QgdG9JbnNlcnQgPSBwYXJhbXNbcm93LmlkXTtcclxuICAgIGNvbnN0IHZhbHVlcyA9IE9iamVjdC52YWx1ZXMocm93KTtcclxuICAgIGlmICghdG9JbnNlcnQuZXZlcnkoKHYsIGkpID0+IHZhbHVlc0VxdWFsKHYsIHZhbHVlc1tpXSkpKSB7XHJcbiAgICAgIC8vIHVwZGF0ZSB0aG9zZSB3aG9zZSB2YWx1ZXMgZGlmZmVyXHJcbiAgICAgIHF1ZXJpZXMucHVzaChcclxuICAgICAgICByYXdRdWVyeShcclxuICAgICAgICAgIGBVUERBVEUgYWRkcmVzc19wb2ludCBTRVQgJHtjb2x1bW5OYW1lc1xyXG4gICAgICAgICAgICAubWFwKChjKSA9PiBgJHtjfSA9ID9gKVxyXG4gICAgICAgICAgICAuam9pbihcIiwgXCIpfSBXSEVSRSBpZCA9ID9gLFxyXG4gICAgICAgICAgWy4uLnRvSW5zZXJ0LCByb3cuaWRdXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGwocXVlcmllcyk7XHJcblxyXG4gIGNvbnN0IHBsYWNlSG9sZGVycyA9IGdlbmVyYXRlMkRQbGFjZWhvbGRlcnMoXHJcbiAgICBjb2x1bW5OYW1lcy5sZW5ndGgsXHJcbiAgICBidWZmZXIubGVuZ3RoXHJcbiAgKTtcclxuXHJcbiAgY29uc3Qga25leCA9IGdldEtuZXhEYigpO1xyXG4gIGF3YWl0IHJhd1F1ZXJ5KFxyXG4gICAgYElOU0VSVCAke1xyXG4gICAgICBpc015c3FsKGtuZXgpID8gXCJJR05PUkVcIiA6IFwiXCJcclxuICAgIH0gSU5UTyBhZGRyZXNzX3BvaW50ICgke2NvbHVtbk5hbWVzLmpvaW4oXCIsXCIpfSkgVkFMVUVTICR7cGxhY2VIb2xkZXJzfSAke1xyXG4gICAgICAhaXNNeXNxbChrbmV4KSA/IFwiT04gQ09ORkxJQ1QgKGlkKSBETyBOT1RISU5HXCIgOiBcIlwiXHJcbiAgICB9YCxcclxuICAgIE9iamVjdC52YWx1ZXMocGFyYW1zKS5mbGF0KClcclxuICApO1xyXG5cclxuICByZXR1cm4gYnVmZmVyLmxlbmd0aDtcclxufTtcclxuXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZW1vdmVEZXByZWNhdGVkQWRkcmVzc1BvaW50cyhcclxuICBhbGxJZHM6IFNldDxudW1iZXI+XHJcbik6IFByb21pc2U8dm9pZD4ge1xyXG4gIGNvbnN0IGtuZXggPSBnZXRLbmV4RGIoKTtcclxuICBjb25zdCBleGlzdGluZ0lkcyA9IGF3YWl0IGtuZXgucGx1Y2soXCJpZFwiKS5mcm9tKFwiYWRkcmVzc19wb2ludFwiKTtcclxuICBjb25zdCB0b1JlbW92ZSA9IGV4aXN0aW5nSWRzLmZpbHRlcigoaWQpID0+ICFhbGxJZHMuaGFzKGlkKSk7XHJcbiAgY29uc3QgY2h1bmtzID0gY2h1bmsodG9SZW1vdmUsIDEwMDApO1xyXG4gIGZvciAoY29uc3QgY2h1bmsgb2YgY2h1bmtzKSB7XHJcbiAgICBhd2FpdCBrbmV4KFwiYWRkcmVzc19wb2ludFwiKS53aGVyZUluKFwiaWRcIiwgY2h1bmspLmRlbGV0ZSgpO1xyXG4gIH1cclxuICBjb25zb2xlLmxvZyhgUmVtb3ZlZCAke3RvUmVtb3ZlLmxlbmd0aH0gZGVwcmVjYXRlZCBhZGRyZXNzIHBvaW50cy5gKTtcclxufVxyXG5cclxuZnVuY3Rpb24gdmFsdWVzRXF1YWwoYTogYW55LCBiOiBhbnkpOiBib29sZWFuIHtcclxuICByZXR1cm4gc2FuaXRpemVWYWx1ZShhKSA9PT0gc2FuaXRpemVWYWx1ZShiKTtcclxufVxyXG5cclxuZnVuY3Rpb24gc2FuaXRpemVWYWx1ZSh2YWx1ZTogYW55KTogYW55IHtcclxuICBpZiAodmFsdWUgPT09IG51bGwpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuICB2YWx1ZSA9IHZhbHVlLnRvU3RyaW5nKCk7XHJcblxyXG4gIGlmICgvXFxkK1xcLlxcZCsvLnRlc3QodmFsdWUpKSB7XHJcbiAgICByZXR1cm4gcm91bmRUb05EZWNpbWFsUGxhY2VzKHBhcnNlRmxvYXQodmFsdWUpLCA2KS50b1N0cmluZygpO1xyXG4gIH1cclxuICByZXR1cm4gdmFsdWU7XHJcbn1cclxuXHJcbmV4cG9ydCBjb25zdCBpbnNlcnRDaXRpZXMgPSBhc3luYyAoYnVmZmVyOiBzdHJpbmdbXVtdKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcclxuICByZXR1cm4gYXdhaXQgaW5zZXJ0TXVsdGlwbGVSb3dzKFxyXG4gICAgZXh0cmFjdEtleVZhbHVlc1BhaXJzKGJ1ZmZlciwgQ29sdW1uLmNpdHlDb2RlLCBbQ29sdW1uLmNpdHlOYW1lXSksXHJcbiAgICBcImNpdHlcIixcclxuICAgIFtcImNvZGVcIiwgXCJuYW1lXCJdXHJcbiAgKTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBpbnNlcnREaXN0cmljdHMgPSBhc3luYyAoYnVmZmVyOiBzdHJpbmdbXVtdKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcclxuICByZXR1cm4gYXdhaXQgaW5zZXJ0TXVsdGlwbGVSb3dzKFxyXG4gICAgZXh0cmFjdEtleVZhbHVlc1BhaXJzKGJ1ZmZlciwgQ29sdW1uLmRpc3RyaWN0Q29kZSwgW1xyXG4gICAgICBDb2x1bW4uY2l0eUNvZGUsXHJcbiAgICAgIENvbHVtbi5kaXN0cmljdE5hbWUsXHJcbiAgICBdKSxcclxuICAgIFwiY2l0eV9kaXN0cmljdFwiLFxyXG4gICAgW1wiY29kZVwiLCBcImNpdHlfY29kZVwiLCBcIm5hbWVcIl1cclxuICApO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGluc2VydE11bmljaXBhbGl0eVBhcnRzID0gYXN5bmMgKFxyXG4gIGJ1ZmZlcjogc3RyaW5nW11bXVxyXG4pOiBQcm9taXNlPG51bWJlcj4gPT4ge1xyXG4gIHJldHVybiBhd2FpdCBpbnNlcnRNdWx0aXBsZVJvd3MoXHJcbiAgICBleHRyYWN0S2V5VmFsdWVzUGFpcnMoYnVmZmVyLCBDb2x1bW4ubXVuaWNpcGFsaXR5UGFydENvZGUsIFtcclxuICAgICAgQ29sdW1uLm11bmljaXBhbGl0eVBhcnROYW1lLFxyXG4gICAgICBDb2x1bW4uY2l0eUNvZGUsXHJcbiAgICBdKSxcclxuICAgIFwibXVuaWNpcGFsaXR5X3BhcnRcIixcclxuICAgIFtcImNvZGVcIiwgXCJuYW1lXCIsIFwiY2l0eV9jb2RlXCJdXHJcbiAgKTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBpbnNlcnRQcmFndWVEaXN0cmljdHMgPSBhc3luYyAoXHJcbiAgYnVmZmVyOiBzdHJpbmdbXVtdXHJcbik6IFByb21pc2U8bnVtYmVyPiA9PiB7XHJcbiAgcmV0dXJuIGF3YWl0IGluc2VydE11bHRpcGxlUm93cyhcclxuICAgIGV4dHJhY3RLZXlWYWx1ZXNQYWlycyhidWZmZXIsIENvbHVtbi5wcmFndWVEaXN0cmljdENvZGUsIFtcclxuICAgICAgQ29sdW1uLnByYWd1ZURpc3RyaWN0TmFtZSxcclxuICAgIF0pLFxyXG4gICAgXCJwcmFndWVfZGlzdHJpY3RcIixcclxuICAgIFtcImNvZGVcIiwgXCJuYW1lXCJdXHJcbiAgKTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBpbnNlcnRTdHJlZXRzID0gYXN5bmMgKGJ1ZmZlcjogc3RyaW5nW11bXSk6IFByb21pc2U8bnVtYmVyPiA9PiB7XHJcbiAgcmV0dXJuIGF3YWl0IGluc2VydE11bHRpcGxlUm93cyhcclxuICAgIGV4dHJhY3RLZXlWYWx1ZXNQYWlycyhidWZmZXIsIENvbHVtbi5zdHJlZXRDb2RlLCBbXHJcbiAgICAgIENvbHVtbi5jaXR5Q29kZSxcclxuICAgICAgQ29sdW1uLnN0cmVldE5hbWUsXHJcbiAgICBdKSxcclxuICAgIFwic3RyZWV0XCIsXHJcbiAgICBbXCJjb2RlXCIsIFwiY2l0eV9jb2RlXCIsIFwibmFtZVwiXVxyXG4gICk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgYXJlQWRkcmVzc1BvaW50c1N5bmNlZCA9IGFzeW5jICgpOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcclxuICBjb25zdCByZXN1bHQgPSBhd2FpdCBnZXRLbmV4RGIoKVxyXG4gICAgLmNvdW50KFwiKlwiLCB7IGFzOiBcImNvdW50QWxsXCIgfSlcclxuICAgIC5mcm9tKFwiYWRkcmVzc19wb2ludFwiKVxyXG4gICAgLmZpcnN0KCk7XHJcbiAgcmV0dXJuIE51bWJlcihyZXN1bHQuY291bnRBbGwpID49IDI5MDAwMDA7IC8vIHRvdGFsIGlzIGFsbW9zdCAzIG1pbGxpb25cclxufTtcclxuXHJcbmNvbnN0IGFkZHJlc3NQb2ludFNlbGVjdCA9IGBcclxuICBTRUxFQ1QgYS5pZCwgcy5uYW1lIEFTIHN0cmVldF9uYW1lLCBvLm5hbWUgQVMgb2JqZWN0X3R5cGVfbmFtZSwgYS5kZXNjcmlwdGl2ZV9udW1iZXIsXHJcbiAgICAgICAgYS5vcmllbnRhdGlvbmFsX251bWJlciwgYS5vcmllbnRhdGlvbmFsX251bWJlcl9sZXR0ZXIsIGMubmFtZSBBUyBjaXR5X25hbWUsXHJcbiAgICAgICAgbS5uYW1lIEFTIG11bmljaXBhbGl0eV9wYXJ0X25hbWUsIHAubmFtZSBBUyBwcmFndWVfZGlzdHJpY3RfbmFtZSxcclxuICAgICAgICBkLm5hbWUgQVMgZGlzdHJpY3RfbmFtZSwgYS5wb3N0YWxfY29kZSwgYS53Z3M4NF9sYXRpdHVkZSwgYS53Z3M4NF9sb25naXR1ZGVcclxuICBGUk9NIGFkZHJlc3NfcG9pbnQgYVxyXG4gIExFRlQgSk9JTiBzdHJlZXQgcyBPTiBhLnN0cmVldF9jb2RlID0gcy5jb2RlXHJcbiAgSU5ORVIgSk9JTiBvYmplY3RfdHlwZSBvIE9OIG8uaWQgPSBhLm9iamVjdF90eXBlX2lkXHJcbiAgSU5ORVIgSk9JTiBjaXR5IGMgT04gYy5jb2RlID0gYS5jaXR5X2NvZGVcclxuICBMRUZUIEpPSU4gY2l0eV9kaXN0cmljdCBkIE9OIGEuY2l0eV9kaXN0cmljdF9jb2RlID0gZC5jb2RlXHJcbiAgTEVGVCBKT0lOIHByYWd1ZV9kaXN0cmljdCBwIE9OIGEucHJhZ3VlX2Rpc3RyaWN0X2NvZGUgPSBwLmNvZGVcclxuICBMRUZUIEpPSU4gbXVuaWNpcGFsaXR5X3BhcnQgbSBPTiBhLm11bmljaXBhbGl0eV9wYXJ0X2NvZGUgPSBtLmNvZGVgO1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldEFkZHJlc3NQb2ludEJ5SWQgPSBhc3luYyAoXHJcbiAgYWRkcmVzc1BvaW50SWQ6IG51bWJlclxyXG4pOiBQcm9taXNlPEFkZHJlc3NQb2ludCB8IG51bGw+ID0+IHtcclxuICBjb25zdCByb3cgPSBhd2FpdCByYXdRdWVyeShcclxuICAgIGAke2FkZHJlc3NQb2ludFNlbGVjdH1cclxuICAgICAgV0hFUkUgYS5pZCA9ID9gLFxyXG4gICAgW2FkZHJlc3NQb2ludElkXVxyXG4gICk7XHJcbiAgaWYgKHJvdy5sZW5ndGggPT09IDApIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuICByZXR1cm4gcm93VG9BZGRyZXNzUG9pbnQocm93WzBdKTtcclxufTtcclxuXHJcbmxldCBsYXN0Rm91bmRlcjogRm91bmRlciB8IG51bGwgPSBudWxsO1xyXG5sZXQgYWxsU3RyZWV0czogc3RyaW5nW10gPSBbXTtcclxuXHJcbmV4cG9ydCBjb25zdCBjaGVja1N0cmVldEV4aXN0cyA9IGFzeW5jIChcclxuICBzdHJlZXROYW1lOiBzdHJpbmcsXHJcbiAgZm91bmRlcjogRm91bmRlclxyXG4pOiBQcm9taXNlPHsgZXhpc3RzOiBib29sZWFuOyBlcnJvcnM6IFNtZEVycm9yW10gfT4gPT4ge1xyXG4gIGNvbnN0IGtuZXggPSBnZXRLbmV4RGIoKTtcclxuICBjb25zdCBlcnJvcnM6IFNtZEVycm9yW10gPSBbXTtcclxuXHJcbiAgLy8gd2UgY2hlY2sgdGhlIHdob2xlIGNpdHlcclxuICBjb25zdCBjaXR5Q29kZSA9IGF3YWl0IGdldEZvdW5kZXJDaXR5Q29kZShcclxuICAgIGZvdW5kZXIubXVuaWNpcGFsaXR5VHlwZSxcclxuICAgIGZvdW5kZXIubXVuaWNpcGFsaXR5Q29kZVxyXG4gICk7XHJcbiAgY29uc3Qgcm93TGlzdCA9IGF3YWl0IHJhd1F1ZXJ5KFxyXG4gICAgYFNFTEVDVCBuYW1lIEFTIHN0cmVldF9uYW1lXHJcbiAgICBGUk9NIHN0cmVldFxyXG4gICAgV0hFUkUgY2l0eV9jb2RlID0gPyBBTkQgbmFtZSA9ID8gICR7XHJcbiAgICAgIGlzU3FsaXRlKGtuZXgpID8gXCJDT0xMQVRFIE5PQ0FTRVwiIDogXCJcIlxyXG4gICAgfWAsXHJcbiAgICBbY2l0eUNvZGUsIHN0cmVldE5hbWVdXHJcbiAgKTtcclxuXHJcbiAgaWYgKHJvd0xpc3QubGVuZ3RoID4gMCkge1xyXG4gICAgY29uc3Qgcm93ID0gcm93TGlzdFswXTtcclxuICAgIGlmIChyb3cuc3RyZWV0X25hbWUgIT09IHN0cmVldE5hbWUpIHtcclxuICAgICAgLy8gZXJyb3JzLnB1c2goXHJcbiAgICAgIC8vICAgYFN0cmVldCAnJHtzdHJlZXROYW1lfScgaGFzIHdyb25nIGNhc2UsIGNvcnJlY3QgY2FzZTogJyR7cm93LnN0cmVldF9uYW1lfScuYFxyXG4gICAgICAvLyApO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHsgZXhpc3RzOiB0cnVlLCBlcnJvcnMgfTtcclxuICB9XHJcblxyXG4gIGlmIChsYXN0Rm91bmRlciAhPT0gZm91bmRlcikge1xyXG4gICAgYWxsU3RyZWV0cyA9IGF3YWl0IGdldEFsbFN0cmVldHMoY2l0eUNvZGUpO1xyXG4gICAgbGFzdEZvdW5kZXIgPSBmb3VuZGVyO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgbWF0Y2ggPSBhbGxTdHJlZXRzLmZpbmQoXHJcbiAgICAocykgPT5cclxuICAgICAgcy50b0xvY2FsZUxvd2VyQ2FzZShcImNzLUNaXCIpID09PSBzdHJlZXROYW1lLnRvTG9jYWxlTG93ZXJDYXNlKFwiY3MtQ1pcIilcclxuICApO1xyXG4gIGxldCBleGlzdHMgPSBmYWxzZTtcclxuICBpZiAobWF0Y2gpIHtcclxuICAgIGV4aXN0cyA9IHRydWU7XHJcbiAgICBpZiAoc3RyZWV0TmFtZSAhPT0gbWF0Y2gpIHtcclxuICAgICAgLy8gZXJyb3JzLnB1c2goXHJcbiAgICAgIC8vICAgYFN0cmVldCAnJHtzdHJlZXROYW1lfScgaGFzIHdyb25nIGNhc2UsIGNvcnJlY3QgY2FzZTogJyR7bWF0Y2h9Jy5gXHJcbiAgICAgIC8vICk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIGNvbnN0IGNsb3Nlc3QgPSBmaW5kQ2xvc2VzdFN0cmluZyhzdHJlZXROYW1lLCBhbGxTdHJlZXRzKTtcclxuICAgIGVycm9ycy5wdXNoKHtcclxuICAgICAgbWVzc2FnZTogYFVsaWNlICcke3N0cmVldE5hbWV9JyB2IHTDqXRvIG9iY2kgbmVleGlzdHVqZSwgbXlzbGVsaSBqc3RlICcke2Nsb3Nlc3R9Jz9gLFxyXG4gICAgICBzdGFydE9mZnNldDogMCxcclxuICAgICAgZW5kT2Zmc2V0OiBzdHJlZXROYW1lLmxlbmd0aCArIDEsXHJcbiAgICB9KTtcclxuICB9XHJcbiAgcmV0dXJuIHsgZXhpc3RzOiBmYWxzZSwgZXJyb3JzIH07XHJcbn07XHJcblxyXG5jb25zdCBnZXRBbGxTdHJlZXRzID0gYXN5bmMgKGNpdHlDb2RlOiBudW1iZXIpOiBQcm9taXNlPHN0cmluZ1tdPiA9PiB7XHJcbiAgY29uc3Qga25leCA9IGdldEtuZXhEYigpO1xyXG4gIHJldHVybiBhd2FpdCBrbmV4LnBsdWNrKFwibmFtZVwiKS5mcm9tKFwic3RyZWV0XCIpLndoZXJlKFwiY2l0eV9jb2RlXCIsIGNpdHlDb2RlKTtcclxufTtcclxuXHJcbmV4cG9ydCB0eXBlIEZpbmRBZGRyZXNzUG9pbnRzUGFyYW1zID1cclxuICB8IHtcclxuICAgICAgdHlwZTogXCJzbWRMaW5lXCI7XHJcbiAgICAgIHNtZExpbmU6IFNtZExpbmU7XHJcbiAgICAgIG11bmljaXBhbGl0eTogTXVuaWNpcGFsaXR5O1xyXG4gICAgICBtdW5pY2lwYWxpdHlQYXJ0Q29kZT86IG51bWJlcjtcclxuICAgIH1cclxuICB8IHtcclxuICAgICAgdHlwZTogXCJ3aG9sZU11bmljaXBhbGl0eVBhcnRcIjtcclxuICAgICAgbXVuaWNpcGFsaXR5UGFydENvZGU6IG51bWJlcjtcclxuICAgIH1cclxuICB8IHtcclxuICAgICAgdHlwZTogXCJ3aG9sZU11bmljaXBhbGl0eVwiO1xyXG4gICAgICBtdW5pY2lwYWxpdHk6IE11bmljaXBhbGl0eTtcclxuICAgIH1cclxuICB8IHtcclxuICAgICAgdHlwZTogXCJ3aG9sZU11bmljaXBhbGl0eU5vU3RyZWV0TmFtZVwiO1xyXG4gICAgICBtdW5pY2lwYWxpdHk6IE11bmljaXBhbGl0eTtcclxuICAgIH07XHJcblxyXG5leHBvcnQgY29uc3QgZmluZEFkZHJlc3NQb2ludHMgPSBhc3luYyAoXHJcbiAgcGFyYW1zOiBGaW5kQWRkcmVzc1BvaW50c1BhcmFtc1xyXG4pOiBQcm9taXNlPEFkZHJlc3NQb2ludFtdPiA9PiB7XHJcbiAgY29uc3QgcXVlcnlQYXJhbXMgPSBnZXRRdWVyeVBhcmFtcyhwYXJhbXMpO1xyXG4gIGNvbnN0IHN0cmVldEpvaW5Db25kaXRpb24gPSBnZXRTdHJlZXRKb2luQ29uZGl0aW9uKHBhcmFtcyk7XHJcblxyXG4gIGNvbnN0IHdoZXJlQ29uZGl0aW9uID0gZ2V0V2hlcmVDb25kaXRpb24ocGFyYW1zKTtcclxuXHJcbiAgY29uc3QgcXVlcnlSZXN1bHQgPSBhd2FpdCByYXdRdWVyeShcclxuICAgIGBTRUxFQ1QgYS5pZCwgcy5uYW1lIEFTIHN0cmVldF9uYW1lLCBvLm5hbWUgQVMgb2JqZWN0X3R5cGVfbmFtZSwgYS5kZXNjcmlwdGl2ZV9udW1iZXIsXHJcbiAgICAgIGEub3JpZW50YXRpb25hbF9udW1iZXIsIGEub3JpZW50YXRpb25hbF9udW1iZXJfbGV0dGVyLCBjLm5hbWUgQVMgY2l0eV9uYW1lLFxyXG4gICAgICBkLm5hbWUgQVMgZGlzdHJpY3RfbmFtZSwgbS5uYW1lIEFTIG11bmljaXBhbGl0eV9wYXJ0X25hbWUsIHAubmFtZSBBUyBwcmFndWVfZGlzdHJpY3RfbmFtZSxcclxuICAgICAgYS5wb3N0YWxfY29kZSwgYS53Z3M4NF9sYXRpdHVkZSwgYS53Z3M4NF9sb25naXR1ZGVcclxuICAgIEZST00gYWRkcmVzc19wb2ludCBhXHJcbiAgICAke3N0cmVldEpvaW5Db25kaXRpb259XHJcbiAgICBJTk5FUiBKT0lOIG9iamVjdF90eXBlIG8gT04gby5pZCA9IGEub2JqZWN0X3R5cGVfaWRcclxuICAgIElOTkVSIEpPSU4gY2l0eSBjIE9OIGMuY29kZSA9IGEuY2l0eV9jb2RlXHJcbiAgICBMRUZUIEpPSU4gY2l0eV9kaXN0cmljdCBkIE9OIGEuY2l0eV9kaXN0cmljdF9jb2RlID0gZC5jb2RlXHJcbiAgICBMRUZUIEpPSU4gbXVuaWNpcGFsaXR5X3BhcnQgbSBPTiBhLm11bmljaXBhbGl0eV9wYXJ0X2NvZGUgPSBtLmNvZGVcclxuICAgIExFRlQgSk9JTiBwcmFndWVfZGlzdHJpY3QgcCBPTiBhLnByYWd1ZV9kaXN0cmljdF9jb2RlID0gcC5jb2RlXHJcbiAgICBXSEVSRSAke3doZXJlQ29uZGl0aW9ufWAsXHJcbiAgICBxdWVyeVBhcmFtc1xyXG4gICk7XHJcblxyXG4gIHJldHVybiBmaWx0ZXJBZGRyZXNzUG9pbnRzKHF1ZXJ5UmVzdWx0Lm1hcChyb3dUb0FkZHJlc3NQb2ludCksIHBhcmFtcyk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZmlsdGVyQWRkcmVzc1BvaW50cyA9IChcclxuICBhZGRyZXNzUG9pbnRzOiBBZGRyZXNzUG9pbnRbXSxcclxuICBwYXJhbXM6IEZpbmRBZGRyZXNzUG9pbnRzUGFyYW1zXHJcbik6IEFkZHJlc3NQb2ludFtdID0+IHtcclxuICBpZiAoXHJcbiAgICBwYXJhbXMudHlwZSA9PT0gXCJ3aG9sZU11bmljaXBhbGl0eVwiIHx8XHJcbiAgICBwYXJhbXMudHlwZSA9PT0gXCJ3aG9sZU11bmljaXBhbGl0eU5vU3RyZWV0TmFtZVwiIHx8XHJcbiAgICBwYXJhbXMudHlwZSA9PT0gXCJ3aG9sZU11bmljaXBhbGl0eVBhcnRcIlxyXG4gICkge1xyXG4gICAgcmV0dXJuIGFkZHJlc3NQb2ludHM7XHJcbiAgfVxyXG5cclxuICBjb25zdCByZXN1bHQ6IEFkZHJlc3NQb2ludFtdID0gW107XHJcbiAgY29uc3QgbnVtYmVyU3BlYyA9IHBhcmFtcy5zbWRMaW5lLm51bWJlclNwZWM7XHJcbiAgaWYgKGlzU2VyaWVzU3BlY0FycmF5KG51bWJlclNwZWMpKSB7XHJcbiAgICBudW1iZXJTcGVjLmZvckVhY2goKHNlcmllc1NwZWMpID0+IHtcclxuICAgICAgcmVzdWx0LnB1c2goLi4uZmlsdGVyQWRkcmVzc1BvaW50c0J5UmFuZ2VzKGFkZHJlc3NQb2ludHMsIHNlcmllc1NwZWMpKTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIHdoZW4gbm8gbnVtYmVyIHNwZWNzIGFyZSBwcmVzZW50LCB3ZSB0YWtlIGV2ZXJ5dGhpbmdcclxuICAgIGlmIChudW1iZXJTcGVjLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICByZXN1bHQucHVzaCguLi5hZGRyZXNzUG9pbnRzKTtcclxuICAgIH1cclxuICB9IGVsc2UgaWYgKGlzTmVnYXRpdmVTZXJpZXNTcGVjKG51bWJlclNwZWMpKSB7XHJcbiAgICAvLyBuZWdhdGl2ZSBudW1iZXIgc3BlYyAoZS5nLiBvZGQgbnVtYmVycyBleGNlcHQgMTMtMTcpXHJcbiAgICBjb25zdCB0b0V4Y2x1ZGUgPSBmaWx0ZXJBZGRyZXNzUG9pbnRzQnlSYW5nZXMoYWRkcmVzc1BvaW50cywgbnVtYmVyU3BlYyk7XHJcbiAgICByZXN1bHQucHVzaChcclxuICAgICAgLi4uYWRkcmVzc1BvaW50cy5maWx0ZXIoXHJcbiAgICAgICAgKGFkZHJlc3NQb2ludCkgPT4gIXRvRXhjbHVkZS5pbmNsdWRlcyhhZGRyZXNzUG9pbnQpXHJcbiAgICAgIClcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuY29uc3QgZmlsdGVyQWRkcmVzc1BvaW50c0J5UmFuZ2VzID0gKFxyXG4gIGFkZHJlc3NQb2ludHM6IEFkZHJlc3NQb2ludFtdLFxyXG4gIHNlcmllc1NwZWM6IFNlcmllc1NwZWNcclxuKTogQWRkcmVzc1BvaW50W10gPT4ge1xyXG4gIGNvbnN0IHJlc3VsdDogQWRkcmVzc1BvaW50W10gPSBbXTtcclxuICBzZXJpZXNTcGVjLnJhbmdlcy5mb3JFYWNoKChyYW5nZSkgPT4ge1xyXG4gICAgcmVzdWx0LnB1c2goXHJcbiAgICAgIC4uLmFkZHJlc3NQb2ludHMuZmlsdGVyKChhZGRyZXNzUG9pbnQpID0+IHtcclxuICAgICAgICBpZiAoaXNSYW5nZShyYW5nZSkpIHtcclxuICAgICAgICAgIGNvbnN0IG51bWJlciA9IGdldE51bWJlckJ5VHlwZShzZXJpZXNTcGVjLnR5cGUsIGFkZHJlc3NQb2ludCk7XHJcbiAgICAgICAgICByZXR1cm4gKFxyXG4gICAgICAgICAgICBpc0luUmFuZ2UoXHJcbiAgICAgICAgICAgICAgbnVtYmVyLFxyXG4gICAgICAgICAgICAgIHNlcmllc1NwZWMudHlwZSAhPT0gU2VyaWVzVHlwZS5EZXNjcmlwdGlvblxyXG4gICAgICAgICAgICAgICAgPyBhZGRyZXNzUG9pbnQub3JpZW50YXRpb25hbE51bWJlckxldHRlciA/PyBudWxsXHJcbiAgICAgICAgICAgICAgICA6IG51bGwsXHJcbiAgICAgICAgICAgICAgcmFuZ2VcclxuICAgICAgICAgICAgKSAmJiBmaXRzVHlwZShudW1iZXIsIHNlcmllc1NwZWMudHlwZSlcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnN0IGZ1bGxTdHJlZXROdW1iZXI6IEZ1bGxTdHJlZXROdW1iZXIgPSByYW5nZTtcclxuICAgICAgICAgIHJldHVybiBlcXVhbHNGdWxsU3RyZWV0TnVtYmVyKGZ1bGxTdHJlZXROdW1iZXIsIGFkZHJlc3NQb2ludCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuICB9KTtcclxuXHJcbiAgLy8gd2hlbiBubyBzZXJpZXMgc3BlY3MgYXJlIHByZXNlbnQsIHdlIHRha2UgZXZlcnl0aGluZyB0aGF0IGZpdHMgdGhlIHR5cGVcclxuICBpZiAoc2VyaWVzU3BlYy5yYW5nZXMubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXN1bHQucHVzaChcclxuICAgICAgLi4uYWRkcmVzc1BvaW50cy5maWx0ZXIoKGFkZHJlc3NQb2ludCkgPT5cclxuICAgICAgICBmaXRzVHlwZShcclxuICAgICAgICAgIGdldE51bWJlckJ5VHlwZShzZXJpZXNTcGVjLnR5cGUsIGFkZHJlc3NQb2ludCksXHJcbiAgICAgICAgICBzZXJpZXNTcGVjLnR5cGVcclxuICAgICAgICApXHJcbiAgICAgIClcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldFF1ZXJ5UGFyYW1zID0gKFxyXG4gIHBhcmFtczogRmluZEFkZHJlc3NQb2ludHNQYXJhbXNcclxuKTogKHN0cmluZyB8IG51bWJlcilbXSA9PiB7XHJcbiAgaWYgKHBhcmFtcy50eXBlID09PSBcInNtZExpbmVcIiAmJiBwYXJhbXMuc21kTGluZS50eXBlID09PSBcInN0cmVldFwiKSB7XHJcbiAgICByZXR1cm4gW3BhcmFtcy5zbWRMaW5lLnN0cmVldCwgcGFyYW1zLm11bmljaXBhbGl0eS5jb2RlXTtcclxuICB9XHJcblxyXG4gIGlmIChcclxuICAgIChwYXJhbXMudHlwZSA9PT0gXCJzbWRMaW5lXCIgJiYgcGFyYW1zLnNtZExpbmUudHlwZSA9PT0gXCJtdW5pY2lwYWxpdHlQYXJ0XCIpIHx8XHJcbiAgICBwYXJhbXMudHlwZSA9PT0gXCJ3aG9sZU11bmljaXBhbGl0eVBhcnRcIlxyXG4gICkge1xyXG4gICAgcmV0dXJuIFtwYXJhbXMubXVuaWNpcGFsaXR5UGFydENvZGVdO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIFtwYXJhbXMubXVuaWNpcGFsaXR5LmNvZGVdO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGdldFN0cmVldEpvaW5Db25kaXRpb24gPSAoXHJcbiAgcGFyYW1zOiBGaW5kQWRkcmVzc1BvaW50c1BhcmFtc1xyXG4pOiBzdHJpbmcgPT4ge1xyXG4gIGlmIChwYXJhbXMudHlwZSA9PT0gXCJzbWRMaW5lXCIgJiYgcGFyYW1zLnNtZExpbmUudHlwZSA9PT0gXCJzdHJlZXRcIikge1xyXG4gICAgcmV0dXJuIGBKT0lOIHN0cmVldCBzIE9OIGEuc3RyZWV0X2NvZGUgPSBzLmNvZGUgQU5EIHMubmFtZSA9ID8gJHtcclxuICAgICAgaXNTcWxpdGUoZ2V0S25leERiKCkpID8gXCJDT0xMQVRFIE5PQ0FTRVwiIDogXCJcIlxyXG4gICAgfWA7XHJcbiAgfVxyXG4gIHJldHVybiBcIkxFRlQgSk9JTiBzdHJlZXQgcyBPTiBhLnN0cmVldF9jb2RlID0gcy5jb2RlXCI7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0V2hlcmVDb25kaXRpb24gPSAocGFyYW1zOiBGaW5kQWRkcmVzc1BvaW50c1BhcmFtcyk6IHN0cmluZyA9PiB7XHJcbiAgaWYgKFxyXG4gICAgKHBhcmFtcy50eXBlID09PSBcInNtZExpbmVcIiAmJiBwYXJhbXMuc21kTGluZS50eXBlID09PSBcIm11bmljaXBhbGl0eVBhcnRcIikgfHxcclxuICAgIHBhcmFtcy50eXBlID09PSBcIndob2xlTXVuaWNpcGFsaXR5UGFydFwiXHJcbiAgKSB7XHJcbiAgICByZXR1cm4gXCJhLm11bmljaXBhbGl0eV9wYXJ0X2NvZGUgPSA/XCI7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyYW1zLnR5cGUgPT09IFwid2hvbGVNdW5pY2lwYWxpdHlOb1N0cmVldE5hbWVcIikge1xyXG4gICAgcmV0dXJuIGAke2dldE11bmljaXBhbGl0eVdoZXJlKFxyXG4gICAgICBcImFcIixcclxuICAgICAgcGFyYW1zLm11bmljaXBhbGl0eVxyXG4gICAgKX0gQU5EIGEuc3RyZWV0X2NvZGUgSVMgTlVMTGA7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gZ2V0TXVuaWNpcGFsaXR5V2hlcmUoXCJhXCIsIHBhcmFtcy5tdW5pY2lwYWxpdHkpO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGlzSW5SYW5nZSA9IChcclxuICBudW1iZXI6IG51bWJlciB8IG51bGwsXHJcbiAgbGV0dGVyOiBzdHJpbmcgfCBudWxsLFxyXG4gIHJhbmdlOiBSYW5nZVNwZWNcclxuKTogYm9vbGVhbiA9PiB7XHJcbiAgaWYgKG51bWJlciA9PT0gbnVsbCkge1xyXG4gICAgcmV0dXJuICFyYW5nZS5mcm9tICYmICFyYW5nZS50bztcclxuICB9XHJcblxyXG4gIC8vIGV4cGxhaW5lcjogZWl0aGVyIHRoZSBsb3dlciBib3VuZCBpcyBub3Qgc2V0LCBvciBpdCBpcyBsb3dlciB0aGFuIHRoZSBudW1iZXJcclxuICAvLyBpZiBpdCdzIGVxdWFsIHRvIHRoZSBudW1iZXIsIHdlIGFsc28gaGF2ZSB0byBjaGVjayB0aGUgbGV0dGVyIC0gaWYgaXQncyBub3Qgc2V0LCB3ZSBkb24ndCBjYXJlXHJcbiAgLy8gaWYgZnJvbS5sZXR0ZXIgaXMgc2V0LCB3ZSBuZWVkIHRvIGhhdmUgYSBsZXR0ZXIgc2V0IGFuZCBpdCBoYXMgdG8gYmUgZ3JlYXRlciBvciBlcXVhbDpcclxuICAvLyBudW1iZXIgd2l0aG91dCBsZXR0ZXIgY291bnRzIGxvd2VyIHRoYW4gbnVtYmVyIHdpdGggbGV0dGVyICdhJyAoZS5nLiAyMyA8IDIzYSlcclxuICBjb25zdCBzYXRpc2ZpZXNGcm9tID1cclxuICAgICFyYW5nZS5mcm9tIHx8XHJcbiAgICBudW1iZXIgPiByYW5nZS5mcm9tLm51bWJlciB8fFxyXG4gICAgKG51bWJlciA9PT0gcmFuZ2UuZnJvbS5udW1iZXIgJiZcclxuICAgICAgKCFyYW5nZS5mcm9tLmxldHRlciB8fCAoISFsZXR0ZXIgJiYgbGV0dGVyID49IHJhbmdlLmZyb20ubGV0dGVyKSkpO1xyXG5cclxuICBjb25zdCBzYXRpc2ZpZXNUbyA9XHJcbiAgICAhcmFuZ2UudG8gfHxcclxuICAgIG51bWJlciA8IHJhbmdlLnRvLm51bWJlciB8fFxyXG4gICAgKG51bWJlciA9PT0gcmFuZ2UudG8ubnVtYmVyICYmXHJcbiAgICAgICghbGV0dGVyIHx8XHJcbiAgICAgICAgKCEhcmFuZ2UudG8ubGV0dGVyICYmICEhbGV0dGVyICYmIGxldHRlciA8PSByYW5nZS50by5sZXR0ZXIpKSk7XHJcblxyXG4gIHJldHVybiBzYXRpc2ZpZXNGcm9tICYmIHNhdGlzZmllc1RvO1xyXG59O1xyXG5cclxuZXhwb3J0IGNvbnN0IGZpdHNUeXBlID0gKG51bWJlcjogbnVtYmVyIHwgbnVsbCwgdHlwZTogU2VyaWVzVHlwZSk6IGJvb2xlYW4gPT4ge1xyXG4gIHJldHVybiAoXHJcbiAgICB0eXBlID09PSBTZXJpZXNUeXBlLkRlc2NyaXB0aW9uIHx8XHJcbiAgICB0eXBlID09PSBTZXJpZXNUeXBlLkFsbCB8fFxyXG4gICAgKHR5cGUgPT09IFNlcmllc1R5cGUuT2RkICYmIG51bWJlciAlIDIgPT09IDEpIHx8XHJcbiAgICAodHlwZSA9PT0gU2VyaWVzVHlwZS5FdmVuICYmIG51bWJlciAlIDIgPT09IDApXHJcbiAgKTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBlcXVhbHNGdWxsU3RyZWV0TnVtYmVyID0gKFxyXG4gIGZ1bGxTdHJlZXROdW1iZXI6IEZ1bGxTdHJlZXROdW1iZXIsXHJcbiAgYWRkcmVzc1BvaW50OiBBZGRyZXNzUG9pbnRcclxuKTogYm9vbGVhbiA9PiB7XHJcbiAgcmV0dXJuIChcclxuICAgIGZ1bGxTdHJlZXROdW1iZXIuZGVzY3JpcHRpb25OdW1iZXIubnVtYmVyID09PSBhZGRyZXNzUG9pbnQuaG91c2VOdW1iZXIgJiZcclxuICAgIGZ1bGxTdHJlZXROdW1iZXIub3JpZW50YXRpb25hbE51bWJlci5udW1iZXIgPT09XHJcbiAgICAgIGFkZHJlc3NQb2ludC5vcmllbnRhdGlvbmFsTnVtYmVyICYmXHJcbiAgICAoKCFmdWxsU3RyZWV0TnVtYmVyLm9yaWVudGF0aW9uYWxOdW1iZXIubGV0dGVyICYmXHJcbiAgICAgICFhZGRyZXNzUG9pbnQub3JpZW50YXRpb25hbE51bWJlckxldHRlcikgfHxcclxuICAgICAgZnVsbFN0cmVldE51bWJlci5vcmllbnRhdGlvbmFsTnVtYmVyLmxldHRlciA9PT1cclxuICAgICAgICBhZGRyZXNzUG9pbnQub3JpZW50YXRpb25hbE51bWJlckxldHRlcilcclxuICApO1xyXG59O1xyXG5cclxuY29uc3QgZ2V0TnVtYmVyQnlUeXBlID0gKFxyXG4gIHR5cGU6IFNlcmllc1R5cGUsXHJcbiAgYWRkcmVzc1BvaW50OiBBZGRyZXNzUG9pbnRcclxuKTogbnVtYmVyIHwgbnVsbCA9PiB7XHJcbiAgcmV0dXJuIHR5cGUgPT09IFNlcmllc1R5cGUuRGVzY3JpcHRpb25cclxuICAgID8gYWRkcmVzc1BvaW50LmhvdXNlTnVtYmVyXHJcbiAgICA6IGFkZHJlc3NQb2ludC5vcmllbnRhdGlvbmFsTnVtYmVyID8/IG51bGw7XHJcbn07XHJcblxyXG5jb25zdCBnZXRNdW5pY2lwYWxpdHlXaGVyZSA9IChcclxuICBhbGlhczogc3RyaW5nLFxyXG4gIG11bmljaXBhbGl0eTogTXVuaWNpcGFsaXR5XHJcbik6IHN0cmluZyA9PiB7XHJcbiAgcmV0dXJuIG11bmljaXBhbGl0eS50eXBlID09PSBNdW5pY2lwYWxpdHlUeXBlLkNpdHlcclxuICAgID8gYCR7YWxpYXN9LmNpdHlfY29kZSA9ID9gXHJcbiAgICA6IGAke2FsaWFzfS5jaXR5X2Rpc3RyaWN0X2NvZGUgPSA/YDtcclxufTtcclxuXHJcbmNvbnN0IHJvd1RvQWRkcmVzc1BvaW50ID0gKHJvdzogYW55KTogQWRkcmVzc1BvaW50ID0+IHtcclxuICBjb25zdCBwb2ludDogQWRkcmVzc1BvaW50ID0ge1xyXG4gICAgaWQ6IHJvdy5pZCxcclxuICAgIGFkZHJlc3M6IFwiXCIsXHJcbiAgICB0eXBlOlxyXG4gICAgICByb3cub2JqZWN0X3R5cGVfbmFtZSA9PT0gRGVzY3JpcHRpdmVUeXBlXHJcbiAgICAgICAgPyBBZGRyZXNzUG9pbnRUeXBlLkRlc2NyaXB0aW9uXHJcbiAgICAgICAgOiBBZGRyZXNzUG9pbnRUeXBlLlJlZ2lzdHJhdGlvbixcclxuICAgIGhvdXNlTnVtYmVyOiByb3cuZGVzY3JpcHRpdmVfbnVtYmVyLFxyXG4gICAgY2l0eTogcm93LmNpdHlfbmFtZSxcclxuICAgIG11bmljaXBhbGl0eVBhcnQ6IHJvdy5tdW5pY2lwYWxpdHlfcGFydF9uYW1lLFxyXG4gICAgcG9zdGFsQ29kZTogcm93LnBvc3RhbF9jb2RlLFxyXG4gICAgbGF0OiByb3cud2dzODRfbGF0aXR1ZGUsXHJcbiAgICBsbmc6IHJvdy53Z3M4NF9sb25naXR1ZGUsXHJcbiAgfTtcclxuICBpZiAocm93LnN0cmVldF9uYW1lICE9PSBudWxsKSB7XHJcbiAgICBwb2ludC5zdHJlZXQgPSByb3cuc3RyZWV0X25hbWU7XHJcbiAgfVxyXG4gIGlmIChyb3cub3JpZW50YXRpb25hbF9udW1iZXIgIT09IG51bGwpIHtcclxuICAgIHBvaW50Lm9yaWVudGF0aW9uYWxOdW1iZXIgPSByb3cub3JpZW50YXRpb25hbF9udW1iZXI7XHJcbiAgfVxyXG4gIGlmIChyb3cub3JpZW50YXRpb25hbF9udW1iZXJfbGV0dGVyICE9PSBudWxsKSB7XHJcbiAgICBwb2ludC5vcmllbnRhdGlvbmFsTnVtYmVyTGV0dGVyID0gcm93Lm9yaWVudGF0aW9uYWxfbnVtYmVyX2xldHRlcjtcclxuICB9XHJcbiAgaWYgKHJvdy5kaXN0cmljdF9uYW1lICE9PSBudWxsKSB7XHJcbiAgICBwb2ludC5kaXN0cmljdCA9IHJvdy5kaXN0cmljdF9uYW1lO1xyXG4gIH1cclxuICBpZiAocm93LnByYWd1ZV9kaXN0cmljdF9uYW1lICE9PSBudWxsKSB7XHJcbiAgICBwb2ludC5wcmFndWVEaXN0cmljdCA9IHJvdy5wcmFndWVfZGlzdHJpY3RfbmFtZTtcclxuICB9XHJcbiAgcG9pbnQuYWRkcmVzcyA9IGNyZWF0ZVNpbmdsZUxpbmVBZGRyZXNzKHBvaW50KTtcclxuICByZXR1cm4gcG9pbnQ7XHJcbn07XHJcbiJdfQ==
|
|
1
|
+
import { AddressPointType, createSingleLineAddress } from "czech-address";
|
|
2
|
+
import { SeriesType, isNegativeSeriesSpec, isRange, isSeriesSpecArray, } from "../street-markdown/types";
|
|
3
|
+
import { findClosestString, roundToNDecimalPlaces } from "../utils/helpers";
|
|
4
|
+
import jtsk2wgs84 from "../utils/jtsk2wgs84";
|
|
5
|
+
import { extractKeyValuesPairs, generate2DPlaceholders, getKnexDb, insertMultipleRows, isMysql, isSqlite, nonEmptyOrNull, rawQuery, } from "./db";
|
|
6
|
+
import { getFounderCityCode } from "./founders";
|
|
7
|
+
import { MunicipalityType } from "./types";
|
|
8
|
+
import chunk from "lodash/chunk";
|
|
9
|
+
const DescriptiveType = "č.p.";
|
|
10
|
+
const RegistrationType = "č.ev.";
|
|
11
|
+
const ObjectTypes = {
|
|
12
|
+
[DescriptiveType]: 1,
|
|
13
|
+
[RegistrationType]: 2,
|
|
14
|
+
};
|
|
15
|
+
export const Column = {
|
|
16
|
+
admCode: 0,
|
|
17
|
+
cityCode: 1,
|
|
18
|
+
cityName: 2,
|
|
19
|
+
districtCode: 3,
|
|
20
|
+
districtName: 4,
|
|
21
|
+
pragueDistrictCode: 5,
|
|
22
|
+
pragueDistrictName: 6,
|
|
23
|
+
municipalityPartCode: 7,
|
|
24
|
+
municipalityPartName: 8,
|
|
25
|
+
streetCode: 9,
|
|
26
|
+
streetName: 10,
|
|
27
|
+
objectType: 11,
|
|
28
|
+
houseNumber: 12,
|
|
29
|
+
orientationalNumber: 13,
|
|
30
|
+
orientationalNumberLetter: 14,
|
|
31
|
+
postalCode: 15,
|
|
32
|
+
yCoordinate: 16,
|
|
33
|
+
xCoordinate: 17,
|
|
34
|
+
validFrom: 18,
|
|
35
|
+
};
|
|
36
|
+
const columnNames = [
|
|
37
|
+
"id",
|
|
38
|
+
"street_code",
|
|
39
|
+
"object_type_id",
|
|
40
|
+
"descriptive_number",
|
|
41
|
+
"orientational_number",
|
|
42
|
+
"orientational_number_letter",
|
|
43
|
+
"city_code",
|
|
44
|
+
"city_district_code",
|
|
45
|
+
"municipality_part_code",
|
|
46
|
+
"prague_district_code",
|
|
47
|
+
"postal_code",
|
|
48
|
+
"jtsk_x",
|
|
49
|
+
"jtsk_y",
|
|
50
|
+
"wgs84_latitude",
|
|
51
|
+
"wgs84_longitude",
|
|
52
|
+
];
|
|
53
|
+
export const commitAddressPoints = async (buffer) => {
|
|
54
|
+
if (buffer.length === 0) {
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
await insertCities(buffer);
|
|
58
|
+
await insertDistricts(buffer);
|
|
59
|
+
await insertMunicipalityParts(buffer);
|
|
60
|
+
await insertStreets(buffer);
|
|
61
|
+
await insertPragueDistricts(buffer);
|
|
62
|
+
const params = {};
|
|
63
|
+
buffer.forEach((data) => {
|
|
64
|
+
let latOrNull, lonOrNull;
|
|
65
|
+
latOrNull = null;
|
|
66
|
+
lonOrNull = null;
|
|
67
|
+
if (data[Column.xCoordinate] && data[Column.yCoordinate]) {
|
|
68
|
+
const { lat, lon } = jtsk2wgs84(parseFloat(data[Column.xCoordinate]), parseFloat(data[Column.yCoordinate]));
|
|
69
|
+
[latOrNull, lonOrNull] = [lat.toString(), lon.toString()];
|
|
70
|
+
}
|
|
71
|
+
params[data[Column.admCode]] = [
|
|
72
|
+
data[Column.admCode],
|
|
73
|
+
nonEmptyOrNull(data[Column.streetCode]),
|
|
74
|
+
ObjectTypes[data[Column.objectType]],
|
|
75
|
+
nonEmptyOrNull(data[Column.houseNumber]),
|
|
76
|
+
nonEmptyOrNull(data[Column.orientationalNumber]),
|
|
77
|
+
nonEmptyOrNull(data[Column.orientationalNumberLetter]),
|
|
78
|
+
data[Column.cityCode],
|
|
79
|
+
nonEmptyOrNull(data[Column.districtCode]),
|
|
80
|
+
nonEmptyOrNull(data[Column.municipalityPartCode]),
|
|
81
|
+
nonEmptyOrNull(data[Column.pragueDistrictCode]),
|
|
82
|
+
data[Column.postalCode],
|
|
83
|
+
nonEmptyOrNull(data[Column.xCoordinate]),
|
|
84
|
+
nonEmptyOrNull(data[Column.yCoordinate]),
|
|
85
|
+
latOrNull,
|
|
86
|
+
lonOrNull,
|
|
87
|
+
];
|
|
88
|
+
});
|
|
89
|
+
// find already existing rows
|
|
90
|
+
const existingRows = await rawQuery(`SELECT * FROM address_point WHERE id IN (${buffer
|
|
91
|
+
.map((data) => data[Column.admCode])
|
|
92
|
+
.join(",")})`);
|
|
93
|
+
const queries = [];
|
|
94
|
+
for (const row of existingRows) {
|
|
95
|
+
const toInsert = params[row.id];
|
|
96
|
+
const values = Object.values(row);
|
|
97
|
+
if (!toInsert.every((v, i) => valuesEqual(v, values[i]))) {
|
|
98
|
+
// update those whose values differ
|
|
99
|
+
queries.push(rawQuery(`UPDATE address_point SET ${columnNames
|
|
100
|
+
.map((c) => `${c} = ?`)
|
|
101
|
+
.join(", ")} WHERE id = ?`, [...toInsert, row.id]));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
await Promise.all(queries);
|
|
105
|
+
const placeHolders = generate2DPlaceholders(columnNames.length, buffer.length);
|
|
106
|
+
const knex = getKnexDb();
|
|
107
|
+
await rawQuery(`INSERT ${isMysql(knex) ? "IGNORE" : ""} INTO address_point (${columnNames.join(",")}) VALUES ${placeHolders} ${!isMysql(knex) ? "ON CONFLICT (id) DO NOTHING" : ""}`, Object.values(params).flat());
|
|
108
|
+
return buffer.length;
|
|
109
|
+
};
|
|
110
|
+
export async function removeDeprecatedAddressPoints(allIds) {
|
|
111
|
+
const knex = getKnexDb();
|
|
112
|
+
const existingIds = await knex.pluck("id").from("address_point");
|
|
113
|
+
const toRemove = existingIds.filter((id) => !allIds.has(id));
|
|
114
|
+
const chunks = chunk(toRemove, 1000);
|
|
115
|
+
for (const chunk of chunks) {
|
|
116
|
+
await knex("address_point").whereIn("id", chunk).delete();
|
|
117
|
+
}
|
|
118
|
+
console.log(`Removed ${toRemove.length} deprecated address points.`);
|
|
119
|
+
}
|
|
120
|
+
function valuesEqual(a, b) {
|
|
121
|
+
return sanitizeValue(a) === sanitizeValue(b);
|
|
122
|
+
}
|
|
123
|
+
function sanitizeValue(value) {
|
|
124
|
+
if (value === null) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
value = value.toString();
|
|
128
|
+
if (/\d+\.\d+/.test(value)) {
|
|
129
|
+
return roundToNDecimalPlaces(parseFloat(value), 6).toString();
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
export const insertCities = async (buffer) => {
|
|
134
|
+
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.cityCode, [Column.cityName]), "city", ["code", "name"]);
|
|
135
|
+
};
|
|
136
|
+
export const insertDistricts = async (buffer) => {
|
|
137
|
+
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.districtCode, [
|
|
138
|
+
Column.cityCode,
|
|
139
|
+
Column.districtName,
|
|
140
|
+
]), "city_district", ["code", "city_code", "name"]);
|
|
141
|
+
};
|
|
142
|
+
export const insertMunicipalityParts = async (buffer) => {
|
|
143
|
+
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.municipalityPartCode, [
|
|
144
|
+
Column.municipalityPartName,
|
|
145
|
+
Column.cityCode,
|
|
146
|
+
]), "municipality_part", ["code", "name", "city_code"]);
|
|
147
|
+
};
|
|
148
|
+
export const insertPragueDistricts = async (buffer) => {
|
|
149
|
+
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.pragueDistrictCode, [
|
|
150
|
+
Column.pragueDistrictName,
|
|
151
|
+
]), "prague_district", ["code", "name"]);
|
|
152
|
+
};
|
|
153
|
+
export const insertStreets = async (buffer) => {
|
|
154
|
+
return await insertMultipleRows(extractKeyValuesPairs(buffer, Column.streetCode, [
|
|
155
|
+
Column.cityCode,
|
|
156
|
+
Column.streetName,
|
|
157
|
+
]), "street", ["code", "city_code", "name"]);
|
|
158
|
+
};
|
|
159
|
+
export const areAddressPointsSynced = async () => {
|
|
160
|
+
const result = await getKnexDb()
|
|
161
|
+
.count("*", { as: "countAll" })
|
|
162
|
+
.from("address_point")
|
|
163
|
+
.first();
|
|
164
|
+
return Number(result.countAll) >= 2900000; // total is almost 3 million
|
|
165
|
+
};
|
|
166
|
+
const addressPointSelect = `
|
|
167
|
+
SELECT a.id, s.name AS street_name, o.name AS object_type_name, a.descriptive_number,
|
|
168
|
+
a.orientational_number, a.orientational_number_letter, c.name AS city_name,
|
|
169
|
+
m.name AS municipality_part_name, p.name AS prague_district_name,
|
|
170
|
+
d.name AS district_name, a.postal_code, a.wgs84_latitude, a.wgs84_longitude
|
|
171
|
+
FROM address_point a
|
|
172
|
+
LEFT JOIN street s ON a.street_code = s.code
|
|
173
|
+
INNER JOIN object_type o ON o.id = a.object_type_id
|
|
174
|
+
INNER JOIN city c ON c.code = a.city_code
|
|
175
|
+
LEFT JOIN city_district d ON a.city_district_code = d.code
|
|
176
|
+
LEFT JOIN prague_district p ON a.prague_district_code = p.code
|
|
177
|
+
LEFT JOIN municipality_part m ON a.municipality_part_code = m.code`;
|
|
178
|
+
export const getAddressPointById = async (addressPointId) => {
|
|
179
|
+
const row = await rawQuery(`${addressPointSelect}
|
|
180
|
+
WHERE a.id = ?`, [addressPointId]);
|
|
181
|
+
if (row.length === 0) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
return rowToAddressPoint(row[0]);
|
|
185
|
+
};
|
|
186
|
+
let lastFounder = null;
|
|
187
|
+
let allStreets = [];
|
|
188
|
+
export const checkStreetExists = async (streetName, founder) => {
|
|
189
|
+
const knex = getKnexDb();
|
|
190
|
+
const errors = [];
|
|
191
|
+
// we check the whole city
|
|
192
|
+
const cityCode = await getFounderCityCode(founder.municipalityType, founder.municipalityCode);
|
|
193
|
+
const rowList = await rawQuery(`SELECT name AS street_name
|
|
194
|
+
FROM street
|
|
195
|
+
WHERE city_code = ? AND name = ? ${isSqlite(knex) ? "COLLATE NOCASE" : ""}`, [cityCode, streetName]);
|
|
196
|
+
if (rowList.length > 0) {
|
|
197
|
+
const row = rowList[0];
|
|
198
|
+
if (row.street_name !== streetName) {
|
|
199
|
+
// errors.push(
|
|
200
|
+
// `Street '${streetName}' has wrong case, correct case: '${row.street_name}'.`
|
|
201
|
+
// );
|
|
202
|
+
}
|
|
203
|
+
return { exists: true, errors };
|
|
204
|
+
}
|
|
205
|
+
if (lastFounder !== founder) {
|
|
206
|
+
allStreets = await getAllStreets(cityCode);
|
|
207
|
+
lastFounder = founder;
|
|
208
|
+
}
|
|
209
|
+
const match = allStreets.find((s) => s.toLocaleLowerCase("cs-CZ") === streetName.toLocaleLowerCase("cs-CZ"));
|
|
210
|
+
let exists = false;
|
|
211
|
+
if (match) {
|
|
212
|
+
exists = true;
|
|
213
|
+
if (streetName !== match) {
|
|
214
|
+
// errors.push(
|
|
215
|
+
// `Street '${streetName}' has wrong case, correct case: '${match}'.`
|
|
216
|
+
// );
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const closest = findClosestString(streetName, allStreets);
|
|
221
|
+
errors.push({
|
|
222
|
+
message: `Ulice '${streetName}' v této obci neexistuje, mysleli jste '${closest}'?`,
|
|
223
|
+
startOffset: 0,
|
|
224
|
+
endOffset: streetName.length + 1,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return { exists: false, errors };
|
|
228
|
+
};
|
|
229
|
+
const getAllStreets = async (cityCode) => {
|
|
230
|
+
const knex = getKnexDb();
|
|
231
|
+
return await knex.pluck("name").from("street").where("city_code", cityCode);
|
|
232
|
+
};
|
|
233
|
+
export const findAddressPoints = async (params) => {
|
|
234
|
+
const queryParams = getQueryParams(params);
|
|
235
|
+
const streetJoinCondition = getStreetJoinCondition(params);
|
|
236
|
+
const whereCondition = getWhereCondition(params);
|
|
237
|
+
const queryResult = await rawQuery(`SELECT a.id, s.name AS street_name, o.name AS object_type_name, a.descriptive_number,
|
|
238
|
+
a.orientational_number, a.orientational_number_letter, c.name AS city_name,
|
|
239
|
+
d.name AS district_name, m.name AS municipality_part_name, p.name AS prague_district_name,
|
|
240
|
+
a.postal_code, a.wgs84_latitude, a.wgs84_longitude
|
|
241
|
+
FROM address_point a
|
|
242
|
+
${streetJoinCondition}
|
|
243
|
+
INNER JOIN object_type o ON o.id = a.object_type_id
|
|
244
|
+
INNER JOIN city c ON c.code = a.city_code
|
|
245
|
+
LEFT JOIN city_district d ON a.city_district_code = d.code
|
|
246
|
+
LEFT JOIN municipality_part m ON a.municipality_part_code = m.code
|
|
247
|
+
LEFT JOIN prague_district p ON a.prague_district_code = p.code
|
|
248
|
+
WHERE ${whereCondition}`, queryParams);
|
|
249
|
+
return filterAddressPoints(queryResult.map(rowToAddressPoint), params);
|
|
250
|
+
};
|
|
251
|
+
export const filterAddressPoints = (addressPoints, params) => {
|
|
252
|
+
if (params.type === "wholeMunicipality" ||
|
|
253
|
+
params.type === "wholeMunicipalityNoStreetName" ||
|
|
254
|
+
params.type === "wholeMunicipalityPart") {
|
|
255
|
+
return addressPoints;
|
|
256
|
+
}
|
|
257
|
+
const result = [];
|
|
258
|
+
const numberSpec = params.smdLine.numberSpec;
|
|
259
|
+
if (isSeriesSpecArray(numberSpec)) {
|
|
260
|
+
numberSpec.forEach((seriesSpec) => {
|
|
261
|
+
result.push(...filterAddressPointsByRanges(addressPoints, seriesSpec));
|
|
262
|
+
});
|
|
263
|
+
// when no number specs are present, we take everything
|
|
264
|
+
if (numberSpec.length === 0) {
|
|
265
|
+
result.push(...addressPoints);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else if (isNegativeSeriesSpec(numberSpec)) {
|
|
269
|
+
// negative number spec (e.g. odd numbers except 13-17)
|
|
270
|
+
const toExclude = filterAddressPointsByRanges(addressPoints, numberSpec);
|
|
271
|
+
result.push(...addressPoints.filter((addressPoint) => !toExclude.includes(addressPoint)));
|
|
272
|
+
}
|
|
273
|
+
return result;
|
|
274
|
+
};
|
|
275
|
+
const filterAddressPointsByRanges = (addressPoints, seriesSpec) => {
|
|
276
|
+
const result = [];
|
|
277
|
+
seriesSpec.ranges.forEach((range) => {
|
|
278
|
+
result.push(...addressPoints.filter((addressPoint) => {
|
|
279
|
+
if (isRange(range)) {
|
|
280
|
+
const number = getNumberByType(seriesSpec.type, addressPoint);
|
|
281
|
+
return (isInRange(number, seriesSpec.type !== SeriesType.Description
|
|
282
|
+
? addressPoint.orientationalNumberLetter ?? null
|
|
283
|
+
: null, range) && fitsType(number, seriesSpec.type));
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const fullStreetNumber = range;
|
|
287
|
+
return equalsFullStreetNumber(fullStreetNumber, addressPoint);
|
|
288
|
+
}
|
|
289
|
+
}));
|
|
290
|
+
});
|
|
291
|
+
// when no series specs are present, we take everything that fits the type
|
|
292
|
+
if (seriesSpec.ranges.length === 0) {
|
|
293
|
+
result.push(...addressPoints.filter((addressPoint) => fitsType(getNumberByType(seriesSpec.type, addressPoint), seriesSpec.type)));
|
|
294
|
+
}
|
|
295
|
+
return result;
|
|
296
|
+
};
|
|
297
|
+
export const getQueryParams = (params) => {
|
|
298
|
+
if (params.type === "smdLine" && params.smdLine.type === "street") {
|
|
299
|
+
return [params.smdLine.street, params.municipality.code];
|
|
300
|
+
}
|
|
301
|
+
if ((params.type === "smdLine" && params.smdLine.type === "municipalityPart") ||
|
|
302
|
+
params.type === "wholeMunicipalityPart") {
|
|
303
|
+
return [params.municipalityPartCode];
|
|
304
|
+
}
|
|
305
|
+
return [params.municipality.code];
|
|
306
|
+
};
|
|
307
|
+
export const getStreetJoinCondition = (params) => {
|
|
308
|
+
if (params.type === "smdLine" && params.smdLine.type === "street") {
|
|
309
|
+
return `JOIN street s ON a.street_code = s.code AND s.name = ? ${isSqlite(getKnexDb()) ? "COLLATE NOCASE" : ""}`;
|
|
310
|
+
}
|
|
311
|
+
return "LEFT JOIN street s ON a.street_code = s.code";
|
|
312
|
+
};
|
|
313
|
+
export const getWhereCondition = (params) => {
|
|
314
|
+
if ((params.type === "smdLine" && params.smdLine.type === "municipalityPart") ||
|
|
315
|
+
params.type === "wholeMunicipalityPart") {
|
|
316
|
+
return "a.municipality_part_code = ?";
|
|
317
|
+
}
|
|
318
|
+
if (params.type === "wholeMunicipalityNoStreetName") {
|
|
319
|
+
return `${getMunicipalityWhere("a", params.municipality)} AND a.street_code IS NULL`;
|
|
320
|
+
}
|
|
321
|
+
return getMunicipalityWhere("a", params.municipality);
|
|
322
|
+
};
|
|
323
|
+
export const isInRange = (number, letter, range) => {
|
|
324
|
+
if (number === null) {
|
|
325
|
+
return !range.from && !range.to;
|
|
326
|
+
}
|
|
327
|
+
// explainer: either the lower bound is not set, or it is lower than the number
|
|
328
|
+
// if it's equal to the number, we also have to check the letter - if it's not set, we don't care
|
|
329
|
+
// if from.letter is set, we need to have a letter set and it has to be greater or equal:
|
|
330
|
+
// number without letter counts lower than number with letter 'a' (e.g. 23 < 23a)
|
|
331
|
+
const satisfiesFrom = !range.from ||
|
|
332
|
+
number > range.from.number ||
|
|
333
|
+
(number === range.from.number &&
|
|
334
|
+
(!range.from.letter || (!!letter && letter >= range.from.letter)));
|
|
335
|
+
const satisfiesTo = !range.to ||
|
|
336
|
+
number < range.to.number ||
|
|
337
|
+
(number === range.to.number &&
|
|
338
|
+
(!letter ||
|
|
339
|
+
(!!range.to.letter && !!letter && letter <= range.to.letter)));
|
|
340
|
+
return satisfiesFrom && satisfiesTo;
|
|
341
|
+
};
|
|
342
|
+
export const fitsType = (number, type) => {
|
|
343
|
+
return (type === SeriesType.Description ||
|
|
344
|
+
type === SeriesType.All ||
|
|
345
|
+
// a missing number (e.g. no orientational number) is neither odd nor even,
|
|
346
|
+
// careful: null % 2 === 0 in JS
|
|
347
|
+
(type === SeriesType.Odd && number !== null && number % 2 === 1) ||
|
|
348
|
+
(type === SeriesType.Even && number !== null && number % 2 === 0));
|
|
349
|
+
};
|
|
350
|
+
export const equalsFullStreetNumber = (fullStreetNumber, addressPoint) => {
|
|
351
|
+
return (fullStreetNumber.descriptionNumber.number === addressPoint.houseNumber &&
|
|
352
|
+
fullStreetNumber.orientationalNumber.number ===
|
|
353
|
+
addressPoint.orientationalNumber &&
|
|
354
|
+
((!fullStreetNumber.orientationalNumber.letter &&
|
|
355
|
+
!addressPoint.orientationalNumberLetter) ||
|
|
356
|
+
fullStreetNumber.orientationalNumber.letter ===
|
|
357
|
+
addressPoint.orientationalNumberLetter));
|
|
358
|
+
};
|
|
359
|
+
const getNumberByType = (type, addressPoint) => {
|
|
360
|
+
return type === SeriesType.Description
|
|
361
|
+
? addressPoint.houseNumber
|
|
362
|
+
: addressPoint.orientationalNumber ?? null;
|
|
363
|
+
};
|
|
364
|
+
const getMunicipalityWhere = (alias, municipality) => {
|
|
365
|
+
return municipality.type === MunicipalityType.City
|
|
366
|
+
? `${alias}.city_code = ?`
|
|
367
|
+
: `${alias}.city_district_code = ?`;
|
|
368
|
+
};
|
|
369
|
+
const rowToAddressPoint = (row) => {
|
|
370
|
+
const point = {
|
|
371
|
+
id: row.id,
|
|
372
|
+
address: "",
|
|
373
|
+
type: row.object_type_name === DescriptiveType
|
|
374
|
+
? AddressPointType.Description
|
|
375
|
+
: AddressPointType.Registration,
|
|
376
|
+
houseNumber: row.descriptive_number,
|
|
377
|
+
city: row.city_name,
|
|
378
|
+
municipalityPart: row.municipality_part_name,
|
|
379
|
+
postalCode: row.postal_code,
|
|
380
|
+
lat: row.wgs84_latitude,
|
|
381
|
+
lng: row.wgs84_longitude,
|
|
382
|
+
};
|
|
383
|
+
if (row.street_name !== null) {
|
|
384
|
+
point.street = row.street_name;
|
|
385
|
+
}
|
|
386
|
+
if (row.orientational_number !== null) {
|
|
387
|
+
point.orientationalNumber = row.orientational_number;
|
|
388
|
+
}
|
|
389
|
+
if (row.orientational_number_letter !== null) {
|
|
390
|
+
point.orientationalNumberLetter = row.orientational_number_letter;
|
|
391
|
+
}
|
|
392
|
+
if (row.district_name !== null) {
|
|
393
|
+
point.district = row.district_name;
|
|
394
|
+
}
|
|
395
|
+
if (row.prague_district_name !== null) {
|
|
396
|
+
point.pragueDistrict = row.prague_district_name;
|
|
397
|
+
}
|
|
398
|
+
point.address = createSingleLineAddress(point);
|
|
399
|
+
return point;
|
|
400
|
+
};
|
|
401
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRkcmVzcy1wb2ludHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGIvYWRkcmVzcy1wb2ludHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLHVCQUF1QixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFFLE9BQU8sRUFLTCxVQUFVLEVBR1Ysb0JBQW9CLEVBQ3BCLE9BQU8sRUFDUCxpQkFBaUIsR0FDbEIsTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM1RSxPQUFPLFVBQVUsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QyxPQUFPLEVBQ0wscUJBQXFCLEVBQ3JCLHNCQUFzQixFQUN0QixTQUFTLEVBQ1Qsa0JBQWtCLEVBQ2xCLE9BQU8sRUFDUCxRQUFRLEVBQ1IsY0FBYyxFQUNkLFFBQVEsR0FDVCxNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUNoRCxPQUFPLEVBQXlCLGdCQUFnQixFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ2xFLE9BQU8sS0FBSyxNQUFNLGNBQWMsQ0FBQztBQUVqQyxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUM7QUFDL0IsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUM7QUFFakMsTUFBTSxXQUFXLEdBQUc7SUFDbEIsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO0lBQ3BCLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxDQUFDO0NBQ3RCLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxNQUFNLEdBQUc7SUFDcEIsT0FBTyxFQUFFLENBQUM7SUFDVixRQUFRLEVBQUUsQ0FBQztJQUNYLFFBQVEsRUFBRSxDQUFDO0lBQ1gsWUFBWSxFQUFFLENBQUM7SUFDZixZQUFZLEVBQUUsQ0FBQztJQUNmLGtCQUFrQixFQUFFLENBQUM7SUFD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R0FBRyxDQUFDLGFBQWEsS0FBSyxJQUFJLEVBQUU7UUFDOUIsS0FBSyxDQUFDLFFBQVEsR0FBRyxHQUFHLENBQUMsYUFBYSxDQUFDO0tBQ3BDO0lBQ0QsSUFBSSxHQUFHLENBQUMsb0JBQW9CLEtBQUssSUFBSSxFQUFFO1FBQ3JDLEtBQUssQ0FBQyxjQUFjLEdBQUcsR0FBRyxDQUFDLG9CQUFvQixDQUFDO0tBQ2pEO0lBQ0QsS0FBSyxDQUFDLE9BQU8sR0FBRyx1QkFBdUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMvQyxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFkZHJlc3NQb2ludFR5cGUsIGNyZWF0ZVNpbmdsZUxpbmVBZGRyZXNzIH0gZnJvbSBcImN6ZWNoLWFkZHJlc3NcIjtcbmltcG9ydCB7XG4gIEFkZHJlc3NQb2ludCxcbiAgRnVsbFN0cmVldE51bWJlcixcbiAgUmFuZ2VTcGVjLFxuICBTZXJpZXNTcGVjLFxuICBTZXJpZXNUeXBlLFxuICBTbWRFcnJvcixcbiAgU21kTGluZSxcbiAgaXNOZWdhdGl2ZVNlcmllc1NwZWMsXG4gIGlzUmFuZ2UsXG4gIGlzU2VyaWVzU3BlY0FycmF5LFxufSBmcm9tIFwiLi4vc3RyZWV0LW1hcmtkb3duL3R5cGVzXCI7XG5pbXBvcnQgeyBmaW5kQ2xvc2VzdFN0cmluZywgcm91bmRUb05EZWNpbWFsUGxhY2VzIH0gZnJvbSBcIi4uL3V0aWxzL2hlbHBlcnNcIjtcbmltcG9ydCBqdHNrMndnczg0IGZyb20gXCIuLi91dGlscy9qdHNrMndnczg0XCI7XG5pbXBvcnQge1xuICBleHRyYWN0S2V5VmFsdWVzUGFpcnMsXG4gIGdlbmVyYXRlMkRQbGFjZWhvbGRlcnMsXG4gIGdldEtuZXhEYixcbiAgaW5zZXJ0TXVsdGlwbGVSb3dzLFxuICBpc015c3FsLFxuICBpc1NxbGl0ZSxcbiAgbm9uRW1wdHlPck51bGwsXG4gIHJhd1F1ZXJ5LFxufSBmcm9tIFwiLi9kYlwiO1xuaW1wb3J0IHsgZ2V0Rm91bmRlckNpdHlDb2RlIH0gZnJvbSBcIi4vZm91bmRlcnNcIjtcbmltcG9ydCB7IEZvdW5kZXIsIE11bmljaXBhbGl0eSwgTXVuaWNpcGFsaXR5VHlwZSB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgY2h1bmsgZnJvbSBcImxvZGFzaC9jaHVua1wiO1xuXG5jb25zdCBEZXNjcmlwdGl2ZVR5cGUgPSBcIsSNLnAuXCI7XG5jb25zdCBSZWdpc3RyYXRpb25UeXBlID0gXCLEjS5ldi5cIjtcblxuY29uc3QgT2JqZWN0VHlwZXMgPSB7XG4gIFtEZXNjcmlwdGl2ZVR5cGVdOiAxLFxuICBbUmVnaXN0cmF0aW9uVHlwZV06IDIsXG59O1xuXG5leHBvcnQgY29uc3QgQ29sdW1uID0ge1xuICBhZG1Db2RlOiAwLFxuICBjaXR5Q29kZTogMSxcbiAgY2l0eU5hbWU6IDIsXG4gIGRpc3RyaWN0Q29kZTogMyxcbiAgZGlzdHJpY3ROYW1lOiA0LFxuICBwcmFndWVEaXN0cmljdENvZGU6IDUsXG4gIHByYWd1ZURpc3RyaWN0TmFtZTogNixcbiAgbXVuaWNpcGFsaXR5UGFydENvZGU6IDcsXG4gIG11bmljaXBhbGl0eVBhcnROYW1lOiA4LFxuICBzdHJlZXRDb2RlOiA5LFxuICBzdHJlZXROYW1lOiAxMCxcbiAgb2JqZWN0VHlwZTogMTEsXG4gIGhvdXNlTnVtYmVyOiAxMixcbiAgb3JpZW50YXRpb25hbE51bWJlcjogMTMsXG4gIG9yaWVudGF0aW9uYWxOdW1iZXJMZXR0ZXI6IDE0LFxuICBwb3N0YWxDb2RlOiAxNSxcbiAgeUNvb3JkaW5hdGU6IDE2LFxuICB4Q29vcmRpbmF0ZTogMTcsXG4gIHZhbGlkRnJvbTogMTgsXG59O1xuXG5jb25zdCBjb2x1bW5OYW1lcyA9IFtcbiAgXCJpZFwiLFxuICBcInN0cmVldF9jb2RlXCIsXG4gIFwib2JqZWN0X3R5cGVfaWRcIixcbiAgXCJkZXNjcmlwdGl2ZV9udW1iZXJcIixcbiAgXCJvcmllbnRhdGlvbmFsX251bWJlclwiLFxuICBcIm9yaWVudGF0aW9uYWxfbnVtYmVyX2xldHRlclwiLFxuICBcImNpdHlfY29kZVwiLFxuICBcImNpdHlfZGlzdHJpY3RfY29kZVwiLFxuICBcIm11bmljaXBhbGl0eV9wYXJ0X2NvZGVcIixcbiAgXCJwcmFndWVfZGlzdHJpY3RfY29kZVwiLFxuICBcInBvc3RhbF9jb2RlXCIsXG4gIFwianRza194XCIsXG4gIFwianRza195XCIsXG4gIFwid2dzODRfbGF0aXR1ZGVcIixcbiAgXCJ3Z3M4NF9sb25naXR1ZGVcIixcbl07XG5cbmV4cG9ydCBjb25zdCBjb21taXRBZGRyZXNzUG9pbnRzID0gYXN5bmMgKFxuICBidWZmZXI6IHN0cmluZ1tdW11cbik6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIGlmIChidWZmZXIubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cbiAgYXdhaXQgaW5zZXJ0Q2l0aWVzKGJ1ZmZlcik7XG4gIGF3YWl0IGluc2VydERpc3RyaWN0cyhidWZmZXIpO1xuICBhd2FpdCBpbnNlcnRNdW5pY2lwYWxpdHlQYXJ0cyhidWZmZXIpO1xuICBhd2FpdCBpbnNlcnRTdHJlZXRzKGJ1ZmZlcik7XG4gIGF3YWl0IGluc2VydFByYWd1ZURpc3RyaWN0cyhidWZmZXIpO1xuXG4gIGNvbnN0IHBhcmFtczogUmVjb3JkPHN0cmluZywgKHN0cmluZyB8IG51bGwpW10+ID0ge307XG4gIGJ1ZmZlci5mb3JFYWNoKChkYXRhKSA9PiB7XG4gICAgbGV0IGxhdE9yTnVsbDogc3RyaW5nLCBsb25Pck51bGw6IHN0cmluZztcbiAgICBsYXRPck51bGwgPSBudWxsO1xuICAgIGxvbk9yTnVsbCA9IG51bGw7XG4gICAgaWYgKGRhdGFbQ29sdW1uLnhDb29yZGluYXRlXSAmJiBkYXRhW0NvbHVtbi55Q29vcmRpbmF0ZV0pIHtcbiAgICAgIGNvbnN0IHsgbGF0LCBsb24gfSA9IGp0c2syd2dzODQoXG4gICAgICAgIHBhcnNlRmxvYXQoZGF0YVtDb2x1bW4ueENvb3JkaW5hdGVdKSxcbiAgICAgICAgcGFyc2VGbG9hdChkYXRhW0NvbHVtbi55Q29vcmRpbmF0ZV0pXG4gICAgICApO1xuICAgICAgW2xhdE9yTnVsbCwgbG9uT3JOdWxsXSA9IFtsYXQudG9TdHJpbmcoKSwgbG9uLnRvU3RyaW5nKCldO1xuICAgIH1cbiAgICBwYXJhbXNbZGF0YVtDb2x1bW4uYWRtQ29kZV1dID0gW1xuICAgICAgZGF0YVtDb2x1bW4uYWRtQ29kZV0sXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi5zdHJlZXRDb2RlXSksXG4gICAgICBPYmplY3RUeXBlc1tkYXRhW0NvbHVtbi5vYmplY3RUeXBlXV0sXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi5ob3VzZU51bWJlcl0pLFxuICAgICAgbm9uRW1wdHlPck51bGwoZGF0YVtDb2x1bW4ub3JpZW50YXRpb25hbE51bWJlcl0pLFxuICAgICAgbm9uRW1wdHlPck51bGwoZGF0YVtDb2x1bW4ub3JpZW50YXRpb25hbE51bWJlckxldHRlcl0pLFxuICAgICAgZGF0YVtDb2x1bW4uY2l0eUNvZGVdLFxuICAgICAgbm9uRW1wdHlPck51bGwoZGF0YVtDb2x1bW4uZGlzdHJpY3RDb2RlXSksXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi5tdW5pY2lwYWxpdHlQYXJ0Q29kZV0pLFxuICAgICAgbm9uRW1wdHlPck51bGwoZGF0YVtDb2x1bW4ucHJhZ3VlRGlzdHJpY3RDb2RlXSksXG4gICAgICBkYXRhW0NvbHVtbi5wb3N0YWxDb2RlXSxcbiAgICAgIG5vbkVtcHR5T3JOdWxsKGRhdGFbQ29sdW1uLnhDb29yZGluYXRlXSksXG4gICAgICBub25FbXB0eU9yTnVsbChkYXRhW0NvbHVtbi55Q29vcmRpbmF0ZV0pLFxuICAgICAgbGF0T3JOdWxsLFxuICAgICAgbG9uT3JOdWxsLFxuICAgIF07XG4gIH0pO1xuXG4gIC8vIGZpbmQgYWxyZWFkeSBleGlzdGluZyByb3dzXG4gIGNvbnN0IGV4aXN0aW5nUm93cyA9IGF3YWl0IHJhd1F1ZXJ5KFxuICAgIGBTRUxFQ1QgKiBGUk9NIGFkZHJlc3NfcG9pbnQgV0hFUkUgaWQgSU4gKCR7YnVmZmVyXG4gICAgICAubWFwKChkYXRhKSA9PiBkYXRhW0NvbHVtbi5hZG1Db2RlXSlcbiAgICAgIC5qb2luKFwiLFwiKX0pYFxuICApO1xuXG4gIGNvbnN0IHF1ZXJpZXMgPSBbXTtcbiAgZm9yIChjb25zdCByb3cgb2YgZXhpc3RpbmdSb3dzKSB7XG4gICAgY29uc3QgdG9JbnNlcnQgPSBwYXJhbXNbcm93LmlkXTtcbiAgICBjb25zdCB2YWx1ZXMgPSBPYmplY3QudmFsdWVzKHJvdyk7XG4gICAgaWYgKCF0b0luc2VydC5ldmVyeSgodiwgaSkgPT4gdmFsdWVzRXF1YWwodiwgdmFsdWVzW2ldKSkpIHtcbiAgICAgIC8vIHVwZGF0ZSB0aG9zZSB3aG9zZSB2YWx1ZXMgZGlmZmVyXG4gICAgICBxdWVyaWVzLnB1c2goXG4gICAgICAgIHJhd1F1ZXJ5KFxuICAgICAgICAgIGBVUERBVEUgYWRkcmVzc19wb2ludCBTRVQgJHtjb2x1bW5OYW1lc1xuICAgICAgICAgICAgLm1hcCgoYykgPT4gYCR7Y30gPSA/YClcbiAgICAgICAgICAgIC5qb2luKFwiLCBcIil9IFdIRVJFIGlkID0gP2AsXG4gICAgICAgICAgWy4uLnRvSW5zZXJ0LCByb3cuaWRdXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYXdhaXQgUHJvbWlzZS5hbGwocXVlcmllcyk7XG5cbiAgY29uc3QgcGxhY2VIb2xkZXJzID0gZ2VuZXJhdGUyRFBsYWNlaG9sZGVycyhcbiAgICBjb2x1bW5OYW1lcy5sZW5ndGgsXG4gICAgYnVmZmVyLmxlbmd0aFxuICApO1xuXG4gIGNvbnN0IGtuZXggPSBnZXRLbmV4RGIoKTtcbiAgYXdhaXQgcmF3UXVlcnkoXG4gICAgYElOU0VSVCAke1xuICAgICAgaXNNeXNxbChrbmV4KSA/IFwiSUdOT1JFXCIgOiBcIlwiXG4gICAgfSBJTlRPIGFkZHJlc3NfcG9pbnQgKCR7Y29sdW1uTmFtZXMuam9pbihcIixcIil9KSBWQUxVRVMgJHtwbGFjZUhvbGRlcnN9ICR7XG4gICAgICAhaXNNeXNxbChrbmV4KSA/IFwiT04gQ09ORkxJQ1QgKGlkKSBETyBOT1RISU5HXCIgOiBcIlwiXG4gICAgfWAsXG4gICAgT2JqZWN0LnZhbHVlcyhwYXJhbXMpLmZsYXQoKVxuICApO1xuXG4gIHJldHVybiBidWZmZXIubGVuZ3RoO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlbW92ZURlcHJlY2F0ZWRBZGRyZXNzUG9pbnRzKFxuICBhbGxJZHM6IFNldDxudW1iZXI+XG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3Qga25leCA9IGdldEtuZXhEYigpO1xuICBjb25zdCBleGlzdGluZ0lkcyA9IGF3YWl0IGtuZXgucGx1Y2soXCJpZFwiKS5mcm9tKFwiYWRkcmVzc19wb2ludFwiKTtcbiAgY29uc3QgdG9SZW1vdmUgPSBleGlzdGluZ0lkcy5maWx0ZXIoKGlkKSA9PiAhYWxsSWRzLmhhcyhpZCkpO1xuICBjb25zdCBjaHVua3MgPSBjaHVuayh0b1JlbW92ZSwgMTAwMCk7XG4gIGZvciAoY29uc3QgY2h1bmsgb2YgY2h1bmtzKSB7XG4gICAgYXdhaXQga25leChcImFkZHJlc3NfcG9pbnRcIikud2hlcmVJbihcImlkXCIsIGNodW5rKS5kZWxldGUoKTtcbiAgfVxuICBjb25zb2xlLmxvZyhgUmVtb3ZlZCAke3RvUmVtb3ZlLmxlbmd0aH0gZGVwcmVjYXRlZCBhZGRyZXNzIHBvaW50cy5gKTtcbn1cblxuZnVuY3Rpb24gdmFsdWVzRXF1YWwoYTogYW55LCBiOiBhbnkpOiBib29sZWFuIHtcbiAgcmV0dXJuIHNhbml0aXplVmFsdWUoYSkgPT09IHNhbml0aXplVmFsdWUoYik7XG59XG5cbmZ1bmN0aW9uIHNhbml0aXplVmFsdWUodmFsdWU6IGFueSk6IGFueSB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIHZhbHVlID0gdmFsdWUudG9TdHJpbmcoKTtcblxuICBpZiAoL1xcZCtcXC5cXGQrLy50ZXN0KHZhbHVlKSkge1xuICAgIHJldHVybiByb3VuZFRvTkRlY2ltYWxQbGFjZXMocGFyc2VGbG9hdCh2YWx1ZSksIDYpLnRvU3RyaW5nKCk7XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufVxuXG5leHBvcnQgY29uc3QgaW5zZXJ0Q2l0aWVzID0gYXN5bmMgKGJ1ZmZlcjogc3RyaW5nW11bXSk6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIHJldHVybiBhd2FpdCBpbnNlcnRNdWx0aXBsZVJvd3MoXG4gICAgZXh0cmFjdEtleVZhbHVlc1BhaXJzKGJ1ZmZlciwgQ29sdW1uLmNpdHlDb2RlLCBbQ29sdW1uLmNpdHlOYW1lXSksXG4gICAgXCJjaXR5XCIsXG4gICAgW1wiY29kZVwiLCBcIm5hbWVcIl1cbiAgKTtcbn07XG5cbmV4cG9ydCBjb25zdCBpbnNlcnREaXN0cmljdHMgPSBhc3luYyAoYnVmZmVyOiBzdHJpbmdbXVtdKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgcmV0dXJuIGF3YWl0IGluc2VydE11bHRpcGxlUm93cyhcbiAgICBleHRyYWN0S2V5VmFsdWVzUGFpcnMoYnVmZmVyLCBDb2x1bW4uZGlzdHJpY3RDb2RlLCBbXG4gICAgICBDb2x1bW4uY2l0eUNvZGUsXG4gICAgICBDb2x1bW4uZGlzdHJpY3ROYW1lLFxuICAgIF0pLFxuICAgIFwiY2l0eV9kaXN0cmljdFwiLFxuICAgIFtcImNvZGVcIiwgXCJjaXR5X2NvZGVcIiwgXCJuYW1lXCJdXG4gICk7XG59O1xuXG5leHBvcnQgY29uc3QgaW5zZXJ0TXVuaWNpcGFsaXR5UGFydHMgPSBhc3luYyAoXG4gIGJ1ZmZlcjogc3RyaW5nW11bXVxuKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgcmV0dXJuIGF3YWl0IGluc2VydE11bHRpcGxlUm93cyhcbiAgICBleHRyYWN0S2V5VmFsdWVzUGFpcnMoYnVmZmVyLCBDb2x1bW4ubXVuaWNpcGFsaXR5UGFydENvZGUsIFtcbiAgICAgIENvbHVtbi5tdW5pY2lwYWxpdHlQYXJ0TmFtZSxcbiAgICAgIENvbHVtbi5jaXR5Q29kZSxcbiAgICBdKSxcbiAgICBcIm11bmljaXBhbGl0eV9wYXJ0XCIsXG4gICAgW1wiY29kZVwiLCBcIm5hbWVcIiwgXCJjaXR5X2NvZGVcIl1cbiAgKTtcbn07XG5cbmV4cG9ydCBjb25zdCBpbnNlcnRQcmFndWVEaXN0cmljdHMgPSBhc3luYyAoXG4gIGJ1ZmZlcjogc3RyaW5nW11bXVxuKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgcmV0dXJuIGF3YWl0IGluc2VydE11bHRpcGxlUm93cyhcbiAgICBleHRyYWN0S2V5VmFsdWVzUGFpcnMoYnVmZmVyLCBDb2x1bW4ucHJhZ3VlRGlzdHJpY3RDb2RlLCBbXG4gICAgICBDb2x1bW4ucHJhZ3VlRGlzdHJpY3ROYW1lLFxuICAgIF0pLFxuICAgIFwicHJhZ3VlX2Rpc3RyaWN0XCIsXG4gICAgW1wiY29kZVwiLCBcIm5hbWVcIl1cbiAgKTtcbn07XG5cbmV4cG9ydCBjb25zdCBpbnNlcnRTdHJlZXRzID0gYXN5bmMgKGJ1ZmZlcjogc3RyaW5nW11bXSk6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIHJldHVybiBhd2FpdCBpbnNlcnRNdWx0aXBsZVJvd3MoXG4gICAgZXh0cmFjdEtleVZhbHVlc1BhaXJzKGJ1ZmZlciwgQ29sdW1uLnN0cmVldENvZGUsIFtcbiAgICAgIENvbHVtbi5jaXR5Q29kZSxcbiAgICAgIENvbHVtbi5zdHJlZXROYW1lLFxuICAgIF0pLFxuICAgIFwic3RyZWV0XCIsXG4gICAgW1wiY29kZVwiLCBcImNpdHlfY29kZVwiLCBcIm5hbWVcIl1cbiAgKTtcbn07XG5cbmV4cG9ydCBjb25zdCBhcmVBZGRyZXNzUG9pbnRzU3luY2VkID0gYXN5bmMgKCk6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuICBjb25zdCByZXN1bHQgPSBhd2FpdCBnZXRLbmV4RGIoKVxuICAgIC5jb3VudChcIipcIiwgeyBhczogXCJjb3VudEFsbFwiIH0pXG4gICAgLmZyb20oXCJhZGRyZXNzX3BvaW50XCIpXG4gICAgLmZpcnN0KCk7XG4gIHJldHVybiBOdW1iZXIocmVzdWx0LmNvdW50QWxsKSA+PSAyOTAwMDAwOyAvLyB0b3RhbCBpcyBhbG1vc3QgMyBtaWxsaW9uXG59O1xuXG5jb25zdCBhZGRyZXNzUG9pbnRTZWxlY3QgPSBgXG4gIFNFTEVDVCBhLmlkLCBzLm5hbWUgQVMgc3RyZWV0X25hbWUsIG8ubmFtZSBBUyBvYmplY3RfdHlwZV9uYW1lLCBhLmRlc2NyaXB0aXZlX251bWJlcixcbiAgICAgICAgYS5vcmllbnRhdGlvbmFsX251bWJlciwgYS5vcmllbnRhdGlvbmFsX251bWJlcl9sZXR0ZXIsIGMubmFtZSBBUyBjaXR5X25hbWUsXG4gICAgICAgIG0ubmFtZSBBUyBtdW5pY2lwYWxpdHlfcGFydF9uYW1lLCBwLm5hbWUgQVMgcHJhZ3VlX2Rpc3RyaWN0X25hbWUsXG4gICAgICAgIGQubmFtZSBBUyBkaXN0cmljdF9uYW1lLCBhLnBvc3RhbF9jb2RlLCBhLndnczg0X2xhdGl0dWRlLCBhLndnczg0X2xvbmdpdHVkZVxuICBGUk9NIGFkZHJlc3NfcG9pbnQgYVxuICBMRUZUIEpPSU4gc3RyZWV0IHMgT04gYS5zdHJlZXRfY29kZSA9IHMuY29kZVxuICBJTk5FUiBKT0lOIG9iamVjdF90eXBlIG8gT04gby5pZCA9IGEub2JqZWN0X3R5cGVfaWRcbiAgSU5ORVIgSk9JTiBjaXR5IGMgT04gYy5jb2RlID0gYS5jaXR5X2NvZGVcbiAgTEVGVCBKT0lOIGNpdHlfZGlzdHJpY3QgZCBPTiBhLmNpdHlfZGlzdHJpY3RfY29kZSA9IGQuY29kZVxuICBMRUZUIEpPSU4gcHJhZ3VlX2Rpc3RyaWN0IHAgT04gYS5wcmFndWVfZGlzdHJpY3RfY29kZSA9IHAuY29kZVxuICBMRUZUIEpPSU4gbXVuaWNpcGFsaXR5X3BhcnQgbSBPTiBhLm11bmljaXBhbGl0eV9wYXJ0X2NvZGUgPSBtLmNvZGVgO1xuXG5leHBvcnQgY29uc3QgZ2V0QWRkcmVzc1BvaW50QnlJZCA9IGFzeW5jIChcbiAgYWRkcmVzc1BvaW50SWQ6IG51bWJlclxuKTogUHJvbWlzZTxBZGRyZXNzUG9pbnQgfCBudWxsPiA9PiB7XG4gIGNvbnN0IHJvdyA9IGF3YWl0IHJhd1F1ZXJ5KFxuICAgIGAke2FkZHJlc3NQb2ludFNlbGVjdH1cbiAgICAgIFdIRVJFIGEuaWQgPSA/YCxcbiAgICBbYWRkcmVzc1BvaW50SWRdXG4gICk7XG4gIGlmIChyb3cubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgcmV0dXJuIHJvd1RvQWRkcmVzc1BvaW50KHJvd1swXSk7XG59O1xuXG5sZXQgbGFzdEZvdW5kZXI6IEZvdW5kZXIgfCBudWxsID0gbnVsbDtcbmxldCBhbGxTdHJlZXRzOiBzdHJpbmdbXSA9IFtdO1xuXG5leHBvcnQgY29uc3QgY2hlY2tTdHJlZXRFeGlzdHMgPSBhc3luYyAoXG4gIHN0cmVldE5hbWU6IHN0cmluZyxcbiAgZm91bmRlcjogRm91bmRlclxuKTogUHJvbWlzZTx7IGV4aXN0czogYm9vbGVhbjsgZXJyb3JzOiBTbWRFcnJvcltdIH0+ID0+IHtcbiAgY29uc3Qga25leCA9IGdldEtuZXhEYigpO1xuICBjb25zdCBlcnJvcnM6IFNtZEVycm9yW10gPSBbXTtcblxuICAvLyB3ZSBjaGVjayB0aGUgd2hvbGUgY2l0eVxuICBjb25zdCBjaXR5Q29kZSA9IGF3YWl0IGdldEZvdW5kZXJDaXR5Q29kZShcbiAgICBmb3VuZGVyLm11bmljaXBhbGl0eVR5cGUsXG4gICAgZm91bmRlci5tdW5pY2lwYWxpdHlDb2RlXG4gICk7XG4gIGNvbnN0IHJvd0xpc3QgPSBhd2FpdCByYXdRdWVyeShcbiAgICBgU0VMRUNUIG5hbWUgQVMgc3RyZWV0X25hbWVcbiAgICBGUk9NIHN0cmVldFxuICAgIFdIRVJFIGNpdHlfY29kZSA9ID8gQU5EIG5hbWUgPSA/ICAke1xuICAgICAgaXNTcWxpdGUoa25leCkgPyBcIkNPTExBVEUgTk9DQVNFXCIgOiBcIlwiXG4gICAgfWAsXG4gICAgW2NpdHlDb2RlLCBzdHJlZXROYW1lXVxuICApO1xuXG4gIGlmIChyb3dMaXN0Lmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCByb3cgPSByb3dMaXN0WzBdO1xuICAgIGlmIChyb3cuc3RyZWV0X25hbWUgIT09IHN0cmVldE5hbWUpIHtcbiAgICAgIC8vIGVycm9ycy5wdXNoKFxuICAgICAgLy8gICBgU3RyZWV0ICcke3N0cmVldE5hbWV9JyBoYXMgd3JvbmcgY2FzZSwgY29ycmVjdCBjYXNlOiAnJHtyb3cuc3RyZWV0X25hbWV9Jy5gXG4gICAgICAvLyApO1xuICAgIH1cbiAgICByZXR1cm4geyBleGlzdHM6IHRydWUsIGVycm9ycyB9O1xuICB9XG5cbiAgaWYgKGxhc3RGb3VuZGVyICE9PSBmb3VuZGVyKSB7XG4gICAgYWxsU3RyZWV0cyA9IGF3YWl0IGdldEFsbFN0cmVldHMoY2l0eUNvZGUpO1xuICAgIGxhc3RGb3VuZGVyID0gZm91bmRlcjtcbiAgfVxuXG4gIGNvbnN0IG1hdGNoID0gYWxsU3RyZWV0cy5maW5kKFxuICAgIChzKSA9PlxuICAgICAgcy50b0xvY2FsZUxvd2VyQ2FzZShcImNzLUNaXCIpID09PSBzdHJlZXROYW1lLnRvTG9jYWxlTG93ZXJDYXNlKFwiY3MtQ1pcIilcbiAgKTtcbiAgbGV0IGV4aXN0cyA9IGZhbHNlO1xuICBpZiAobWF0Y2gpIHtcbiAgICBleGlzdHMgPSB0cnVlO1xuICAgIGlmIChzdHJlZXROYW1lICE9PSBtYXRjaCkge1xuICAgICAgLy8gZXJyb3JzLnB1c2goXG4gICAgICAvLyAgIGBTdHJlZXQgJyR7c3RyZWV0TmFtZX0nIGhhcyB3cm9uZyBjYXNlLCBjb3JyZWN0IGNhc2U6ICcke21hdGNofScuYFxuICAgICAgLy8gKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgY2xvc2VzdCA9IGZpbmRDbG9zZXN0U3RyaW5nKHN0cmVldE5hbWUsIGFsbFN0cmVldHMpO1xuICAgIGVycm9ycy5wdXNoKHtcbiAgICAgIG1lc3NhZ2U6IGBVbGljZSAnJHtzdHJlZXROYW1lfScgdiB0w6l0byBvYmNpIG5lZXhpc3R1amUsIG15c2xlbGkganN0ZSAnJHtjbG9zZXN0fSc/YCxcbiAgICAgIHN0YXJ0T2Zmc2V0OiAwLFxuICAgICAgZW5kT2Zmc2V0OiBzdHJlZXROYW1lLmxlbmd0aCArIDEsXG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIHsgZXhpc3RzOiBmYWxzZSwgZXJyb3JzIH07XG59O1xuXG5jb25zdCBnZXRBbGxTdHJlZXRzID0gYXN5bmMgKGNpdHlDb2RlOiBudW1iZXIpOiBQcm9taXNlPHN0cmluZ1tdPiA9PiB7XG4gIGNvbnN0IGtuZXggPSBnZXRLbmV4RGIoKTtcbiAgcmV0dXJuIGF3YWl0IGtuZXgucGx1Y2soXCJuYW1lXCIpLmZyb20oXCJzdHJlZXRcIikud2hlcmUoXCJjaXR5X2NvZGVcIiwgY2l0eUNvZGUpO1xufTtcblxuZXhwb3J0IHR5cGUgRmluZEFkZHJlc3NQb2ludHNQYXJhbXMgPVxuICB8IHtcbiAgICAgIHR5cGU6IFwic21kTGluZVwiO1xuICAgICAgc21kTGluZTogU21kTGluZTtcbiAgICAgIG11bmljaXBhbGl0eTogTXVuaWNpcGFsaXR5O1xuICAgICAgbXVuaWNpcGFsaXR5UGFydENvZGU/OiBudW1iZXI7XG4gICAgfVxuICB8IHtcbiAgICAgIHR5cGU6IFwid2hvbGVNdW5pY2lwYWxpdHlQYXJ0XCI7XG4gICAgICBtdW5pY2lwYWxpdHlQYXJ0Q29kZTogbnVtYmVyO1xuICAgIH1cbiAgfCB7XG4gICAgICB0eXBlOiBcIndob2xlTXVuaWNpcGFsaXR5XCI7XG4gICAgICBtdW5pY2lwYWxpdHk6IE11bmljaXBhbGl0eTtcbiAgICB9XG4gIHwge1xuICAgICAgdHlwZTogXCJ3aG9sZU11bmljaXBhbGl0eU5vU3RyZWV0TmFtZVwiO1xuICAgICAgbXVuaWNpcGFsaXR5OiBNdW5pY2lwYWxpdHk7XG4gICAgfTtcblxuZXhwb3J0IGNvbnN0IGZpbmRBZGRyZXNzUG9pbnRzID0gYXN5bmMgKFxuICBwYXJhbXM6IEZpbmRBZGRyZXNzUG9pbnRzUGFyYW1zXG4pOiBQcm9taXNlPEFkZHJlc3NQb2ludFtdPiA9PiB7XG4gIGNvbnN0IHF1ZXJ5UGFyYW1zID0gZ2V0UXVlcnlQYXJhbXMocGFyYW1zKTtcbiAgY29uc3Qgc3RyZWV0Sm9pbkNvbmRpdGlvbiA9IGdldFN0cmVldEpvaW5Db25kaXRpb24ocGFyYW1zKTtcblxuICBjb25zdCB3aGVyZUNvbmRpdGlvbiA9IGdldFdoZXJlQ29uZGl0aW9uKHBhcmFtcyk7XG5cbiAgY29uc3QgcXVlcnlSZXN1bHQgPSBhd2FpdCByYXdRdWVyeShcbiAgICBgU0VMRUNUIGEuaWQsIHMubmFtZSBBUyBzdHJlZXRfbmFtZSwgby5uYW1lIEFTIG9iamVjdF90eXBlX25hbWUsIGEuZGVzY3JpcHRpdmVfbnVtYmVyLFxuICAgICAgYS5vcmllbnRhdGlvbmFsX251bWJlciwgYS5vcmllbnRhdGlvbmFsX251bWJlcl9sZXR0ZXIsIGMubmFtZSBBUyBjaXR5X25hbWUsXG4gICAgICBkLm5hbWUgQVMgZGlzdHJpY3RfbmFtZSwgbS5uYW1lIEFTIG11bmljaXBhbGl0eV9wYXJ0X25hbWUsIHAubmFtZSBBUyBwcmFndWVfZGlzdHJpY3RfbmFtZSxcbiAgICAgIGEucG9zdGFsX2NvZGUsIGEud2dzODRfbGF0aXR1ZGUsIGEud2dzODRfbG9uZ2l0dWRlXG4gICAgRlJPTSBhZGRyZXNzX3BvaW50IGFcbiAgICAke3N0cmVldEpvaW5Db25kaXRpb259XG4gICAgSU5ORVIgSk9JTiBvYmplY3RfdHlwZSBvIE9OIG8uaWQgPSBhLm9iamVjdF90eXBlX2lkXG4gICAgSU5ORVIgSk9JTiBjaXR5IGMgT04gYy5jb2RlID0gYS5jaXR5X2NvZGVcbiAgICBMRUZUIEpPSU4gY2l0eV9kaXN0cmljdCBkIE9OIGEuY2l0eV9kaXN0cmljdF9jb2RlID0gZC5jb2RlXG4gICAgTEVGVCBKT0lOIG11bmljaXBhbGl0eV9wYXJ0IG0gT04gYS5tdW5pY2lwYWxpdHlfcGFydF9jb2RlID0gbS5jb2RlXG4gICAgTEVGVCBKT0lOIHByYWd1ZV9kaXN0cmljdCBwIE9OIGEucHJhZ3VlX2Rpc3RyaWN0X2NvZGUgPSBwLmNvZGVcbiAgICBXSEVSRSAke3doZXJlQ29uZGl0aW9ufWAsXG4gICAgcXVlcnlQYXJhbXNcbiAgKTtcblxuICByZXR1cm4gZmlsdGVyQWRkcmVzc1BvaW50cyhxdWVyeVJlc3VsdC5tYXAocm93VG9BZGRyZXNzUG9pbnQpLCBwYXJhbXMpO1xufTtcblxuZXhwb3J0IGNvbnN0IGZpbHRlckFkZHJlc3NQb2ludHMgPSAoXG4gIGFkZHJlc3NQb2ludHM6IEFkZHJlc3NQb2ludFtdLFxuICBwYXJhbXM6IEZpbmRBZGRyZXNzUG9pbnRzUGFyYW1zXG4pOiBBZGRyZXNzUG9pbnRbXSA9PiB7XG4gIGlmIChcbiAgICBwYXJhbXMudHlwZSA9PT0gXCJ3aG9sZU11bmljaXBhbGl0eVwiIHx8XG4gICAgcGFyYW1zLnR5cGUgPT09IFwid2hvbGVNdW5pY2lwYWxpdHlOb1N0cmVldE5hbWVcIiB8fFxuICAgIHBhcmFtcy50eXBlID09PSBcIndob2xlTXVuaWNpcGFsaXR5UGFydFwiXG4gICkge1xuICAgIHJldHVybiBhZGRyZXNzUG9pbnRzO1xuICB9XG5cbiAgY29uc3QgcmVzdWx0OiBBZGRyZXNzUG9pbnRbXSA9IFtdO1xuICBjb25zdCBudW1iZXJTcGVjID0gcGFyYW1zLnNtZExpbmUubnVtYmVyU3BlYztcbiAgaWYgKGlzU2VyaWVzU3BlY0FycmF5KG51bWJlclNwZWMpKSB7XG4gICAgbnVtYmVyU3BlYy5mb3JFYWNoKChzZXJpZXNTcGVjKSA9PiB7XG4gICAgICByZXN1bHQucHVzaCguLi5maWx0ZXJBZGRyZXNzUG9pbnRzQnlSYW5nZXMoYWRkcmVzc1BvaW50cywgc2VyaWVzU3BlYykpO1xuICAgIH0pO1xuXG4gICAgLy8gd2hlbiBubyBudW1iZXIgc3BlY3MgYXJlIHByZXNlbnQsIHdlIHRha2UgZXZlcnl0aGluZ1xuICAgIGlmIChudW1iZXJTcGVjLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmVzdWx0LnB1c2goLi4uYWRkcmVzc1BvaW50cyk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGlzTmVnYXRpdmVTZXJpZXNTcGVjKG51bWJlclNwZWMpKSB7XG4gICAgLy8gbmVnYXRpdmUgbnVtYmVyIHNwZWMgKGUuZy4gb2RkIG51bWJlcnMgZXhjZXB0IDEzLTE3KVxuICAgIGNvbnN0IHRvRXhjbHVkZSA9IGZpbHRlckFkZHJlc3NQb2ludHNCeVJhbmdlcyhhZGRyZXNzUG9pbnRzLCBudW1iZXJTcGVjKTtcbiAgICByZXN1bHQucHVzaChcbiAgICAgIC4uLmFkZHJlc3NQb2ludHMuZmlsdGVyKFxuICAgICAgICAoYWRkcmVzc1BvaW50KSA9PiAhdG9FeGNsdWRlLmluY2x1ZGVzKGFkZHJlc3NQb2ludClcbiAgICAgIClcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbmNvbnN0IGZpbHRlckFkZHJlc3NQb2ludHNCeVJhbmdlcyA9IChcbiAgYWRkcmVzc1BvaW50czogQWRkcmVzc1BvaW50W10sXG4gIHNlcmllc1NwZWM6IFNlcmllc1NwZWNcbik6IEFkZHJlc3NQb2ludFtdID0+IHtcbiAgY29uc3QgcmVzdWx0OiBBZGRyZXNzUG9pbnRbXSA9IFtdO1xuICBzZXJpZXNTcGVjLnJhbmdlcy5mb3JFYWNoKChyYW5nZSkgPT4ge1xuICAgIHJlc3VsdC5wdXNoKFxuICAgICAgLi4uYWRkcmVzc1BvaW50cy5maWx0ZXIoKGFkZHJlc3NQb2ludCkgPT4ge1xuICAgICAgICBpZiAoaXNSYW5nZShyYW5nZSkpIHtcbiAgICAgICAgICBjb25zdCBudW1iZXIgPSBnZXROdW1iZXJCeVR5cGUoc2VyaWVzU3BlYy50eXBlLCBhZGRyZXNzUG9pbnQpO1xuICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBpc0luUmFuZ2UoXG4gICAgICAgICAgICAgIG51bWJlcixcbiAgICAgICAgICAgICAgc2VyaWVzU3BlYy50eXBlICE9PSBTZXJpZXNUeXBlLkRlc2NyaXB0aW9uXG4gICAgICAgICAgICAgICAgPyBhZGRyZXNzUG9pbnQub3JpZW50YXRpb25hbE51bWJlckxldHRlciA/PyBudWxsXG4gICAgICAgICAgICAgICAgOiBudWxsLFxuICAgICAgICAgICAgICByYW5nZVxuICAgICAgICAgICAgKSAmJiBmaXRzVHlwZShudW1iZXIsIHNlcmllc1NwZWMudHlwZSlcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnN0IGZ1bGxTdHJlZXROdW1iZXI6IEZ1bGxTdHJlZXROdW1iZXIgPSByYW5nZTtcbiAgICAgICAgICByZXR1cm4gZXF1YWxzRnVsbFN0cmVldE51bWJlcihmdWxsU3RyZWV0TnVtYmVyLCBhZGRyZXNzUG9pbnQpO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICk7XG4gIH0pO1xuXG4gIC8vIHdoZW4gbm8gc2VyaWVzIHNwZWNzIGFyZSBwcmVzZW50LCB3ZSB0YWtlIGV2ZXJ5dGhpbmcgdGhhdCBmaXRzIHRoZSB0eXBlXG4gIGlmIChzZXJpZXNTcGVjLnJhbmdlcy5sZW5ndGggPT09IDApIHtcbiAgICByZXN1bHQucHVzaChcbiAgICAgIC4uLmFkZHJlc3NQb2ludHMuZmlsdGVyKChhZGRyZXNzUG9pbnQpID0+XG4gICAgICAgIGZpdHNUeXBlKFxuICAgICAgICAgIGdldE51bWJlckJ5VHlwZShzZXJpZXNTcGVjLnR5cGUsIGFkZHJlc3NQb2ludCksXG4gICAgICAgICAgc2VyaWVzU3BlYy50eXBlXG4gICAgICAgIClcbiAgICAgIClcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRRdWVyeVBhcmFtcyA9IChcbiAgcGFyYW1zOiBGaW5kQWRkcmVzc1BvaW50c1BhcmFtc1xuKTogKHN0cmluZyB8IG51bWJlcilbXSA9PiB7XG4gIGlmIChwYXJhbXMudHlwZSA9PT0gXCJzbWRMaW5lXCIgJiYgcGFyYW1zLnNtZExpbmUudHlwZSA9PT0gXCJzdHJlZXRcIikge1xuICAgIHJldHVybiBbcGFyYW1zLnNtZExpbmUuc3RyZWV0LCBwYXJhbXMubXVuaWNpcGFsaXR5LmNvZGVdO1xuICB9XG5cbiAgaWYgKFxuICAgIChwYXJhbXMudHlwZSA9PT0gXCJzbWRMaW5lXCIgJiYgcGFyYW1zLnNtZExpbmUudHlwZSA9PT0gXCJtdW5pY2lwYWxpdHlQYXJ0XCIpIHx8XG4gICAgcGFyYW1zLnR5cGUgPT09IFwid2hvbGVNdW5pY2lwYWxpdHlQYXJ0XCJcbiAgKSB7XG4gICAgcmV0dXJuIFtwYXJhbXMubXVuaWNpcGFsaXR5UGFydENvZGVdO1xuICB9XG5cbiAgcmV0dXJuIFtwYXJhbXMubXVuaWNpcGFsaXR5LmNvZGVdO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldFN0cmVldEpvaW5Db25kaXRpb24gPSAoXG4gIHBhcmFtczogRmluZEFkZHJlc3NQb2ludHNQYXJhbXNcbik6IHN0cmluZyA9PiB7XG4gIGlmIChwYXJhbXMudHlwZSA9PT0gXCJzbWRMaW5lXCIgJiYgcGFyYW1zLnNtZExpbmUudHlwZSA9PT0gXCJzdHJlZXRcIikge1xuICAgIHJldHVybiBgSk9JTiBzdHJlZXQgcyBPTiBhLnN0cmVldF9jb2RlID0gcy5jb2RlIEFORCBzLm5hbWUgPSA/ICR7XG4gICAgICBpc1NxbGl0ZShnZXRLbmV4RGIoKSkgPyBcIkNPTExBVEUgTk9DQVNFXCIgOiBcIlwiXG4gICAgfWA7XG4gIH1cbiAgcmV0dXJuIFwiTEVGVCBKT0lOIHN0cmVldCBzIE9OIGEuc3RyZWV0X2NvZGUgPSBzLmNvZGVcIjtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRXaGVyZUNvbmRpdGlvbiA9IChwYXJhbXM6IEZpbmRBZGRyZXNzUG9pbnRzUGFyYW1zKTogc3RyaW5nID0+IHtcbiAgaWYgKFxuICAgIChwYXJhbXMudHlwZSA9PT0gXCJzbWRMaW5lXCIgJiYgcGFyYW1zLnNtZExpbmUudHlwZSA9PT0gXCJtdW5pY2lwYWxpdHlQYXJ0XCIpIHx8XG4gICAgcGFyYW1zLnR5cGUgPT09IFwid2hvbGVNdW5pY2lwYWxpdHlQYXJ0XCJcbiAgKSB7XG4gICAgcmV0dXJuIFwiYS5tdW5pY2lwYWxpdHlfcGFydF9jb2RlID0gP1wiO1xuICB9XG5cbiAgaWYgKHBhcmFtcy50eXBlID09PSBcIndob2xlTXVuaWNpcGFsaXR5Tm9TdHJlZXROYW1lXCIpIHtcbiAgICByZXR1cm4gYCR7Z2V0TXVuaWNpcGFsaXR5V2hlcmUoXG4gICAgICBcImFcIixcbiAgICAgIHBhcmFtcy5tdW5pY2lwYWxpdHlcbiAgICApfSBBTkQgYS5zdHJlZXRfY29kZSBJUyBOVUxMYDtcbiAgfVxuXG4gIHJldHVybiBnZXRNdW5pY2lwYWxpdHlXaGVyZShcImFcIiwgcGFyYW1zLm11bmljaXBhbGl0eSk7XG59O1xuXG5leHBvcnQgY29uc3QgaXNJblJhbmdlID0gKFxuICBudW1iZXI6IG51bWJlciB8IG51bGwsXG4gIGxldHRlcjogc3RyaW5nIHwgbnVsbCxcbiAgcmFuZ2U6IFJhbmdlU3BlY1xuKTogYm9vbGVhbiA9PiB7XG4gIGlmIChudW1iZXIgPT09IG51bGwpIHtcbiAgICByZXR1cm4gIXJhbmdlLmZyb20gJiYgIXJhbmdlLnRvO1xuICB9XG5cbiAgLy8gZXhwbGFpbmVyOiBlaXRoZXIgdGhlIGxvd2VyIGJvdW5kIGlzIG5vdCBzZXQsIG9yIGl0IGlzIGxvd2VyIHRoYW4gdGhlIG51bWJlclxuICAvLyBpZiBpdCdzIGVxdWFsIHRvIHRoZSBudW1iZXIsIHdlIGFsc28gaGF2ZSB0byBjaGVjayB0aGUgbGV0dGVyIC0gaWYgaXQncyBub3Qgc2V0LCB3ZSBkb24ndCBjYXJlXG4gIC8vIGlmIGZyb20ubGV0dGVyIGlzIHNldCwgd2UgbmVlZCB0byBoYXZlIGEgbGV0dGVyIHNldCBhbmQgaXQgaGFzIHRvIGJlIGdyZWF0ZXIgb3IgZXF1YWw6XG4gIC8vIG51bWJlciB3aXRob3V0IGxldHRlciBjb3VudHMgbG93ZXIgdGhhbiBudW1iZXIgd2l0aCBsZXR0ZXIgJ2EnIChlLmcuIDIzIDwgMjNhKVxuICBjb25zdCBzYXRpc2ZpZXNGcm9tID1cbiAgICAhcmFuZ2UuZnJvbSB8fFxuICAgIG51bWJlciA+IHJhbmdlLmZyb20ubnVtYmVyIHx8XG4gICAgKG51bWJlciA9PT0gcmFuZ2UuZnJvbS5udW1iZXIgJiZcbiAgICAgICghcmFuZ2UuZnJvbS5sZXR0ZXIgfHwgKCEhbGV0dGVyICYmIGxldHRlciA+PSByYW5nZS5mcm9tLmxldHRlcikpKTtcblxuICBjb25zdCBzYXRpc2ZpZXNUbyA9XG4gICAgIXJhbmdlLnRvIHx8XG4gICAgbnVtYmVyIDwgcmFuZ2UudG8ubnVtYmVyIHx8XG4gICAgKG51bWJlciA9PT0gcmFuZ2UudG8ubnVtYmVyICYmXG4gICAgICAoIWxldHRlciB8fFxuICAgICAgICAoISFyYW5nZS50by5sZXR0ZXIgJiYgISFsZXR0ZXIgJiYgbGV0dGVyIDw9IHJhbmdlLnRvLmxldHRlcikpKTtcblxuICByZXR1cm4gc2F0aXNmaWVzRnJvbSAmJiBzYXRpc2ZpZXNUbztcbn07XG5cbmV4cG9ydCBjb25zdCBmaXRzVHlwZSA9IChudW1iZXI6IG51bWJlciB8IG51bGwsIHR5cGU6IFNlcmllc1R5cGUpOiBib29sZWFuID0+IHtcbiAgcmV0dXJuIChcbiAgICB0eXBlID09PSBTZXJpZXNUeXBlLkRlc2NyaXB0aW9uIHx8XG4gICAgdHlwZSA9PT0gU2VyaWVzVHlwZS5BbGwgfHxcbiAgICAvLyBhIG1pc3NpbmcgbnVtYmVyIChlLmcuIG5vIG9yaWVudGF0aW9uYWwgbnVtYmVyKSBpcyBuZWl0aGVyIG9kZCBub3IgZXZlbixcbiAgICAvLyBjYXJlZnVsOiBudWxsICUgMiA9PT0gMCBpbiBKU1xuICAgICh0eXBlID09PSBTZXJpZXNUeXBlLk9kZCAmJiBudW1iZXIgIT09IG51bGwgJiYgbnVtYmVyICUgMiA9PT0gMSkgfHxcbiAgICAodHlwZSA9PT0gU2VyaWVzVHlwZS5FdmVuICYmIG51bWJlciAhPT0gbnVsbCAmJiBudW1iZXIgJSAyID09PSAwKVxuICApO1xufTtcblxuZXhwb3J0IGNvbnN0IGVxdWFsc0Z1bGxTdHJlZXROdW1iZXIgPSAoXG4gIGZ1bGxTdHJlZXROdW1iZXI6IEZ1bGxTdHJlZXROdW1iZXIsXG4gIGFkZHJlc3NQb2ludDogQWRkcmVzc1BvaW50XG4pOiBib29sZWFuID0+IHtcbiAgcmV0dXJuIChcbiAgICBmdWxsU3RyZWV0TnVtYmVyLmRlc2NyaXB0aW9uTnVtYmVyLm51bWJlciA9PT0gYWRkcmVzc1BvaW50LmhvdXNlTnVtYmVyICYmXG4gICAgZnVsbFN0cmVldE51bWJlci5vcmllbnRhdGlvbmFsTnVtYmVyLm51bWJlciA9PT1cbiAgICAgIGFkZHJlc3NQb2ludC5vcmllbnRhdGlvbmFsTnVtYmVyICYmXG4gICAgKCghZnVsbFN0cmVldE51bWJlci5vcmllbnRhdGlvbmFsTnVtYmVyLmxldHRlciAmJlxuICAgICAgIWFkZHJlc3NQb2ludC5vcmllbnRhdGlvbmFsTnVtYmVyTGV0dGVyKSB8fFxuICAgICAgZnVsbFN0cmVldE51bWJlci5vcmllbnRhdGlvbmFsTnVtYmVyLmxldHRlciA9PT1cbiAgICAgICAgYWRkcmVzc1BvaW50Lm9yaWVudGF0aW9uYWxOdW1iZXJMZXR0ZXIpXG4gICk7XG59O1xuXG5jb25zdCBnZXROdW1iZXJCeVR5cGUgPSAoXG4gIHR5cGU6IFNlcmllc1R5cGUsXG4gIGFkZHJlc3NQb2ludDogQWRkcmVzc1BvaW50XG4pOiBudW1iZXIgfCBudWxsID0+IHtcbiAgcmV0dXJuIHR5cGUgPT09IFNlcmllc1R5cGUuRGVzY3JpcHRpb25cbiAgICA/IGFkZHJlc3NQb2ludC5ob3VzZU51bWJlclxuICAgIDogYWRkcmVzc1BvaW50Lm9yaWVudGF0aW9uYWxOdW1iZXIgPz8gbnVsbDtcbn07XG5cbmNvbnN0IGdldE11bmljaXBhbGl0eVdoZXJlID0gKFxuICBhbGlhczogc3RyaW5nLFxuICBtdW5pY2lwYWxpdHk6IE11bmljaXBhbGl0eVxuKTogc3RyaW5nID0+IHtcbiAgcmV0dXJuIG11bmljaXBhbGl0eS50eXBlID09PSBNdW5pY2lwYWxpdHlUeXBlLkNpdHlcbiAgICA/IGAke2FsaWFzfS5jaXR5X2NvZGUgPSA/YFxuICAgIDogYCR7YWxpYXN9LmNpdHlfZGlzdHJpY3RfY29kZSA9ID9gO1xufTtcblxuY29uc3Qgcm93VG9BZGRyZXNzUG9pbnQgPSAocm93OiBhbnkpOiBBZGRyZXNzUG9pbnQgPT4ge1xuICBjb25zdCBwb2ludDogQWRkcmVzc1BvaW50ID0ge1xuICAgIGlkOiByb3cuaWQsXG4gICAgYWRkcmVzczogXCJcIixcbiAgICB0eXBlOlxuICAgICAgcm93Lm9iamVjdF90eXBlX25hbWUgPT09IERlc2NyaXB0aXZlVHlwZVxuICAgICAgICA/IEFkZHJlc3NQb2ludFR5cGUuRGVzY3JpcHRpb25cbiAgICAgICAgOiBBZGRyZXNzUG9pbnRUeXBlLlJlZ2lzdHJhdGlvbixcbiAgICBob3VzZU51bWJlcjogcm93LmRlc2NyaXB0aXZlX251bWJlcixcbiAgICBjaXR5OiByb3cuY2l0eV9uYW1lLFxuICAgIG11bmljaXBhbGl0eVBhcnQ6IHJvdy5tdW5pY2lwYWxpdHlfcGFydF9uYW1lLFxuICAgIHBvc3RhbENvZGU6IHJvdy5wb3N0YWxfY29kZSxcbiAgICBsYXQ6IHJvdy53Z3M4NF9sYXRpdHVkZSxcbiAgICBsbmc6IHJvdy53Z3M4NF9sb25naXR1ZGUsXG4gIH07XG4gIGlmIChyb3cuc3RyZWV0X25hbWUgIT09IG51bGwpIHtcbiAgICBwb2ludC5zdHJlZXQgPSByb3cuc3RyZWV0X25hbWU7XG4gIH1cbiAgaWYgKHJvdy5vcmllbnRhdGlvbmFsX251bWJlciAhPT0gbnVsbCkge1xuICAgIHBvaW50Lm9yaWVudGF0aW9uYWxOdW1iZXIgPSByb3cub3JpZW50YXRpb25hbF9udW1iZXI7XG4gIH1cbiAgaWYgKHJvdy5vcmllbnRhdGlvbmFsX251bWJlcl9sZXR0ZXIgIT09IG51bGwpIHtcbiAgICBwb2ludC5vcmllbnRhdGlvbmFsTnVtYmVyTGV0dGVyID0gcm93Lm9yaWVudGF0aW9uYWxfbnVtYmVyX2xldHRlcjtcbiAgfVxuICBpZiAocm93LmRpc3RyaWN0X25hbWUgIT09IG51bGwpIHtcbiAgICBwb2ludC5kaXN0cmljdCA9IHJvdy5kaXN0cmljdF9uYW1lO1xuICB9XG4gIGlmIChyb3cucHJhZ3VlX2Rpc3RyaWN0X25hbWUgIT09IG51bGwpIHtcbiAgICBwb2ludC5wcmFndWVEaXN0cmljdCA9IHJvdy5wcmFndWVfZGlzdHJpY3RfbmFtZTtcbiAgfVxuICBwb2ludC5hZGRyZXNzID0gY3JlYXRlU2luZ2xlTGluZUFkZHJlc3MocG9pbnQpO1xuICByZXR1cm4gcG9pbnQ7XG59O1xuIl19
|