@whiteslove/parsing-lexicon 0.6.14 → 0.6.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/package.json +1 -1
  2. package/src/housing-address.js +6 -0
  3. package/src/housing-card-fields.js +1 -1
  4. package/src/housing-listing-enrichment.d.ts +4 -1
  5. package/src/housing-listing-enrichment.js +6 -4
  6. package/src/housing-listing-fields.d.ts +1 -1
  7. package/src/housing-listing-fields.js +17 -4
  8. package/src/housing-money.js +9 -0
  9. package/src/housing-structured.js +9 -3
  10. package/src/housing-text.js +2 -1
  11. package/src/kg-bishkek-area-extensions.js +17 -0
  12. package/src/kg-bishkek-residential-extensions.js +15 -0
  13. package/src/kg-bishkek-street-extensions.js +16 -1
  14. package/src/locations-runtime.js +47 -1
  15. package/src/ua-chernihiv-street-extensions.js +12 -0
  16. package/src/ua-dnipro-street-extensions.js +14 -0
  17. package/src/ua-kharkiv-location-translations.js +2 -0
  18. package/src/ua-kharkiv-microdistrict-extensions.js +1 -0
  19. package/src/ua-kharkiv-street-extensions.js +16 -0
  20. package/src/ua-kryvyi-rih-street-extensions.js +51 -0
  21. package/src/ua-kyiv-street-extensions.js +9 -0
  22. package/src/ua-mykolaiv-street-extensions.js +20 -0
  23. package/src/ua-vinnytsia-street-extensions.js +28 -0
  24. package/src/ua-zaporizhzhia-street-extensions.js +46 -0
  25. package/src/uz-andijan-street-extensions.js +22 -0
  26. package/src/uz-bukhara-location-extensions.js +22 -0
  27. package/src/uz-fergana-street-extensions.js +16 -0
  28. package/src/uz-namangan-street-extensions.js +27 -0
  29. package/src/uz-nukus-street-extensions.js +28 -0
  30. package/src/uz-qarshi-street-extensions.js +25 -0
  31. package/src/uz-samarkand-context-extensions.js +10 -1
  32. package/src/uz-tashkent-context-extensions.js +37 -1
  33. package/src/uz-tashkent-reviewed-residential-extensions.js +30 -0
  34. package/src/uz-tashkent-reviewed-street-extensions.js +34 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whiteslove/parsing-lexicon",
3
- "version": "0.6.14",
3
+ "version": "0.6.16",
4
4
  "description": "Shared deterministic multilingual parsing lexicon for WhitesLove housing and hiring services",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,6 +39,12 @@ function compactStreet(value) {
39
39
  // "проживания" -> "оживания").
40
40
  .replace(new RegExp(`^${PREFIX_STREET_MARKER}(?!\\p{L})\\s*`, 'iu'), '')
41
41
  .replace(new RegExp(`\\s+${POSTFIX_STREET_MARKER}$`, 'iu'), '')
42
+ // OCR frequently substitutes “оя” for the Ukrainian/Russian “ля” in
43
+ // “шлях”; correct the street-token typo before canonical lookup.
44
+ .replace(/(?<!\p{L})шоях(?!\p{L})/giu, 'шлях')
45
+ // Listings commonly abbreviate this Kharkiv street to an initial and
46
+ // surname; expand it so address-only consumers do not retain just “Л”.
47
+ .replace(/(?<!\p{L})л\s*\.\s*малой(?!\p{L})/giu, 'Любови Малой')
42
48
  .replace(/[\s,;:.\-–—]+$/gu, '')
43
49
  .trim() || null;
44
50
  }
@@ -51,7 +51,7 @@ function enumeratedNearby(text) {
51
51
  const items = [];
52
52
  for (const item of blocks.join(', ').split(/[,;•·|]+/).map((part) => part
53
53
  .replace(/\s{2,}/g, ' ')
54
- .replace(/^[\s\-–—.]+|[\s\-–—.!]+$/g, '')
54
+ .replace(/^[\s\-–—."'«»“”„]+|[\s\-–—.!"'«»“”„]+$/g, '')
55
55
  .trim())) {
56
56
  if (item.length < 3 || item.length > 45 || NEARBY_NOISE_RE.test(item) || NEARBY_FILLER_RE.test(item)) continue;
57
57
  if (!/\p{L}{3,}/u.test(item)) continue;
@@ -71,4 +71,7 @@ export function parseHousingCommissionAmount(value: unknown): HousingCommissionA
71
71
  export function parseHousingPerPersonPrice(value: unknown, options?: { country?: string }): HousingPerPersonPrice | null;
72
72
  export function parseHousingTransitRoutes(value: unknown): readonly string[];
73
73
  export function parseHousingObservedAmenities(value: unknown): readonly string[];
74
- export function parseHousingListingEnrichment(value: unknown, options?: { country?: string }): Readonly<HousingListingEnrichment>;
74
+ export function parseHousingListingEnrichment(
75
+ value: unknown,
76
+ options?: { country?: string; dealType?: 'sale' | 'longRent' | 'shortRent' | null },
77
+ ): Readonly<HousingListingEnrichment>;
@@ -9,6 +9,7 @@ import { parseHousingListingFields } from './housing-listing-fields.js';
9
9
  import { parseHousingResidentialComplex } from './housing-text.js';
10
10
  import { parseHousingAddress } from './housing-address.js';
11
11
  import { HOUSING_LANDMARK_EXTENSIONS, HOUSING_POI_EXTENSIONS } from './housing-poi-extensions.js';
12
+ import { resolveHousingIntent } from './housing-intent.js';
12
13
 
13
14
  const GENERIC_CATEGORY = Object.freeze({
14
15
  Park: 'park', Metro: 'metro', 'Bus stop': 'transport', 'Public transport': 'transport', 'Main road': 'transport',
@@ -229,10 +230,11 @@ function walkMinutes(text) {
229
230
  return Number.isInteger(value) && value > 0 && value <= 180 ? value : null;
230
231
  }
231
232
 
232
- export function parseHousingListingEnrichment(value, { country = '' } = {}) {
233
+ export function parseHousingListingEnrichment(value, { country = '', dealType = null } = {}) {
233
234
  const text = normalizeUnicode(value ?? '');
234
235
  if (!text) return deepFreeze({});
235
- const listingFields = parseHousingListingFields(text, { country });
236
+ const resolvedDealType = dealType || resolveHousingIntent(text)?.dealType || null;
237
+ const listingFields = parseHousingListingFields(text, { country, dealType: resolvedDealType });
236
238
  const floor = parseHousingFloor(text);
237
239
  const areas = parseHousingAreas(text);
238
240
  const audience = parseHousingAudience(text);
@@ -271,7 +273,7 @@ export function parseHousingListingEnrichment(value, { country = '' } = {}) {
271
273
  euroLayout: listingFields.euroLayout ?? null,
272
274
  gas: listingFields.gas ?? null,
273
275
  newBuilding: listingFields.newBuilding ?? null,
274
- communalSeparated: listingFields.communalSeparated ?? null,
276
+ communalSeparated: resolvedDealType === 'sale' ? null : (listingFields.communalSeparated ?? null),
275
277
  parking: listingFields.parking ?? null,
276
278
  elevator: listingFields.elevator ?? null,
277
279
  heating: listingFields.heating ?? null,
@@ -284,7 +286,7 @@ export function parseHousingListingEnrichment(value, { country = '' } = {}) {
284
286
  furnished: listingFields.furnished ?? null,
285
287
  deposit: listingFields.depositRequired ?? null,
286
288
  firstRental: firstRental(text, listingFields),
287
- utilitiesAmount: listingFields.utilitiesAmount ?? null,
289
+ utilitiesAmount: resolvedDealType === 'sale' ? null : (listingFields.utilitiesAmount ?? null),
288
290
  commission,
289
291
  commissionPercent: commission === false ? 0 : null,
290
292
  commissionAmount,
@@ -53,5 +53,5 @@ export type HousingListingFields = Readonly<{
53
53
  */
54
54
  export function parseHousingListingFields(
55
55
  value: unknown,
56
- options?: { country?: string },
56
+ options?: { country?: string; dealType?: 'sale' | 'longRent' | 'shortRent' | null },
57
57
  ): Readonly<Partial<HousingListingFields>>;
@@ -2,6 +2,7 @@ import { deepFreeze } from './lexicon-core.js';
2
2
  import { normalizeUnicode } from './normalization.js';
3
3
  import { parseHousingContext } from './housing-context.js';
4
4
  import { parseHousingFeatures } from './housing-features.js';
5
+ import { resolveHousingIntent } from './housing-intent.js';
5
6
 
6
7
  const bool = (text, positive, negative = null) => {
7
8
  if (negative?.test(text)) return false;
@@ -69,6 +70,11 @@ function parseAvailableFrom(text) {
69
70
  const match = text.match(/(?:доступн\p{L}*\s+с|свободн\p{L}*\s+с|заселени\p{L}*\s+с|заезд\s+с|available\s+from|move[- ]?in\s+from)\s*[:\-]?\s*((?:\d{1,2}[./-]\d{1,2}(?:[./-]\d{2,4})?)|(?:\d{1,2}\s+[\p{L}]{3,12}(?:\s+\d{4})?))/iu);
70
71
  if (match?.[1]) return match[1].trim();
71
72
 
73
+ // Ukrainian listings commonly phrase this as “move-in is possible only
74
+ // from …”, rather than using the shorter “available from …” form.
75
+ const ukrainianMoveIn = text.match(/(?:перегляд\s+(?:і|та)\s+)?заселен\p{L}*\s+можлив\p{L}*(?:\s+лише)?\s+з\s*((?:\d{1,2}[./-]\d{1,2}(?:[./-]\d{2,4})?)|(?:\d{1,2}\s+[\p{L}]{3,12}(?:\s+\d{4})?))/iu);
76
+ if (ukrainianMoveIn?.[1]) return ukrainianMoveIn[1].trim();
77
+
72
78
  // Uzbek listings commonly attach the ablative suffix directly to the month:
73
79
  // "1-sentyabrdan beriladi" / "1-сентябрдан берилади".
74
80
  const uzbek = text.match(/(\d{1,2}\s*[-./]?\s*[\p{L}]{3,12})(?:dan|дан)(?=$|[^\p{L}\p{N}_])[^.\r\n]{0,32}(?:beriladi|берилади|bo['’]?sh|бўш)/iu);
@@ -76,7 +82,9 @@ function parseAvailableFrom(text) {
76
82
  }
77
83
 
78
84
  function parseUtilitiesAmount(text) {
79
- const match = text.match(/(?:коммунальн\p{L}*|коммуналк\p{L}*|ком\.?\s*услуг\p{L}*|utilities?|bills?)\D{0,24}(?:около|примерно|~|≈)?\s*(\d{2,8}(?:[.,]\d{1,2})?)\s*(₴|грн|uah|\$|usd|€|eur|сум|uzs|тг|kzt|lei|ron|руб|rub)?/iu);
85
+ // Do not bridge a sentence boundary. Otherwise “plus utilities. Tel. 06…”
86
+ // turns the first phone digits into a fictitious utility bill.
87
+ const match = text.match(/(?:коммунальн\p{L}*|коммуналк\p{L}*|ком\.?\s*услуг\p{L}*|utilities?|bills?)[^\d.;!?…\r\n]{0,24}(?:около|примерно|~|≈)?\s*(\d{2,8}(?:[.,]\d{1,2})?)\s*(₴|грн|uah|\$|usd|€|eur|сум|uzs|тг|kzt|lei|ron|руб|rub)?/iu);
80
88
  if (!match) return null;
81
89
  const amount = Number(match[1].replace(',', '.'));
82
90
  if (!Number.isFinite(amount) || amount <= 0) return null;
@@ -103,11 +111,16 @@ function parseDepositRequired(text) {
103
111
  return null;
104
112
  }
105
113
 
106
- export function parseHousingListingFields(value, { country = '' } = {}) {
114
+ export function parseHousingListingFields(value, { country = '', dealType = null } = {}) {
107
115
  const text = normalizeUnicode(value ?? '');
108
116
  const context = parseHousingContext(text);
109
117
  const features = parseHousingFeatures(text);
110
118
  if (!text) return deepFreeze({});
119
+ // Utility billing is a rental-only concept. A source may carry a generic
120
+ // payment-table value on every listing, including sales, so never let that
121
+ // value become a persisted housing attribute for a sale.
122
+ const resolvedDealType = dealType || resolveHousingIntent(text)?.dealType || null;
123
+ const isSale = resolvedDealType === 'sale';
111
124
 
112
125
  const gas = bool(text,
113
126
  /(?:^|[^\p{L}\p{N}_])(?:газ|gaz|gas)(?=$|[^\p{L}\p{N}_])|метан|aragaz|gaz\s+ta['’]?min/iu,
@@ -211,7 +224,7 @@ export function parseHousingListingFields(value, { country = '' } = {}) {
211
224
  ),
212
225
  gas,
213
226
  newBuilding: bool(text, /новостро|новобуд|новый\s+дом|novast(?:royka|iroyka)|navast(?:royka|iroyka)|new\s*build|newly\s+built|yangi\s+(?:bino|qurilgan|uy)|bloc\s+nou/iu),
214
- communalSeparated: parseCommunalSeparated(text, country),
227
+ communalSeparated: isSale ? null : parseCommunalSeparated(text, country),
215
228
  parking: bool(
216
229
  text,
217
230
  /паркинг|парков|машино[- ]?мест|parking|avtoturargoh|mashina\s*joyi/iu,
@@ -239,6 +252,6 @@ export function parseHousingListingFields(value, { country = '' } = {}) {
239
252
  firstRent,
240
253
  minRentTerm: parseMinRentTerm(text),
241
254
  availableFrom: parseAvailableFrom(text),
242
- utilitiesAmount: parseUtilitiesAmount(text),
255
+ utilitiesAmount: isSale ? null : parseUtilitiesAmount(text),
243
256
  });
244
257
  }
@@ -242,8 +242,17 @@ export function parseHousingPrice(value, fallbackCurrency = '') {
242
242
  // `500 m2` and `5 minut` cannot be promoted to 500 million / 5 million.
243
243
  const match = priceText.match(new RegExp(`(\\d+(?:[.,]\\d+)?)\\s*(${SCALE_PATTERN})(?=$|[^\\p{L}\\p{N}_])`, 'iu'));
244
244
  if (match) {
245
+ // Ukrainian listings abbreviate a microdistrict as “531 м/р”. The
246
+ // one-letter million scale is otherwise valid, but this trailing
247
+ // “/р” makes the token an area identifier, never a price.
248
+ const tail = priceText.slice((match.index ?? 0) + match[0].length);
249
+ if (/^\s*\/\s*[рr](?=$|[^\p{L}\p{N}_])/iu.test(tail)) {
250
+ // Fall through to the ordinary bare-number pass, which can still
251
+ // recover a genuine rent amount later in the listing.
252
+ } else {
245
253
  const amount = parseScaledAmount(match[1], match[2]);
246
254
  if (amount != null && amount >= 1000 && amount <= 5_000_000_000) price = Math.round(amount);
255
+ }
247
256
  }
248
257
  }
249
258
 
@@ -430,6 +430,12 @@ export function parseHousingStructured(value, options = {}) {
430
430
  const country = String(options.country || '').trim();
431
431
  const fallbackCurrency = options.fallbackCurrency || countryCurrency(country) || '';
432
432
  const phoneCountry = options.phoneCountry || countryPhoneHint(country) || null;
433
+ const intent = resolveHousingIntent(text);
434
+ const listingFields = parseHousingListingFields(text, { country, dealType: intent?.dealType || null });
435
+ const parsedPayments = parseHousingPaymentDetails(text);
436
+ const payments = intent?.dealType === 'sale'
437
+ ? deepFreeze({ ...parsedPayments, utilities: null })
438
+ : parsedPayments;
433
439
 
434
440
  return deepFreeze({
435
441
  text,
@@ -437,7 +443,7 @@ export function parseHousingStructured(value, options = {}) {
437
443
  platform: sourcePost.source,
438
444
  contact: sourcePost.contact,
439
445
  },
440
- intent: resolveHousingIntent(text),
446
+ intent,
441
447
  context: parseHousingContext(text),
442
448
  rooms: parseHousingRoomCount(text),
443
449
  floor: parseHousingFloor(text),
@@ -450,8 +456,8 @@ export function parseHousingStructured(value, options = {}) {
450
456
  }),
451
457
  residentialComplex: parseHousingResidentialComplex(text),
452
458
  amenities: parseHousingAmenities(text),
453
- listingFields: parseHousingListingFields(text, { country }),
454
- payments: parseHousingPaymentDetails(text),
459
+ listingFields,
460
+ payments,
455
461
  seller: parseHousingSeller(text),
456
462
  infrastructure: parseHousingInfrastructure(text),
457
463
  contacts: parseHousingContacts(text, { countryHint: phoneCountry, sourcePost }),
@@ -33,6 +33,7 @@ const RC_ATTRIBUTE_TOKEN_RE = /^\d|^[\d/]+$|^[a-zа-яё]?\d+(?:[а-яёa-z]{1,4
33
33
  const RC_LATIN_NOISE_RE = /^(?:vip|lux|luxe|elite|premium|euro|evro|new|top|super|best|hot|urgent|srochno|arenda|ijara|sotiladi|sale|rent|for|home|house|flat|apartment|apartments|kvartira|tashkent|toshkent|wifi|wi|fi|tv|ac|internet|telegram|yandex|google|instagram|whatsapp|iphone|samsung|lg|bosch|artel|km|km2|m2|sqm|usd|uzs|eur)$/iu;
34
34
  const RC_LATIN_WORD_RE = /^[A-Za-z][A-Za-z'’\-]{1,}$/u;
35
35
  const RC_DISTRICT_MARKER_RE = /^(?:район|районе|районы|туман|тумани|tumani|district)$/iu;
36
+ const RC_ADDRESS_INTRO_RE = /^(?:за|адрес(?:ою|у|ом)?|вул(?:иця)?|улица)$/iu;
36
37
  const RC_MARKER_RE = /(?:жк|жм|ж\/к|residential complex|ansamblu(?: rezidential)?|turar[- ]?joy majmuasi)\s*/i;
37
38
 
38
39
  function leadingLatinName(text) {
@@ -65,7 +66,7 @@ export function parseHousingResidentialComplex(value) {
65
66
  const parsed = String(candidate).trim().replace(/([\p{Ll}\d])(\p{Lu})/gu, '$1 $2').replace(/\s{2,}/g, ' ').split(/\s+/).reduce((words, token) => {
66
67
  if (words.stopped || words.list.length >= 4) return { ...words, stopped: true };
67
68
  const clean = token.replace(/^[«»"'„“]+|[«»"'„“!|,]+$/g, '');
68
- if (!clean || RC_STOP_WORD_RE.test(clean) || RC_ATTRIBUTE_TOKEN_RE.test(clean)) return { ...words, stopped: true, by: clean };
69
+ if (!clean || RC_STOP_WORD_RE.test(clean) || RC_ADDRESS_INTRO_RE.test(clean) || RC_ATTRIBUTE_TOKEN_RE.test(clean)) return { ...words, stopped: true, by: clean };
69
70
  return { list: [...words.list, clean], stopped: false, by: words.by };
70
71
  }, { list: [], stopped: false, by: '' });
71
72
  const words = RC_DISTRICT_MARKER_RE.test(parsed.by) ? parsed.list.slice(0, -1) : parsed.list;
@@ -0,0 +1,17 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const KG_BISHKEK_AREA_EXTENSIONS = Object.freeze({
4
+ Bishkek: Object.freeze({
5
+ districts: locationEntries([
6
+ ['Pervomaisky', 'Первомайский', 'Первомайский район', 'Первомайский административный район', 'Биринчи Май', 'Биринчи Май району', 'Биринчи май административдик району'],
7
+ ['Leninsky', 'Ленинский', 'Ленинский район', 'Ленинский административный район', 'Ленин району', 'Ленин административдик району'],
8
+ ['Oktyabrsky', 'Октябрьский', 'Октябрьский район', 'Октябрьский административный район', 'Октябрь району', 'Октябрь административдик району'],
9
+ ['Sverdlovsky', 'Свердловский', 'Свердловский район', 'Свердловский административный район', 'Свердлов району', 'Свердлов административдик району'],
10
+ ]),
11
+ microdistricts: locationEntries([
12
+ ['4-й микрорайон', '4 микрорайон', '4 мкр', '4 мкр.', '4-й мкр', '4th microdistrict'],
13
+ ['5-й микрорайон', '5 микрорайон', '5 мкр', '5 мкр.', '5-й мкр', '5th microdistrict'],
14
+ ['9-й микрорайон', '9 микрорайон', '9 мкр', '9 мкр.', '9-й мкр', '9th microdistrict'],
15
+ ]),
16
+ }),
17
+ });
@@ -28,6 +28,21 @@ export const KG_BISHKEK_RESIDENTIAL_EXTENSIONS = Object.freeze({
28
28
  ['Южный', 'ЖК Южный', 'Жилой комплекс Южный', 'Жилой комплекс "Южный"', 'Yuzhny'],
29
29
  ['Легенда', 'ЖК Легенда', 'ЖК «Легенда»', 'Жилой комплекс Легенда', 'Legenda'],
30
30
  ['Meridian', 'MERIDIAN', 'Меридиан', 'ЖК Meridian', 'ЖК «Meridian»', 'Жилой комплекс Meridian'],
31
+ ['Tokyo City', 'ЖК Tokyo', 'ЖК «Tokyo»', 'Строящийся жилой комплекс "Tokyo"'],
32
+ ['Ачекей', 'ЖК Ачекей', 'Жилой комплекс Ачекей', "Жилой комплекс ''Ачекей''"],
33
+ ['Арбат', 'ЖК Арбат', 'Жилой комплекс Арбат', 'Arbat'],
34
+ ['Чынгыз Айтматов Ордосу', 'ЖК Чынгыз Айтматов Ордосу', 'Жилой комплекс Чынгыз Айтматов Ордосу', 'ЖК Чынгыз Айтматов', 'Жилой комплекс Чынгыз Айтматов'],
35
+ ['Jal Artis', 'JAL ARTIS', 'Джал Артис', 'ЖК Jal Artis', 'ЖК Джал Артис', 'Жилой комплекс Джал Артис'],
36
+ ['Флоренция', 'ЖК Флоренция', 'Жилой комплекс Флоренция', 'Florence'],
37
+ ['IHLAS Residence', 'Ihlas Residence', 'ЖК IHLAS Residence', 'Жилой комплекс IHLAS Residence'],
38
+ ['Империал', 'ЖК Империал', 'Жилой комплекс Империал', 'Imperial'],
39
+ ['Jibekcity', 'JIBEK CITY', 'Jibek City', 'ЖИБЕК СИТИ', 'ЖК Jibekcity', 'ЖК JIBEK CITY', 'Жилой комплекс JIBEK CITY'],
40
+ ['Континенталь', 'ЖК Континенталь', 'Жилой комплекс Континенталь', 'Continental'],
41
+ ['Кремлевский', 'Кремлёвский', 'ЖК Кремлевский', 'ЖК Кремлёвский', 'Жилой комплекс Кремлевский', 'Kremlevskiy'],
42
+ ['Malina', 'MALINA', 'Малина', 'ЖК Malina', 'ЖК MALINA', 'ЖК Малина'],
43
+ ['Мурас', 'ЖК Мурас', 'Жилой комплекс Мурас', 'Muras'],
44
+ ['Пионер', 'ЖК Пионер', 'Жилой комплекс Пионер', 'Pioner'],
45
+ ['Royal', 'ROYAL', 'Роял', 'ЖК Royal', 'Жилой комплекс Royal'],
31
46
  ]),
32
47
  }),
33
48
  });
@@ -9,7 +9,7 @@ export const KG_BISHKEK_STREET_EXTENSIONS = Object.freeze({
9
9
  ['Chui Avenue', 'Chuy Avenue', 'Chui avenue', 'Чуйский проспект', 'проспект Чуй', 'проспект Чүй', 'Чүй проспекти'],
10
10
  ['Baitik Baatyr Street', 'Baitik baatyr Street', 'Baytik Baatyr Street', 'улица Байтик-Баатыра', 'улица Байтик Баатыра', 'ул. Байтик-Баатыра', 'Байтик Баатыр көчөсү'],
11
11
  ['Nasirdin Isanov Street', 'Isanov Street', 'улица Исанова', 'улица Насирдина Исанова', 'ул. Исанова', 'Насирдин Исанов көчөсү'],
12
- ['Ibraimov Street', 'Ibragimov Street', 'улица Ибраимова', 'ул. Ибраимова', 'Ибраимов көчөсү'],
12
+ ['Ibraimov Street', 'Ibragimov Street', 'улица Ибраимова', 'улице Ибраимова', 'ул. Ибраимова', 'Ибраимов көчөсү'],
13
13
  ['Toktogul Street', 'Toktogul Satylganov Street', 'улица Токтогула', 'улица Токтогула Сатылганова', 'ул. Токтогула', 'Токтогул көчөсү', 'Токтогул Сатылганов көчөсү'],
14
14
  ['Joomart Bokonbayev Street', 'Joomart Bokonbaev Street', 'Bokonbayev Street', 'Bokonbaev Street', 'улица Боконбаева', 'улица Жоомарта Боконбаева', 'ул. Боконбаева', 'Жоомарт Бөкөнбаев көчөсү'],
15
15
  ['Jusup Abdrakhmanov Street', 'Yusup Abdrakhmanov Street', 'Abdrakhmanov Street', 'улица Юсупа Абдрахманова', 'улица Жусупа Абдрахманова', 'ул. Абдрахманова', 'Жусуп Абдрахманов көчөсү'],
@@ -67,6 +67,21 @@ export const KG_BISHKEK_STREET_EXTENSIONS = Object.freeze({
67
67
  ['Murmanskaya Street', 'Murmansk Street', 'Мурманская улица', 'улица Мурманская'],
68
68
  ['Valdayskaya Street', 'Valdai Street', 'Валдайская улица', 'улица Валдайская'],
69
69
  ['Ala-Archinskaya Street', 'Ala Archa Street', 'Ала-Арчинская улица', 'улица Ала-Арчинская'],
70
+ ['Бишкек-1 улица', 'улица Бишкек-1', 'Бишкек 1 улица'],
71
+ ['Бишкек-2 улица', 'улица Бишкек-2', 'Бишкек 2 улица'],
72
+ ['Бишкек-3 улица', 'улица Бишкек-3', 'Бишкек 3 улица'],
73
+ ['Бишкек-4 улица', 'улица Бишкек-4', 'Бишкек 4 улица'],
74
+ ['Бишкек-5 улица', 'улица Бишкек-5', 'Бишкек 5 улица'],
75
+ ['Бишкек-6 улица', 'улица Бишкек-6', 'Бишкек 6 улица'],
76
+ ['Бишкек-7 улица', 'улица Бишкек-7', 'Бишкек 7 улица'],
77
+ ['Бишкек-8 улица', 'улица Бишкек-8', 'Бишкек 8 улица'],
78
+ ['Улица Бишкек-9', 'Бишкек-9 улица', 'улица Бишкек 9'],
79
+ ['Улица Абдумомунова', 'Абдумомунова улица', 'ул. Абдумомунова'],
80
+ ['Улица Байгазак Арпачиева', 'Байгазак Арпачиева улица', 'ул. Байгазак Арпачиева'],
81
+ ['Улица квартал Кирова', 'квартал Кирова улица'],
82
+ ['Парковая улица', 'улица Парковая', 'ул. Парковая'],
83
+ ['Улица Тунгуч', 'Тунгуч улица', 'ул. Тунгуч'],
84
+ ['Улица Турусбекова', 'Турусбекова улица', 'ул. Турусбекова'],
70
85
  ]),
71
86
  }),
72
87
  });
@@ -8,6 +8,7 @@ import {
8
8
  import { LOCATION_LIST_KEYS, mergeLocationCountries } from './location-merge.js';
9
9
  import { canonicalCity } from './geography.js';
10
10
  import { KG_LOCATION_EXTENSIONS } from './kg-location-extensions.js';
11
+ import { KG_BISHKEK_AREA_EXTENSIONS } from './kg-bishkek-area-extensions.js';
11
12
  import { KG_BISHKEK_STREET_EXTENSIONS } from './kg-bishkek-street-extensions.js';
12
13
  import { KG_BISHKEK_RESIDENTIAL_EXTENSIONS } from './kg-bishkek-residential-extensions.js';
13
14
  import { KG_OSH_LOCATION_EXTENSIONS } from './kg-osh-location-extensions.js';
@@ -30,17 +31,46 @@ import { KZ_CITY_RESIDENTIAL_EXTENSIONS } from './kz-city-residential-extensions
30
31
  import { UA_RESIDENTIAL_EXTENSIONS } from './ua-residential-extensions.js';
31
32
  import { UA_CHERNIHIV_RESIDENTIAL_EXTENSIONS } from './ua-chernihiv-residential-extensions.js';
32
33
  import { UA_KHARKIV_MICRODISTRICT_EXTENSIONS } from './ua-kharkiv-microdistrict-extensions.js';
34
+ import { UA_KYIV_STREET_EXTENSIONS } from './ua-kyiv-street-extensions.js';
35
+ import { UA_KHARKIV_STREET_EXTENSIONS } from './ua-kharkiv-street-extensions.js';
36
+ import { UA_DNIPRO_STREET_EXTENSIONS } from './ua-dnipro-street-extensions.js';
37
+ import { UA_ZAPORIZHZHIA_STREET_EXTENSIONS } from './ua-zaporizhzhia-street-extensions.js';
38
+ import { UA_KRYVYI_RIH_STREET_EXTENSIONS } from './ua-kryvyi-rih-street-extensions.js';
39
+ import { UA_MYKOLAIV_STREET_EXTENSIONS } from './ua-mykolaiv-street-extensions.js';
40
+ import { UA_VINNYTSIA_STREET_EXTENSIONS } from './ua-vinnytsia-street-extensions.js';
41
+ import { UA_CHERNIHIV_STREET_EXTENSIONS } from './ua-chernihiv-street-extensions.js';
33
42
  import { UZ_TASHKENT_CONTEXT_EXTENSIONS } from './uz-tashkent-context-extensions.js';
43
+ import { UZ_TASHKENT_REVIEWED_RESIDENTIAL_EXTENSIONS } from './uz-tashkent-reviewed-residential-extensions.js';
44
+ import { UZ_TASHKENT_REVIEWED_STREET_EXTENSIONS } from './uz-tashkent-reviewed-street-extensions.js';
34
45
  import { UZ_SAMARKAND_CONTEXT_EXTENSIONS } from './uz-samarkand-context-extensions.js';
35
46
  import { UZ_BUKHARA_LOCATION_EXTENSIONS } from './uz-bukhara-location-extensions.js';
47
+ import { UZ_NUKUS_STREET_EXTENSIONS } from './uz-nukus-street-extensions.js';
48
+ import { UZ_NAMANGAN_STREET_EXTENSIONS } from './uz-namangan-street-extensions.js';
49
+ import { UZ_FERGANA_STREET_EXTENSIONS } from './uz-fergana-street-extensions.js';
50
+ import { UZ_ANDIJAN_STREET_EXTENSIONS } from './uz-andijan-street-extensions.js';
51
+ import { UZ_QARSHI_STREET_EXTENSIONS } from './uz-qarshi-street-extensions.js';
36
52
 
37
53
  export { UA_REGION_ENTRIES, UA_SECONDARY_CITIES, matchUkraineRegion, matchUkraineSecondaryCity };
38
54
 
55
+ const TASHKENT_SHIFOKORLAR_STREET_ADDRESS_FORMS = new Set([
56
+ 'Shifokorlar-5',
57
+ 'Shifokorlar-6',
58
+ ]);
59
+
39
60
  // Sattepo is a mahalla in the canonical Samarkand layer. The legacy base seed
40
61
  // also exposes the same physical place as the Sartepa microdistrict; remove
41
- // that duplicate owner before runtime extensions are merged.
62
+ // that duplicate owner before runtime extensions are merged. Shifokorlar-5/6
63
+ // are street/address forms, not standalone Tashkent local areas, so remove the
64
+ // stale local-area owners before the reviewed street extension is merged.
42
65
  const UZ_RUNTIME_BASE_LOCATION_DICTIONARIES = Object.freeze({
43
66
  ...(BASE_LOCATION_DICTIONARIES.UZ || {}),
67
+ Tashkent: Object.freeze({
68
+ ...(BASE_LOCATION_DICTIONARIES.UZ?.Tashkent || {}),
69
+ localAreas: Object.freeze(
70
+ (BASE_LOCATION_DICTIONARIES.UZ?.Tashkent?.localAreas || [])
71
+ .filter(({ name }) => !TASHKENT_SHIFOKORLAR_STREET_ADDRESS_FORMS.has(name)),
72
+ ),
73
+ }),
44
74
  Samarkand: Object.freeze({
45
75
  ...(BASE_LOCATION_DICTIONARIES.UZ?.Samarkand || {}),
46
76
  microdistricts: Object.freeze(
@@ -53,6 +83,7 @@ const UZ_RUNTIME_BASE_LOCATION_DICTIONARIES = Object.freeze({
53
83
  const KG_LEGACY_LOCATION_DICTIONARIES = mergeLocationCountries(
54
84
  BASE_LOCATION_DICTIONARIES.KG || {},
55
85
  KG_LOCATION_EXTENSIONS,
86
+ KG_BISHKEK_AREA_EXTENSIONS,
56
87
  KG_BISHKEK_STREET_EXTENSIONS,
57
88
  KG_BISHKEK_RESIDENTIAL_EXTENSIONS,
58
89
  KG_OSH_LOCATION_EXTENSIONS,
@@ -75,12 +106,27 @@ export const LOCATION_DICTIONARIES = Object.freeze({
75
106
  UA_RESIDENTIAL_EXTENSIONS,
76
107
  UA_CHERNIHIV_RESIDENTIAL_EXTENSIONS,
77
108
  UA_KHARKIV_MICRODISTRICT_EXTENSIONS,
109
+ UA_KYIV_STREET_EXTENSIONS,
110
+ UA_KHARKIV_STREET_EXTENSIONS,
111
+ UA_DNIPRO_STREET_EXTENSIONS,
112
+ UA_ZAPORIZHZHIA_STREET_EXTENSIONS,
113
+ UA_KRYVYI_RIH_STREET_EXTENSIONS,
114
+ UA_MYKOLAIV_STREET_EXTENSIONS,
115
+ UA_VINNYTSIA_STREET_EXTENSIONS,
116
+ UA_CHERNIHIV_STREET_EXTENSIONS,
78
117
  ),
79
118
  UZ: mergeLocationCountries(
80
119
  UZ_RUNTIME_BASE_LOCATION_DICTIONARIES,
81
120
  UZ_TASHKENT_CONTEXT_EXTENSIONS,
121
+ UZ_TASHKENT_REVIEWED_RESIDENTIAL_EXTENSIONS,
122
+ UZ_TASHKENT_REVIEWED_STREET_EXTENSIONS,
82
123
  UZ_SAMARKAND_CONTEXT_EXTENSIONS,
83
124
  UZ_BUKHARA_LOCATION_EXTENSIONS,
125
+ UZ_NUKUS_STREET_EXTENSIONS,
126
+ UZ_NAMANGAN_STREET_EXTENSIONS,
127
+ UZ_FERGANA_STREET_EXTENSIONS,
128
+ UZ_ANDIJAN_STREET_EXTENSIONS,
129
+ UZ_QARSHI_STREET_EXTENSIONS,
84
130
  ),
85
131
  KZ: mergeLocationCountries(
86
132
  BASE_LOCATION_DICTIONARIES.KZ || {},
@@ -0,0 +1,12 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UA_CHERNIHIV_STREET_EXTENSIONS = Object.freeze({
4
+ Chernihiv: Object.freeze({
5
+ streets: locationEntries([
6
+ ['провулок Коти', 'пров. Коти'],
7
+ ['провулок Квітки Цісик', 'пров. Квітки Цісик'],
8
+ ['провулок Поліський', 'пров. Поліський'],
9
+ ['вулиця Євгена Онацького', 'вул. Євгена Онацького'],
10
+ ]),
11
+ }),
12
+ });
@@ -0,0 +1,14 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UA_DNIPRO_STREET_EXTENSIONS = Object.freeze({
4
+ Dnipro: Object.freeze({
5
+ streets: locationEntries([
6
+ ['Батальона «Днепр» бульвар', 'бульвар Батальона «Днепр»', 'бул. Батальона «Днепр»', 'Батальона «Днепр» бул.'],
7
+ ['Славы бульвар', 'бульвар Славы', 'Славы бул.'],
8
+ ['Звёздный бульвар', 'бульвар Звёздный', 'Звёздный бул.'],
9
+ ['Театральный бульвар', 'бульвар Театральный', 'Театральный бул.'],
10
+ ['Черновола бульвар', 'бульвар Черновола', 'Черновола бул.'],
11
+ ['Кельнський бульвар', 'бульвар Кельнський', 'Кельнський бул.'],
12
+ ]),
13
+ }),
14
+ });
@@ -39,6 +39,8 @@ export const UA_KHARKIV_LOCATION_TRANSLATIONS = Object.freeze({
39
39
  ['Horizont', 'Обрій', 'Обрий', 'Obrii', 'Горизонт'],
40
40
  ]),
41
41
  streets: locationEntries([
42
+ ['Poltavskyi Shliakh Street', 'Полтавський шлях', 'Полтавский шлях', 'Полтавський шоях', 'Полтавский шоях'],
43
+ ['Liubovi Maloi Street', 'вулиця Любові Малої', 'вул. Любові Малої', 'Любові Малої', 'улица Любови Малой', 'ул. Любови Малой', 'Любови Малой', 'Л. Малой', 'Л.Малой', 'ул. Л. Малой', 'ул.Л.Малой', 'улица Л. Малой', 'улица Л.Малой'],
42
44
  ['Hvardiitsiv-Shyronintsiv Street', 'вулиця Гвардійців-Широнінців', 'вул. Гвардійців-Широнінців', 'Гвардійців-Широнінців', 'улица Гвардейцев-Широнинцев', 'ул. Гвардейцев-Широнинцев', 'Гвардейцев-Широнинцев', 'Гвардейцев Широнинцев'],
43
45
  ['Yuvileinyi Avenue', 'проспект Ювілейний', 'пр-т Ювілейний', 'Ювілейний проспект', 'проспект Юбилейный', 'пр-т Юбилейный', 'Юбилейный проспект', 'проспект 50-річчя ВЛКСМ', 'проспект 50-летия ВЛКСМ'],
44
46
  ['Traktorobudivnykiv Avenue', 'проспект Тракторобудівників', 'пр-т Тракторобудівників', 'Тракторобудівників проспект', 'проспект Тракторостроителей', 'пр-т Тракторостроителей', 'Тракторостроителей проспект'],
@@ -3,6 +3,7 @@ import { locationEntries } from './location-merge.js';
3
3
  export const UA_KHARKIV_MICRODISTRICT_EXTENSIONS = Object.freeze({
4
4
  Kharkiv: Object.freeze({
5
5
  microdistricts: locationEntries([
6
+ ['Kholodna Hora', 'Хол. Гора', 'Хол Гора'],
6
7
  ['337 microdistrict', '337-й мікрорайон', '337 мікрорайон', '337-й микрорайон', '337 микрорайон', '337 мкр', '337 мкр.', '337-й мкр', '337 м/р', '337 мрн'],
7
8
  ['339 microdistrict', '339-й мікрорайон', '339 мікрорайон', '339-й микрорайон', '339 микрорайон', '339 мкр', '339 мкр.', '339-й мкр', '339 м/р', '339 мрн'],
8
9
  ]),
@@ -0,0 +1,16 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UA_KHARKIV_STREET_EXTENSIONS = Object.freeze({
4
+ Kharkiv: Object.freeze({
5
+ streets: locationEntries([
6
+ ['Гончаровский бульвар', 'Гончаровский бул.'],
7
+ ['Жасминовый бульвар', 'Жасминовый бул.'],
8
+ ['Профсоюзный бульвар', 'Профсоюзный бул.'],
9
+ ['бульвар Фронтовиков', 'бул. Фронтовиков'],
10
+ ['Садовый бульвар', 'Садовый бул.'],
11
+ ['бульвар Юрьева', 'бул. Юрьева'],
12
+ ['бульвар Богдана Хмельницкого', 'бул. Богдана Хмельницкого'],
13
+ ['бульвар Дмитрия Антоновича', 'бул. Дмитрия Антоновича'],
14
+ ]),
15
+ }),
16
+ });
@@ -0,0 +1,51 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UA_KRYVYI_RIH_STREET_EXTENSIONS = Object.freeze({
4
+ 'Kryvyi Rih': Object.freeze({
5
+ streets: locationEntries([
6
+ ['вулиця Генерала Безручка', 'вул. Генерала Безручка'],
7
+ ['Свято-Вознесенська вулиця', 'вулиця Свято-Вознесенська', 'вул. Свято-Вознесенська'],
8
+ ['вулиця Пелагеї Литвинової', 'вул. Пелагеї Литвинової'],
9
+ ['Низова вулиця', 'вулиця Низова', 'вул. Низова'],
10
+ ['Андижанська вулиця', 'вулиця Андижанська', 'вул. Андижанська'],
11
+ ['вулиця 80-ї Десантно-Штурмової Бригади', 'вул. 80-ї Десантно-Штурмової Бригади'],
12
+ ['вулиця Віри Нікітіної', 'вул. Віри Нікітіної'],
13
+ ['улица Андрея Дробиленко', 'ул. Андрея Дробиленко'],
14
+ ['Софии Русовой улица', 'улица Софии Русовой', 'ул. Софии Русовой'],
15
+ ['Панаса Мирного улица', 'улица Панаса Мирного', 'ул. Панаса Мирного'],
16
+ ['Почтовый проспект', 'проспект Почтовый', 'просп. Почтовый', 'пр-т Почтовый'],
17
+ ['Победы проспект', 'проспект Победы', 'просп. Победы', 'пр-т Победы'],
18
+ ['Центральный проспект', 'проспект Центральный', 'просп. Центральный', 'пр-т Центральный'],
19
+ ['проспект Ивана Нечуя-Левицкого', 'просп. Ивана Нечуя-Левицкого', 'пр-т Ивана Нечуя-Левицкого'],
20
+ ['проспект Мира', 'просп. Мира', 'пр-т Мира'],
21
+ ['провулок Тельмана', 'пров. Тельмана'],
22
+ ['Рудничний провулок', 'провулок Рудничний', 'пров. Рудничний'],
23
+ ['Гімназичний провулок', 'провулок Гімназичний', 'пров. Гімназичний'],
24
+ ['3-й Сальський провулок', 'провулок 3-й Сальський', 'пров. 3-й Сальський'],
25
+ ['Варшавский переулок', 'переулок Варшавский', 'пер. Варшавский'],
26
+ ['Бугский переулок', 'переулок Бугский', 'пер. Бугский'],
27
+ ['переулок Сергея Байдака', 'пер. Сергея Байдака'],
28
+ ['переулок Ампера', 'пер. Ампера'],
29
+ ['Артековский переулок', 'переулок Артековский', 'пер. Артековский'],
30
+ ['Козацька вулиця', 'вулиця Козацька', 'вул. Козацька'],
31
+ ['Чехословацька вулиця', 'вулиця Чехословацька', 'вул. Чехословацька'],
32
+ ['вулиця Нестора Махна', 'вул. Нестора Махна'],
33
+ ['вулиця Волонтерів', 'вул. Волонтерів'],
34
+ ['Карагандинська вулиця', 'вулиця Карагандинська', 'вул. Карагандинська'],
35
+ ['Каменедробильна вулиця', 'вулиця Каменедробильна', 'вул. Каменедробильна'],
36
+ ['вулиця Гойї', 'вул. Гойї'],
37
+ ['Репина улица', 'улица Репина', 'ул. Репина'],
38
+ ['Костя Гордиенко улица', 'улица Костя Гордиенко', 'ул. Костя Гордиенко'],
39
+ ['Южный проспект', 'проспект Южный', 'просп. Южный', 'пр-т Южный'],
40
+ ['Университетский проспект', 'проспект Университетский', 'просп. Университетский', 'пр-т Университетский'],
41
+ ['200-летия Кривого Рога проспект', 'проспект 200-летия Кривого Рога', 'просп. 200-летия Кривого Рога', 'пр-т 200-летия Кривого Рога'],
42
+ ['Економічний провулок', 'провулок Економічний', 'пров. Економічний'],
43
+ ['Азовський провулок', 'провулок Азовський', 'пров. Азовський'],
44
+ ['Рубіновий провулок', 'провулок Рубіновий', 'пров. Рубіновий'],
45
+ ['провулок Слави', 'пров. Слави'],
46
+ ['Грушевского переулок', 'переулок Грушевского', 'пер. Грушевского'],
47
+ ['переулок Казака Рога', 'пер. Казака Рога'],
48
+ ['Новолозоватский переулок', 'переулок Новолозоватский', 'пер. Новолозоватский'],
49
+ ]),
50
+ }),
51
+ });
@@ -0,0 +1,9 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UA_KYIV_STREET_EXTENSIONS = Object.freeze({
4
+ Kyiv: Object.freeze({
5
+ streets: locationEntries([
6
+ ['бульвар Тараса Шевченко', 'бул. Тараса Шевченко'],
7
+ ]),
8
+ }),
9
+ });
@@ -0,0 +1,20 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UA_MYKOLAIV_STREET_EXTENSIONS = Object.freeze({
4
+ Mykolaiv: Object.freeze({
5
+ streets: locationEntries([
6
+ ['провулок Курортний', 'пров. Курортний'],
7
+ ['Армійський провулок', 'провулок Армійський', 'пров. Армійський'],
8
+ ['Фінський провулок', 'провулок Фінський', 'пров. Фінський'],
9
+ ['Міжрічковий провулок', 'провулок Міжрічковий', 'пров. Міжрічковий'],
10
+ ['Перший провулок', 'провулок Перший', 'пров. Перший'],
11
+ ['Очаковский переулок', 'переулок Очаковский', 'пер. Очаковский'],
12
+ ['Измаильский переулок', 'переулок Измаильский', 'пер. Измаильский'],
13
+ ['4-й Парниковый переулок', 'переулок 4-й Парниковый', 'пер. 4-й Парниковый'],
14
+ ['1-й Парниковый переулок', 'переулок 1-й Парниковый', 'пер. 1-й Парниковый'],
15
+ ['2-й Парниковый переулок', 'переулок 2-й Парниковый', 'пер. 2-й Парниковый'],
16
+ ['Офицерский бульвар', 'бульвар Офицерский', 'Офицерский бул.'],
17
+ ['Бузький бульвар', 'бульвар Бузький', 'бул. Бузький', 'Бугский бульвар', 'бульвар Бугский', 'бул. Бугский'],
18
+ ]),
19
+ }),
20
+ });
@@ -0,0 +1,28 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UA_VINNYTSIA_STREET_EXTENSIONS = Object.freeze({
4
+ Vinnytsia: Object.freeze({
5
+ streets: locationEntries([
6
+ ['Свободы бульвар', 'бульвар Свободы', 'бул. Свободы'],
7
+ ['Марко Вовчок бульвар', 'бульвар Марко Вовчок', 'Марко Вовчок бул.'],
8
+ ['провулок Івана Світличного', 'пров. Івана Світличного'],
9
+ ['вулиця Уласа Самчука', 'вул. Уласа Самчука'],
10
+ ['Ольги Кобылянской улица', 'улица Ольги Кобылянской', 'ул. Ольги Кобылянской'],
11
+ ['Марии Гавриш улица', 'улица Марии Гавриш', 'ул. Марии Гавриш'],
12
+ ['Августовская улица', 'улица Августовская', 'ул. Августовская'],
13
+ ['Днепровская улица', 'улица Днепровская', 'ул. Днепровская'],
14
+ ['Юности проспект', 'проспект Юности', 'просп. Юности', 'пр-т Юности'],
15
+ ['проспект Космонавтів', 'просп. Космонавтів', 'пр-т Космонавтів'],
16
+ ['Коцюбинского проспект', 'проспект Коцюбинского', 'просп. Коцюбинского', 'пр-т Коцюбинского'],
17
+ ['2-й провулок Тетяни Яблонської', 'провулок 2-й Тетяни Яблонської', 'пров. 2-й Тетяни Яблонської'],
18
+ ['1-й провулок Тетяни Яблонської', 'провулок 1-й Тетяни Яблонської', 'пров. 1-й Тетяни Яблонської'],
19
+ ['1-й Восточный переулок', 'переулок 1-й Восточный', 'пер. 1-й Восточный'],
20
+ ['Привокзальный переулок', 'переулок Привокзальный', 'пер. Привокзальный'],
21
+ ['1-й Ботанический переулок', 'переулок 1-й Ботанический', 'пер. 1-й Ботанический'],
22
+ ['3-й Руданского переулок', 'переулок 3-й Руданского', 'пер. 3-й Руданского'],
23
+ ['Игоря Савченко переулок', 'переулок Игоря Савченко', 'пер. Игоря Савченко'],
24
+ ['2-й Ботанический переулок', 'переулок 2-й Ботанический', 'пер. 2-й Ботанический'],
25
+ ['2-й Одесский переулок', 'переулок 2-й Одесский', 'пер. 2-й Одесский'],
26
+ ]),
27
+ }),
28
+ });
@@ -0,0 +1,46 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UA_ZAPORIZHZHIA_STREET_EXTENSIONS = Object.freeze({
4
+ Zaporizhzhia: Object.freeze({
5
+ streets: locationEntries([
6
+ ['вулиця Білогірська', 'вул. Білогірська'],
7
+ ['вулиця Мирна', 'вул. Мирна'],
8
+ ['вулиця Молочна', 'вул. Молочна'],
9
+ ['вулиця Почаївська', 'вул. Почаївська'],
10
+ ['вулиця Радіальна', 'вул. Радіальна'],
11
+ ['вулиця Радісна', 'вул. Радісна'],
12
+ ['вулиця Садівництва', 'вул. Садівництва'],
13
+ ['вулиця Слобожанська', 'вул. Слобожанська'],
14
+ ['вулиця Теслярська', 'вул. Теслярська'],
15
+ ['вулиця Фонтанна', 'вул. Фонтанна'],
16
+ ['проспект Інженера Преображенського', 'просп. Інженера Преображенського', 'пр-т Інженера Преображенського'],
17
+ ['проспект Героїв Національної Гвардії України', 'просп. Героїв Національної Гвардії України', 'пр-т Героїв Національної Гвардії України'],
18
+ ['проспект Металургів', 'просп. Металургів', 'пр-т Металургів'],
19
+ ['проспект Соборний', 'просп. Соборний', 'пр-т Соборний'],
20
+ ['проспект Ювілейний', 'просп. Ювілейний', 'пр-т Ювілейний'],
21
+ ['Арабатський провулок', 'провулок Арабатський', 'пров. Арабатський'],
22
+ ['Балхашський провулок', 'провулок Балхашський', 'пров. Балхашський'],
23
+ ['Березневий провулок', 'провулок Березневий', 'пров. Березневий'],
24
+ ['Вірний провулок', 'провулок Вірний', 'пров. Вірний'],
25
+ ['Галицький провулок', 'провулок Галицький', 'пров. Галицький'],
26
+ ['Гурзуфський провулок', 'провулок Гурзуфський', 'пров. Гурзуфський'],
27
+ ['Гімалайський провулок', 'провулок Гімалайський', 'пров. Гімалайський'],
28
+ ['Дніпрорудний провулок', 'провулок Дніпрорудний', 'пров. Дніпрорудний'],
29
+ ['Олега Мельниченка провулок', 'провулок Олега Мельниченка', 'пров. Олега Мельниченка'],
30
+ ['Прохолодний провулок', 'провулок Прохолодний', 'пров. Прохолодний'],
31
+ ['Спасівський провулок', 'провулок Спасівський', 'пров. Спасівський'],
32
+ ['Тираспольський провулок', 'провулок Тираспольський', 'пров. Тираспольський'],
33
+ ['Хвилясний провулок', 'провулок Хвилясний', 'пров. Хвилясний'],
34
+ ['Ширшова провулок', 'провулок Ширшова', 'пров. Ширшова'],
35
+ ['провулок Бакинський', 'пров. Бакинський'],
36
+ ['провулок Березовий', 'пров. Березовий'],
37
+ ['Бельфорський бульвар', 'бульвар Бельфорський', 'Бельфорський бул.'],
38
+ ['бульвар Будівельників', 'бул. Будівельників'],
39
+ ['бульвар Героїв полку Азов', 'бул. Героїв полку Азов'],
40
+ ['бульвар Марії Примаченко', 'бул. Марії Примаченко'],
41
+ ['бульвар Парковий', 'бул. Парковий'],
42
+ ['бульвар Центральний', 'бул. Центральний'],
43
+ ['бульвар Шевченка', 'бул. Шевченка'],
44
+ ]),
45
+ }),
46
+ });
@@ -0,0 +1,22 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UZ_ANDIJAN_STREET_EXTENSIONS = Object.freeze({
4
+ Andijan: Object.freeze({
5
+ streets: locationEntries([
6
+ ['улица Абдулазиза Юлдашева', 'ул. Абдулазиза Юлдашева'],
7
+ ['Тинчлик улица', 'Тинчлик ул.'],
8
+ ['улица Атабекова', 'ул. Атабекова'],
9
+ ['улица Т. Келдиева', 'ул. Т. Келдиева'],
10
+ ['улица Шабнам', 'ул. Шабнам'],
11
+ ['улица Токлик', 'ул. Токлик'],
12
+ ['улица Абдурауфа Фитрата', 'ул. Абдурауфа Фитрата'],
13
+ ['улица Обихаёт', 'ул. Обихаёт'],
14
+ ['улица Дамарик', 'ул. Дамарик'],
15
+ ['улица Хурсандлик', 'ул. Хурсандлик'],
16
+ ['улица Ифтихор', 'ул. Ифтихор'],
17
+ ['улица Бахоуддина Накшбанди', 'ул. Бахоуддина Накшбанди'],
18
+ ['Сарбонтепа улица', 'Сарбонтепа ул.'],
19
+ ['улица Саиды Зуннуновой', 'ул. Саиды Зуннуновой'],
20
+ ]),
21
+ }),
22
+ });
@@ -8,7 +8,29 @@ export const UZ_BUKHARA_LOCATION_EXTENSIONS = Object.freeze({
8
8
  ['3-й микрорайон', '3 микрорайон', '3 мкр', '3 мкр.', '3-й мкр'],
9
9
  ['4-й микрорайон', '4 микрорайон', '4 мкр', '4 мкр.', '4-й мкр'],
10
10
  ['5А микрорайон', '5а микрорайон', '5A микрорайон', '5А мкр', '5а мкр', '5A mkr'],
11
+ ['5Б микрорайон', '5б микрорайон', '5Б мкр', '5б мкр'],
12
+ ['5В микрорайон', '5в микрорайон', '5V микрорайон', '5В мкр', '5в мкр'],
13
+ ['6A микрорайон', '6А микрорайон', '6а микрорайон', '6A мкр', '6А мкр'],
14
+ ['6Б микрорайон', '6б микрорайон', '6Б мкр', '6б мкр'],
11
15
  ['7-й микрорайон', '7 микрорайон', '7 мкр', '7 мкр.', '7-й мкр'],
16
+ ['Северный микрорайон', 'Северный мкр', 'мкр Северный'],
17
+ ]),
18
+ localAreas: locationEntries([
19
+ ['Жилмассив Сафедмуй'],
20
+ ]),
21
+ streets: locationEntries([
22
+ ['1-й поворот улицы Махтумкули улица'],
23
+ ['Улица 1-й улицы Муборак'],
24
+ ['1-я улица Хавзи Бодом'],
25
+ ['1-я улица Шейхон'],
26
+ ['2-я улица Хавзи Бодом'],
27
+ ['Чашмаи Аюб улица'],
28
+ ['улица Хафиза Шеразия', 'ул. Хафиза Шеразия'],
29
+ ['улица Марата Каримова', 'ул. Марата Каримова'],
30
+ ['Мирдустим улица'],
31
+ ['Мухтара Ашрафи улица'],
32
+ ['Отабая Эшанова улица'],
33
+ ['Писташиканон улица'],
12
34
  ]),
13
35
  }),
14
36
  });
@@ -0,0 +1,16 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UZ_FERGANA_STREET_EXTENSIONS = Object.freeze({
4
+ Fergana: Object.freeze({
5
+ streets: locationEntries([
6
+ ['Кувасайская улица', 'Кувасайская ул.'],
7
+ ['улица Конституции', 'ул. Конституции'],
8
+ ['улица Нихол', 'ул. Нихол'],
9
+ ['улица Белова', 'ул. Белова'],
10
+ ['улица Ворис', 'ул. Ворис'],
11
+ ['улица Гулистон', 'ул. Гулистон'],
12
+ ['улица Бинафша', 'ул. Бинафша'],
13
+ ['улица Янги Хаёт', 'ул. Янги Хаёт'],
14
+ ]),
15
+ }),
16
+ });
@@ -0,0 +1,27 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UZ_NAMANGAN_STREET_EXTENSIONS = Object.freeze({
4
+ Namangan: Object.freeze({
5
+ streets: locationEntries([
6
+ ['улица Гузал', 'ул. Гузал'],
7
+ ['Гирванбулакская улица', 'Гирванбулакская ул.'],
8
+ ['улица Янги Арик', 'ул. Янги Арик'],
9
+ ['улица Х.Хайитов', 'ул. Х.Хайитов'],
10
+ ['улица Казанбулак', 'ул. Казанбулак'],
11
+ ['улица Ипакчи', 'ул. Ипакчи'],
12
+ ['улица Дилшод', 'ул. Дилшод'],
13
+ ['улица Чаманзор', 'ул. Чаманзор'],
14
+ ['улица Янгиарык 2-й проезд', 'ул. Янгиарык 2-й проезд'],
15
+ ['улица Шарк гузали', 'ул. Шарк гузали'],
16
+ ['1-я улица Достон', '1-я ул. Достон'],
17
+ ['улица Олмазора', 'ул. Олмазора'],
18
+ ['1-я улица Чархпалак', '1-я ул. Чархпалак'],
19
+ ['улица Бунёдкор', 'ул. Бунёдкор'],
20
+ ['улица Мингтерак', 'ул. Мингтерак'],
21
+ ['2-я улица Табаррук', '2-я ул. Табаррук'],
22
+ ['улица 20-летия Независимости', 'ул. 20-летия Независимости'],
23
+ ['улица Янги Бог', 'ул. Янги Бог'],
24
+ ['3-я улица Хасанабад', '3-я ул. Хасанабад'],
25
+ ]),
26
+ }),
27
+ });
@@ -0,0 +1,28 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UZ_NUKUS_STREET_EXTENSIONS = Object.freeze({
4
+ Nukus: Object.freeze({
5
+ streets: locationEntries([
6
+ ['улица А. Мусаева', 'ул. А. Мусаева'],
7
+ ['улица Уллы жол', 'ул. Уллы жол'],
8
+ ['улица Шагласын', 'ул. Шагласын'],
9
+ ['улица Каруан жолы', 'ул. Каруан жолы'],
10
+ ['улица Нур ата', 'ул. Нур ата'],
11
+ ['улица Кенимех', 'ул. Кенимех'],
12
+ ['улица Мажнунтал', 'ул. Мажнунтал'],
13
+ ['улица Дашти кыпшак', 'ул. Дашти кыпшак'],
14
+ ['улица Сахра гули', 'ул. Сахра гули'],
15
+ ['улица Саламатлык', 'ул. Саламатлык'],
16
+ ['улица А. Досназарова', 'ул. А. Досназарова'],
17
+ ['улица Айбек', 'ул. Айбек'],
18
+ ['улица Гауир кала', 'ул. Гауир кала'],
19
+ ['улица Табыс', 'ул. Табыс'],
20
+ ['улица К. Айымбетова', 'ул. К. Айымбетова'],
21
+ ['улица Кос кол-3', 'ул. Кос кол-3'],
22
+ ['улица Темир жол', 'ул. Темир жол'],
23
+ ['улица Каракалпакстан', 'ул. Каракалпакстан'],
24
+ ['улица Бирликли', 'ул. Бирликли'],
25
+ ['улица Ораз Ахун', 'ул. Ораз Ахун'],
26
+ ]),
27
+ }),
28
+ });
@@ -0,0 +1,25 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ export const UZ_QARSHI_STREET_EXTENSIONS = Object.freeze({
4
+ Qarshi: Object.freeze({
5
+ streets: locationEntries([
6
+ ['улица Шерозий', 'ул. Шерозий'],
7
+ ['улица Бунёдкор', 'ул. Бунёдкор'],
8
+ ['улица Узумзор', 'ул. Узумзор'],
9
+ ['улица Мукумий', 'ул. Мукумий'],
10
+ ['Кум Кишлак улица', 'Кум Кишлак ул.'],
11
+ ['улица Халклар Дустлиги', 'ул. Халклар Дустлиги'],
12
+ ['Коратепа улица', 'Коратепа ул.'],
13
+ ['улица Корлугбогот', 'ул. Корлугбогот'],
14
+ ['улица Нуристон', 'ул. Нуристон'],
15
+ ['улица Хусниобод', 'ул. Хусниобод'],
16
+ ['улица Туркистон', 'ул. Туркистон'],
17
+ ['Буюк Туран улица', 'Буюк Туран ул.'],
18
+ ['улица Жуковского', 'ул. Жуковского'],
19
+ ['улица Маргилон', 'ул. Маргилон'],
20
+ ['улица Кургантепа', 'ул. Кургантепа'],
21
+ ['улица Хужабог', 'ул. Хужабог'],
22
+ ['улица Зарафшон', 'ул. Зарафшон'],
23
+ ]),
24
+ }),
25
+ });
@@ -22,7 +22,7 @@ const residential = (canonical, aliases, labels) => entry(
22
22
  labels,
23
23
  );
24
24
 
25
- const street = (canonical, aliases, labels) => entry(
25
+ const street = (canonical, aliases = [], labels = null) => entry(
26
26
  canonical,
27
27
  'street',
28
28
  aliases,
@@ -100,6 +100,15 @@ export const UZ_SAMARKAND_CONTEXT_EXTENSIONS = Object.freeze({
100
100
  street('Buyuk Ipak Yuli Street', [
101
101
  'Buyuk Ipak yo‘li ko‘chasi', "Buyuk Ipak yo'li ko'chasi", 'улица Буюк Ипак Йули', 'улица Великий Шёлковый путь',
102
102
  ], { en: 'Buyuk Ipak Yuli Street', uz: "Buyuk Ipak yo'li ko'chasi", ru: 'улица Буюк Ипак Йули' }),
103
+ street('2-я Кызылкумская'),
104
+ street('1-я Самарканд улица'),
105
+ street('2-я Самарканд улица'),
106
+ street('Халила Султана улица'),
107
+ street('Улица Махорат', ['ул. Махорат']),
108
+ street('Намазгох переулок', ['пер. Намазгох']),
109
+ street('Улица Расадхона', ['ул. Расадхона']),
110
+ street('Улица Шахмурада', ['ул. Шахмурада']),
111
+ street('Улица Устозлар', ['ул. Устозлар']),
103
112
  ]),
104
113
  }),
105
114
  });
@@ -1,4 +1,5 @@
1
1
  import { TASHKENT_AREAS } from './geo.js';
2
+ import { locationEntries } from './location-merge.js';
2
3
  import { aliasesToRegex } from './normalization.js';
3
4
 
4
5
  function legacyAreaEntry(district, canonical) {
@@ -44,9 +45,44 @@ function residentialEntry(canonical, aliases = []) {
44
45
  // a second C-1 canonical or consumer-local regex.
45
46
  const C1 = legacyAreaEntry('Mirzo Ulugbek', 'Buyuk Ipak Yuli');
46
47
 
48
+ const REVIEWED_LOCAL_AREAS = locationEntries([
49
+ ['Ibn Sino-2', 'Abu Ali ibn Sina-2', 'Абу Али ибн Сина-2', 'Abu Ali ibn Sino-2', 'Абу Али ибн Сино-2', 'Abu Ali ibn Sino-2 dahasi', 'Массив Калинина 2'],
50
+ ['Ahmad Yugnakiy', 'Ахмада Югнаки', 'Ахмада Югнаки (Солнечный)', 'Ahmad Yugnakiy (Solnechnyy)'],
51
+ ['Aviasozlar-2', 'Авиасозлар-2', 'Авиасозлар 2', 'Aviasozlar 2'],
52
+ ['Aviasozlar-3', 'Авиасозлар-3', 'Авиасозлар 3', 'Aviasozlar 3'],
53
+ ['Beltepa', 'Белтепа', 'Белтепа массив', 'Beltepa massiv', 'Beltepa massivi'],
54
+ ['Feruza-3', 'Феруза-3', 'Феруза 3', 'Feruza 3'],
55
+ ['Guliston', 'Гулистон', 'Гулистан', 'Жилмассив Гулистон', 'Guliston massivi', 'массив Гулистан'],
56
+ ['Humoyun', 'Хумаюн', 'Хумаюн (Ясный)', 'Humoyun (Yasnyy)'],
57
+ ['Tuzel-2', 'Тузель-2', 'Тузель 2', 'Tuzel 2'],
58
+ ['Yalangach', 'Ялангач', 'Ялангач (Высоковольтный)', 'Yalangach (Vysokovoltnyy)'],
59
+ ["Yo'ldosh-2", 'Йулдош 2', 'Йулдош (Спутник) 2', 'Спутник 2', 'Yoldosh-2'],
60
+ ["Yo'ldosh-9", 'Йулдош 9', 'Йулдош (Спутник) 9', 'Спутник 9', 'Yoldosh-9'],
61
+ ["Yo'ldosh-16", 'Йулдош 16', 'Йулдош (Спутник) 16', 'Спутник 16', 'Yoldosh-16'],
62
+ ["Yo'ldosh-17", 'Йулдош 17', 'Йулдош (Спутник) 17', 'Спутник 17', 'Yoldosh-17'],
63
+ ["Yo'ldosh-C2", 'Йулдош Ц2', 'Йулдош (Спутник) Ц2', 'Спутник Ц2', 'Yoldosh-C2'],
64
+ ]);
65
+
66
+ const REVIEWED_MICRODISTRICTS = locationEntries([
67
+ ['Chilanzar-6', 'Чиланзар-6', 'Чиланзар 6', 'Chilonzor-6', 'Chilonzor 6 mavzesi', '6-mavze'],
68
+ ['Chilanzar-7', 'Чиланзар-7', 'Чиланзар 7', 'Chilonzor-7', 'Chilonzor 7 mavzesi', '7-mavze'],
69
+ ['Chilanzar-8', 'Чиланзар-8', 'Чиланзар 8', 'Chilonzor-8', 'Chilonzor 8 mavzesi', '8-mavze'],
70
+ ['Chilanzar-14', 'Чиланзар-14', 'Чиланзар 14', 'Chilonzor-14', 'Chilonzor 14 mavzesi', '14-mavze'],
71
+ ['Chilanzar-20', 'Чиланзар-20', 'Чиланзар 20', 'Chilonzor-20', 'Chilonzor 20 mavzesi', '20-mavze'],
72
+ ['Chilanzar-21', 'Чиланзар-21', 'Чиланзар 21', 'Chilonzor-21', 'Chilonzor 21 mavzesi', '21-mavze', 'Чиланзар 21-й квартал'],
73
+ ['Chilanzar-22', 'Чиланзар-22', 'Чиланзар 22', 'Chilonzor-22', 'Chilonzor 22 mavzesi', '22-mavze', 'Чиланзар 22-й квартал'],
74
+ ['Dilbulok', 'Дилбулок', 'Микрорайон Дилбулок', 'Dilbuloq', 'Dilbuloq mikrohududi'],
75
+ ]);
76
+
77
+ const REVIEWED_MAHALLAS = locationEntries([
78
+ ['Yangi Tashkent', 'Махалля Янги Тошкент', 'Янги Тошкент махалля', 'Yangi Toshkent mahallasi'],
79
+ ]);
80
+
47
81
  export const UZ_TASHKENT_CONTEXT_EXTENSIONS = Object.freeze({
48
82
  Tashkent: Object.freeze({
49
- localAreas: Object.freeze([C1]),
83
+ mahallas: REVIEWED_MAHALLAS,
84
+ microdistricts: REVIEWED_MICRODISTRICTS,
85
+ localAreas: Object.freeze([C1, ...REVIEWED_LOCAL_AREAS]),
50
86
  residentialComplexes: Object.freeze([
51
87
  residentialEntry('Eco Dream', [
52
88
  'ЖК Eco Dream', 'Eco Dream TJM', 'Eco Dream turar joy majmuasi', 'Eco Dream turar-joy majmuasi',
@@ -0,0 +1,30 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ /**
4
+ * Lexical owners for the reviewed Tashkent residential OSM batch.
5
+ * Canonical names mirror geo-catalog; aliases only remove generic residential prefixes
6
+ * or harmless quote/case variants without inventing a translated brand name.
7
+ */
8
+ export const UZ_TASHKENT_REVIEWED_RESIDENTIAL_EXTENSIONS = Object.freeze({
9
+ Tashkent: Object.freeze({
10
+ residentialComplexes: locationEntries([
11
+ ['ЖК "Актепа Сохил буйи"', 'ЖК Актепа Сохил буйи', 'Актепа Сохил буйи'],
12
+ ['ЖК "Бтги Шамол"', 'ЖК Бтги Шамол', 'Бтги Шамол'],
13
+ ['Жилой комплекс Elegant', 'ЖК Elegant', 'Elegant'],
14
+ ['ЖК "Грин Сити" (Дровосеки)', 'ЖК Грин Сити (Дровосеки)', 'Грин Сити (Дровосеки)', 'Грин Сити'],
15
+ ['жилой комплекс Гульсарай', 'ЖК Гульсарай', 'Гульсарай'],
16
+ ['Хувайдо жилой комплекс', 'ЖК Хувайдо', 'Хувайдо'],
17
+ ['Жилой комплекс LOTUS 7', 'ЖК LOTUS 7', 'LOTUS 7', 'Lotus 7'],
18
+ ['жилой комплекс "Milliy House" от NESS', 'ЖК Milliy House', 'Milliy House', 'Milliy House от NESS'],
19
+ ['ЖК "Ness City"', 'ЖК Ness City', 'Ness City'],
20
+ ['жилой комплекс "Ness One" от Ness', 'ЖК Ness One', 'Ness One', 'Ness One от Ness'],
21
+ ['ЖК "Ness Sebzar"', 'ЖК Ness Sebzar', 'Ness Sebzar'],
22
+ ["Жилой комплекс 'Оазис'", 'Жилой комплекс Оазис', 'ЖК Оазис', 'Оазис'],
23
+ ['Переспектива жилой комплекс', 'ЖК Переспектива', 'Переспектива'],
24
+ ['Sultania ЖК', 'ЖК Sultania', 'Sultania'],
25
+ ['ЖК Учтепа Авению', 'Учтепа Авению'],
26
+ ['ЖК Янгибахт', 'Янгибахт'],
27
+ ['Жилой комплекс “Замок счастья”', 'Жилой комплекс Замок счастья', 'ЖК Замок счастья', 'Замок счастья'],
28
+ ]),
29
+ }),
30
+ });
@@ -0,0 +1,34 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ /**
4
+ * Reviewed Tashkent street aliases from provider-backed geo/address evidence.
5
+ * Keep aliases street-qualified so generic area/mahalla references are not captured.
6
+ */
7
+ export const UZ_TASHKENT_REVIEWED_STREET_EXTENSIONS = Object.freeze({
8
+ Tashkent: Object.freeze({
9
+ streets: locationEntries([
10
+ ['Тараккиёт 4-мавзе улица', 'Тараккиёт 4 мавзе улица'],
11
+ ['Улица Ташкент', 'ул. Ташкент'],
12
+ ['Shifokorlar Street',
13
+ 'Shifokorlar ko‘chasi',
14
+ "Shifokorlar ko'chasi",
15
+ 'Шифокорлар кўчаси',
16
+ 'улица Шифокорлар',
17
+ 'ул. Шифокорлар',
18
+ 'Shifokorlar-5',
19
+ 'Shifokorlar 5',
20
+ 'Шифокорлар-5',
21
+ 'Шифокорлар 5',
22
+ 'Shifokorlar-6',
23
+ 'Shifokorlar 6',
24
+ 'Шифокорлар-6',
25
+ 'Шифокорлар 6',
26
+ 'улица Шифокорлар, 5',
27
+ 'ул. Шифокорлар, 5',
28
+ 'улица Шифокорлар, 6',
29
+ 'ул. Шифокорлар, 6',
30
+ ],
31
+ ['Shimoliy Olmazor Street', 'Shimoliy Olmazor ko‘chasi', "Shimoliy Olmazor ko'chasi", 'Шимолий Олмазор кўчаси', 'улица Шимолий Олмазор', 'ул. Шимолий Олмазор'],
32
+ ]),
33
+ }),
34
+ });